This will allow decoupling the parser from the decoder.tags/n3.1
@@ -278,117 +278,6 @@ fail: | |||||
return AVERROR(ENOMEM); // ff_h264_free_tables will clean up for us | return AVERROR(ENOMEM); // ff_h264_free_tables will clean up for us | ||||
} | } | ||||
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size, | |||||
int parse_extradata); | |||||
/* There are (invalid) samples in the wild with mp4-style extradata, where the | |||||
* parameter sets are stored unescaped (i.e. as RBSP). | |||||
* This function catches the parameter set decoding failure and tries again | |||||
* after escaping it */ | |||||
static int decode_extradata_ps_mp4(H264Context *h, const uint8_t *buf, int buf_size) | |||||
{ | |||||
int ret; | |||||
ret = decode_nal_units(h, buf, buf_size, 1); | |||||
if (ret < 0 && !(h->avctx->err_recognition & AV_EF_EXPLODE)) { | |||||
GetByteContext gbc; | |||||
PutByteContext pbc; | |||||
uint8_t *escaped_buf; | |||||
int escaped_buf_size; | |||||
av_log(h->avctx, AV_LOG_WARNING, | |||||
"SPS decoding failure, trying again after escaping the NAL\n"); | |||||
if (buf_size / 2 >= (INT16_MAX - AV_INPUT_BUFFER_PADDING_SIZE) / 3) | |||||
return AVERROR(ERANGE); | |||||
escaped_buf_size = buf_size * 3 / 2 + AV_INPUT_BUFFER_PADDING_SIZE; | |||||
escaped_buf = av_mallocz(escaped_buf_size); | |||||
if (!escaped_buf) | |||||
return AVERROR(ENOMEM); | |||||
bytestream2_init(&gbc, buf, buf_size); | |||||
bytestream2_init_writer(&pbc, escaped_buf, escaped_buf_size); | |||||
while (bytestream2_get_bytes_left(&gbc)) { | |||||
if (bytestream2_get_bytes_left(&gbc) >= 3 && | |||||
bytestream2_peek_be24(&gbc) <= 3) { | |||||
bytestream2_put_be24(&pbc, 3); | |||||
bytestream2_skip(&gbc, 2); | |||||
} else | |||||
bytestream2_put_byte(&pbc, bytestream2_get_byte(&gbc)); | |||||
} | |||||
escaped_buf_size = bytestream2_tell_p(&pbc); | |||||
AV_WB16(escaped_buf, escaped_buf_size - 2); | |||||
ret = decode_nal_units(h, escaped_buf, escaped_buf_size, 1); | |||||
av_freep(&escaped_buf); | |||||
if (ret < 0) | |||||
return ret; | |||||
} | |||||
return 0; | |||||
} | |||||
int ff_h264_decode_extradata(H264Context *h) | |||||
{ | |||||
AVCodecContext *avctx = h->avctx; | |||||
int ret; | |||||
if (avctx->extradata[0] == 1) { | |||||
int i, cnt, nalsize; | |||||
unsigned char *p = avctx->extradata; | |||||
h->is_avc = 1; | |||||
if (avctx->extradata_size < 7) { | |||||
av_log(avctx, AV_LOG_ERROR, | |||||
"avcC %d too short\n", avctx->extradata_size); | |||||
return AVERROR_INVALIDDATA; | |||||
} | |||||
/* sps and pps in the avcC always have length coded with 2 bytes, | |||||
* so put a fake nal_length_size = 2 while parsing them */ | |||||
h->nal_length_size = 2; | |||||
// Decode sps from avcC | |||||
cnt = *(p + 5) & 0x1f; // Number of sps | |||||
p += 6; | |||||
for (i = 0; i < cnt; i++) { | |||||
nalsize = AV_RB16(p) + 2; | |||||
if (p - avctx->extradata + nalsize > avctx->extradata_size) | |||||
return AVERROR_INVALIDDATA; | |||||
ret = decode_extradata_ps_mp4(h, p, nalsize); | |||||
if (ret < 0) { | |||||
av_log(avctx, AV_LOG_ERROR, | |||||
"Decoding sps %d from avcC failed\n", i); | |||||
return ret; | |||||
} | |||||
p += nalsize; | |||||
} | |||||
// Decode pps from avcC | |||||
cnt = *(p++); // Number of pps | |||||
for (i = 0; i < cnt; i++) { | |||||
nalsize = AV_RB16(p) + 2; | |||||
if (p - avctx->extradata + nalsize > avctx->extradata_size) | |||||
return AVERROR_INVALIDDATA; | |||||
ret = decode_extradata_ps_mp4(h, p, nalsize); | |||||
if (ret < 0) { | |||||
av_log(avctx, AV_LOG_ERROR, | |||||
"Decoding pps %d from avcC failed\n", i); | |||||
return ret; | |||||
} | |||||
p += nalsize; | |||||
} | |||||
// Store right nal length size that will be used to parse all other nals | |||||
h->nal_length_size = (avctx->extradata[4] & 0x03) + 1; | |||||
} else { | |||||
h->is_avc = 0; | |||||
ret = decode_nal_units(h, avctx->extradata, avctx->extradata_size, 1); | |||||
if (ret < 0) | |||||
return ret; | |||||
} | |||||
return 0; | |||||
} | |||||
static int h264_init_context(AVCodecContext *avctx, H264Context *h) | static int h264_init_context(AVCodecContext *avctx, H264Context *h) | ||||
{ | { | ||||
int i; | int i; | ||||
@@ -462,7 +351,9 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx) | |||||
} | } | ||||
if (avctx->extradata_size > 0 && avctx->extradata) { | if (avctx->extradata_size > 0 && avctx->extradata) { | ||||
ret = ff_h264_decode_extradata(h); | |||||
ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, | |||||
&h->ps, &h->is_avc, &h->nal_length_size, | |||||
avctx->err_recognition, avctx); | |||||
if (ret < 0) { | if (ret < 0) { | ||||
ff_h264_free_context(h); | ff_h264_free_context(h); | ||||
return ret; | return ret; | ||||
@@ -919,8 +810,7 @@ static int get_last_needed_nal(H264Context *h) | |||||
return nals_needed; | return nals_needed; | ||||
} | } | ||||
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size, | |||||
int parse_extradata) | |||||
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) | |||||
{ | { | ||||
AVCodecContext *const avctx = h->avctx; | AVCodecContext *const avctx = h->avctx; | ||||
unsigned context_count = 0; | unsigned context_count = 0; | ||||
@@ -956,19 +846,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size, | |||||
continue; | continue; | ||||
again: | again: | ||||
/* Ignore every NAL unit type except PPS and SPS during extradata | |||||
* parsing. Decoding slices is not possible in codec init | |||||
* with frame-mt */ | |||||
if (parse_extradata && HAVE_THREADS && | |||||
(h->avctx->active_thread_type & FF_THREAD_FRAME) && | |||||
(nal->type != NAL_PPS && nal->type != NAL_SPS)) { | |||||
if (nal->type < NAL_AUD || nal->type > NAL_AUXILIARY_SLICE) | |||||
av_log(avctx, AV_LOG_INFO, | |||||
"Ignoring NAL unit %d during extradata parsing\n", | |||||
nal->type); | |||||
nal->type = NAL_FF_IGNORE; | |||||
} | |||||
// FIXME these should stop being context-global variables | // FIXME these should stop being context-global variables | ||||
h->nal_ref_idc = nal->ref_idc; | h->nal_ref_idc = nal->ref_idc; | ||||
h->nal_unit_type = nal->type; | h->nal_unit_type = nal->type; | ||||
@@ -1183,7 +1060,7 @@ out: | |||||
return buf_index; | return buf_index; | ||||
} | } | ||||
buf_index = decode_nal_units(h, buf, buf_size, 0); | |||||
buf_index = decode_nal_units(h, buf, buf_size); | |||||
if (buf_index < 0) | if (buf_index < 0) | ||||
return AVERROR_INVALIDDATA; | return AVERROR_INVALIDDATA; | ||||
@@ -706,7 +706,6 @@ int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb, | |||||
int ff_generate_sliding_window_mmcos(H264Context *h, int first_slice); | int ff_generate_sliding_window_mmcos(H264Context *h, int first_slice); | ||||
void ff_h264_hl_decode_mb(const H264Context *h, H264SliceContext *sl); | void ff_h264_hl_decode_mb(const H264Context *h, H264SliceContext *sl); | ||||
int ff_h264_decode_extradata(H264Context *h); | |||||
int ff_h264_decode_init(AVCodecContext *avctx); | int ff_h264_decode_init(AVCodecContext *avctx); | ||||
void ff_h264_decode_init_vlc(void); | void ff_h264_decode_init_vlc(void); | ||||
@@ -16,6 +16,7 @@ | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
*/ | */ | ||||
#include "bytestream.h" | |||||
#include "get_bits.h" | #include "get_bits.h" | ||||
#include "golomb.h" | #include "golomb.h" | ||||
#include "h264.h" | #include "h264.h" | ||||
@@ -305,3 +306,146 @@ int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, | |||||
return 0; | return 0; | ||||
} | } | ||||
static int decode_extradata_ps(const uint8_t *data, int size, H264ParamSets *ps, | |||||
int is_avc, void *logctx) | |||||
{ | |||||
H2645Packet pkt = { 0 }; | |||||
int i, ret = 0; | |||||
ret = ff_h2645_packet_split(&pkt, data, size, logctx, is_avc, 2, AV_CODEC_ID_H264); | |||||
if (ret < 0) | |||||
goto fail; | |||||
for (i = 0; i < pkt.nb_nals; i++) { | |||||
H2645NAL *nal = &pkt.nals[i]; | |||||
switch (nal->type) { | |||||
case NAL_SPS: | |||||
ret = ff_h264_decode_seq_parameter_set(&nal->gb, logctx, ps); | |||||
if (ret < 0) | |||||
goto fail; | |||||
break; | |||||
case NAL_PPS: | |||||
ret = ff_h264_decode_picture_parameter_set(&nal->gb, logctx, ps, | |||||
nal->size_bits); | |||||
if (ret < 0) | |||||
goto fail; | |||||
break; | |||||
default: | |||||
av_log(logctx, AV_LOG_VERBOSE, "Ignoring NAL type %d in extradata\n", | |||||
nal->type); | |||||
break; | |||||
} | |||||
} | |||||
fail: | |||||
ff_h2645_packet_uninit(&pkt); | |||||
return ret; | |||||
} | |||||
/* There are (invalid) samples in the wild with mp4-style extradata, where the | |||||
* parameter sets are stored unescaped (i.e. as RBSP). | |||||
* This function catches the parameter set decoding failure and tries again | |||||
* after escaping it */ | |||||
static int decode_extradata_ps_mp4(const uint8_t *buf, int buf_size, H264ParamSets *ps, | |||||
int err_recognition, void *logctx) | |||||
{ | |||||
int ret; | |||||
ret = decode_extradata_ps(buf, buf_size, ps, 1, logctx); | |||||
if (ret < 0 && !(err_recognition & AV_EF_EXPLODE)) { | |||||
GetByteContext gbc; | |||||
PutByteContext pbc; | |||||
uint8_t *escaped_buf; | |||||
int escaped_buf_size; | |||||
av_log(logctx, AV_LOG_WARNING, | |||||
"SPS decoding failure, trying again after escaping the NAL\n"); | |||||
if (buf_size / 2 >= (INT16_MAX - AV_INPUT_BUFFER_PADDING_SIZE) / 3) | |||||
return AVERROR(ERANGE); | |||||
escaped_buf_size = buf_size * 3 / 2 + AV_INPUT_BUFFER_PADDING_SIZE; | |||||
escaped_buf = av_mallocz(escaped_buf_size); | |||||
if (!escaped_buf) | |||||
return AVERROR(ENOMEM); | |||||
bytestream2_init(&gbc, buf, buf_size); | |||||
bytestream2_init_writer(&pbc, escaped_buf, escaped_buf_size); | |||||
while (bytestream2_get_bytes_left(&gbc)) { | |||||
if (bytestream2_get_bytes_left(&gbc) >= 3 && | |||||
bytestream2_peek_be24(&gbc) <= 3) { | |||||
bytestream2_put_be24(&pbc, 3); | |||||
bytestream2_skip(&gbc, 2); | |||||
} else | |||||
bytestream2_put_byte(&pbc, bytestream2_get_byte(&gbc)); | |||||
} | |||||
escaped_buf_size = bytestream2_tell_p(&pbc); | |||||
AV_WB16(escaped_buf, escaped_buf_size - 2); | |||||
ret = decode_extradata_ps(escaped_buf, escaped_buf_size, ps, 1, logctx); | |||||
av_freep(&escaped_buf); | |||||
if (ret < 0) | |||||
return ret; | |||||
} | |||||
return 0; | |||||
} | |||||
int ff_h264_decode_extradata(const uint8_t *data, int size, H264ParamSets *ps, | |||||
int *is_avc, int *nal_length_size, | |||||
int err_recognition, void *logctx) | |||||
{ | |||||
int ret; | |||||
if (data[0] == 1) { | |||||
int i, cnt, nalsize; | |||||
const uint8_t *p = data; | |||||
*is_avc = 1; | |||||
if (size < 7) { | |||||
av_log(logctx, AV_LOG_ERROR, "avcC %d too short\n", size); | |||||
return AVERROR_INVALIDDATA; | |||||
} | |||||
// Decode sps from avcC | |||||
cnt = *(p + 5) & 0x1f; // Number of sps | |||||
p += 6; | |||||
for (i = 0; i < cnt; i++) { | |||||
nalsize = AV_RB16(p) + 2; | |||||
if (p - data + nalsize > size) | |||||
return AVERROR_INVALIDDATA; | |||||
ret = decode_extradata_ps_mp4(p, nalsize, ps, err_recognition, logctx); | |||||
if (ret < 0) { | |||||
av_log(logctx, AV_LOG_ERROR, | |||||
"Decoding sps %d from avcC failed\n", i); | |||||
return ret; | |||||
} | |||||
p += nalsize; | |||||
} | |||||
// Decode pps from avcC | |||||
cnt = *(p++); // Number of pps | |||||
for (i = 0; i < cnt; i++) { | |||||
nalsize = AV_RB16(p) + 2; | |||||
if (p - data + nalsize > size) | |||||
return AVERROR_INVALIDDATA; | |||||
ret = decode_extradata_ps_mp4(p, nalsize, ps, err_recognition, logctx); | |||||
if (ret < 0) { | |||||
av_log(logctx, AV_LOG_ERROR, | |||||
"Decoding pps %d from avcC failed\n", i); | |||||
return ret; | |||||
} | |||||
p += nalsize; | |||||
} | |||||
// Store right nal length size that will be used to parse all other nals | |||||
*nal_length_size = (data[4] & 0x03) + 1; | |||||
} else { | |||||
*is_avc = 0; | |||||
ret = decode_extradata_ps(data, size, ps, 0, logctx); | |||||
if (ret < 0) | |||||
return ret; | |||||
} | |||||
return 0; | |||||
} |
@@ -54,6 +54,7 @@ typedef struct H264POCContext { | |||||
struct SPS; | struct SPS; | ||||
struct PPS; | struct PPS; | ||||
struct H264ParamSets; | |||||
int ff_h264_pred_weight_table(GetBitContext *gb, const struct SPS *sps, | int ff_h264_pred_weight_table(GetBitContext *gb, const struct SPS *sps, | ||||
const int *ref_count, int slice_type_nos, | const int *ref_count, int slice_type_nos, | ||||
@@ -82,4 +83,8 @@ int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, | |||||
const struct SPS *sps, H264POCContext *poc, | const struct SPS *sps, H264POCContext *poc, | ||||
int picture_structure, int nal_ref_idc); | int picture_structure, int nal_ref_idc); | ||||
int ff_h264_decode_extradata(const uint8_t *data, int size, struct H264ParamSets *ps, | |||||
int *is_avc, int *nal_length_size, | |||||
int err_recognition, void *logctx); | |||||
#endif /* AVCODEC_H264_PARSE_H */ | #endif /* AVCODEC_H264_PARSE_H */ |
@@ -50,6 +50,8 @@ typedef struct H264ParseContext { | |||||
H264DSPContext h264dsp; | H264DSPContext h264dsp; | ||||
H264POCContext poc; | H264POCContext poc; | ||||
H264SEIContext sei; | H264SEIContext sei; | ||||
int is_avc; | |||||
int nal_length_size; | |||||
int got_first; | int got_first; | ||||
} H264ParseContext; | } H264ParseContext; | ||||
@@ -500,7 +502,9 @@ static int h264_parse(AVCodecParserContext *s, | |||||
// NB: estimate_timings_from_pts behaves exactly like this. | // NB: estimate_timings_from_pts behaves exactly like this. | ||||
if (!avctx->has_b_frames) | if (!avctx->has_b_frames) | ||||
h->low_delay = 1; | h->low_delay = 1; | ||||
ff_h264_decode_extradata(h); | |||||
ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size, | |||||
&p->ps, &p->is_avc, &p->nal_length_size, | |||||
avctx->err_recognition, avctx); | |||||
} | } | ||||
} | } | ||||