h264: reimplement 3aa661ec5 in a more explicit way

Instead of handling the problem inside NAL decoding code, add a higher
level wrapper function. This should be more robust against future
changes (and easier to read).
This commit is contained in:
Anton Khirnov 2016-03-21 14:23:19 +01:00
parent add1467e5e
commit a7829a2a3f
1 changed files with 54 additions and 10 deletions

View File

@ -32,6 +32,7 @@
#include "libavutil/stereo3d.h"
#include "libavutil/timer.h"
#include "internal.h"
#include "bytestream.h"
#include "cabac.h"
#include "cabac_functions.h"
#include "error_resilience.h"
@ -407,6 +408,55 @@ fail:
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;
@ -433,7 +483,7 @@ int ff_h264_decode_extradata(H264Context *h)
nalsize = AV_RB16(p) + 2;
if (p - avctx->extradata + nalsize > avctx->extradata_size)
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, 1);
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);
@ -447,7 +497,7 @@ int ff_h264_decode_extradata(H264Context *h)
nalsize = AV_RB16(p) + 2;
if (p - avctx->extradata + nalsize > avctx->extradata_size)
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, 1);
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);
@ -1379,14 +1429,8 @@ again:
case NAL_SPS:
init_get_bits(&h->gb, ptr, bit_length);
ret = ff_h264_decode_seq_parameter_set(h);
if (ret < 0 && h->is_avc && (nalsize != consumed) && nalsize) {
av_log(h->avctx, AV_LOG_DEBUG,
"SPS decoding failure, trying again with the complete NAL\n");
init_get_bits(&h->gb, buf + buf_index + 1 - consumed,
8 * (nalsize - 1));
ff_h264_decode_seq_parameter_set(h);
}
if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
goto end;
break;
case NAL_PPS:
init_get_bits(&h->gb, ptr, bit_length);