Instead, skip the invalid data in an attempt to find an ADTS frame, and continue decoding from there.
Fixes ticket #6634 Signed-off-by: James Almer <jamr...@gmail.com> --- New in v2: - avpriv_aac_parse_header() used to validate ADTS headers more thoroughly. - Removed the usage of avio_tell(s->pb) in resync() and replaced it with a local counter. libavformat/aacdec.c | 77 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index 364b33404f..e744a9f40d 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -21,6 +21,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavcodec/aacadtsdec.h" #include "avformat.h" #include "internal.h" #include "id3v1.h" @@ -77,10 +78,52 @@ static int adts_aac_probe(AVProbeData *p) return 0; } +static int resync(AVFormatContext *s) +{ + AACADTSHeaderInfo hdr; + GetBitContext gbc; + uint8_t buf[AAC_ADTS_HEADER_SIZE]; + uint16_t state; + int64_t cnt = 1; + + state = avio_r8(s->pb); + while (!avio_feof(s->pb) && cnt++ < s->probesize) { + int fsize, ret; + + state = ((state << 8) | avio_r8(s->pb)); + if ((state >> 4) != 0xFFF) + continue; + + avio_seek(s->pb, -2, SEEK_CUR); + ret = avio_read(s->pb, buf, sizeof(buf)); + if (ret < 0) + return ret; + if (ret < AAC_ADTS_HEADER_SIZE) + return AVERROR(EIO); + + init_get_bits8(&gbc, buf, sizeof(buf)); + fsize = avpriv_aac_parse_header(&gbc, &hdr); + if (fsize < 0) { + // not a valid frame. Seek back to the "state" offset and continue. + avio_seek(s->pb, -5, SEEK_CUR); + continue; + } + + // likely to be a valid frame. Seek back to the start and return. + avio_seek(s->pb, -ret, SEEK_CUR); + break; + } + + if ((state >> 4) != 0xFFF) + return avio_feof(s->pb) ? AVERROR_EOF : AVERROR_INVALIDDATA; + + return 0; +} + static int adts_aac_read_header(AVFormatContext *s) { AVStream *st; - uint16_t state; + int ret; st = avformat_new_stream(s, NULL); if (!st) @@ -99,16 +142,9 @@ static int adts_aac_read_header(AVFormatContext *s) } // skip data until the first ADTS frame is found - state = avio_r8(s->pb); - while (!avio_feof(s->pb) && avio_tell(s->pb) < s->probesize) { - state = (state << 8) | avio_r8(s->pb); - if ((state >> 4) != 0xFFF) - continue; - avio_seek(s->pb, -2, SEEK_CUR); - break; - } - if ((state >> 4) != 0xFFF) - return AVERROR_INVALIDDATA; + ret = resync(s); + if (ret < 0) + return ret; // LCM of all possible ADTS sample rates avpriv_set_pts_info(st, 64, 1, 28224000); @@ -118,6 +154,8 @@ static int adts_aac_read_header(AVFormatContext *s) static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) { + AACADTSHeaderInfo hdr; + GetBitContext gbc; int ret, fsize; ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE); @@ -128,15 +166,16 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EIO); } - if ((AV_RB16(pkt->data) >> 4) != 0xfff) { - av_packet_unref(pkt); - return AVERROR_INVALIDDATA; - } - - fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF; - if (fsize < ADTS_HEADER_SIZE) { + init_get_bits8(&gbc, pkt->data, AAC_ADTS_HEADER_SIZE); + fsize = avpriv_aac_parse_header(&gbc, &hdr); + if (fsize < 0) { + // skip data in an attempt to find an ADTS frame. av_packet_unref(pkt); - return AVERROR_INVALIDDATA; + avio_seek(s->pb, -ret, SEEK_CUR); + ret = resync(s); + if (ret < 0) + return ret; + return adts_aac_read_packet(s, pkt); } return av_append_packet(s->pb, pkt, fsize - ADTS_HEADER_SIZE); -- 2.13.3 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel