diff mbox

[FFmpeg-devel] avformat/aacdec: add a custom read_packet function

Message ID 20170603033333.4436-1-jamrial@gmail.com
State Accepted
Headers show

Commit Message

James Almer June 3, 2017, 3:33 a.m. UTC
Atempt to read and propagate only full ADTS frames and not other data,
like id3v1 or APETags at the end of the file.

Fixes ticket #6439.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/aacdec.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

Comments

Michael Niedermayer June 3, 2017, 8:16 p.m. UTC | #1
On Sat, Jun 03, 2017 at 12:33:33AM -0300, James Almer wrote:
> Atempt to read and propagate only full ADTS frames and not other data,
> like id3v1 or APETags at the end of the file.
> 
> Fixes ticket #6439.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/aacdec.c | 42 ++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 40 insertions(+), 2 deletions(-)
> 
> diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
> index 5ab5197e33..aee1efe03c 100644
> --- a/libavformat/aacdec.c
> +++ b/libavformat/aacdec.c
> @@ -23,10 +23,11 @@
>  #include "libavutil/intreadwrite.h"
>  #include "avformat.h"
>  #include "internal.h"
> -#include "rawdec.h"
>  #include "id3v1.h"
>  #include "apetag.h"
>  
> +#define ADTS_HEADER_SIZE 7
> +
>  static int adts_aac_probe(AVProbeData *p)
>  {
>      int max_frames = 0, first_frames = 0;
> @@ -79,6 +80,7 @@ static int adts_aac_probe(AVProbeData *p)
>  static int adts_aac_read_header(AVFormatContext *s)
>  {
>      AVStream *st;
> +    uint16_t state;
>  
>      st = avformat_new_stream(s, NULL);
>      if (!st)
> @@ -96,18 +98,54 @@ static int adts_aac_read_header(AVFormatContext *s)
>          avio_seek(s->pb, cur, SEEK_SET);
>      }
>  
> +    // skip data until the first ADTS frame is found
> +    state = avio_r8(s->pb);
> +    while (!avio_feof(s->pb)) {
> +        state = (state << 8) | avio_r8(s->pb);
> +        if ((state >> 4) != 0xFFF)
> +            continue;
> +        avio_seek(s->pb, -2, SEEK_CUR);
> +        break;
> +    }

this would loop forever with /dev/zero as input

no more comments from me, seems working with what i tested

is it easy to add a fate test ? if so please add one

thx

[...]
James Almer June 3, 2017, 9:14 p.m. UTC | #2
On 6/3/2017 5:16 PM, Michael Niedermayer wrote:
> On Sat, Jun 03, 2017 at 12:33:33AM -0300, James Almer wrote:
>> Atempt to read and propagate only full ADTS frames and not other data,
>> like id3v1 or APETags at the end of the file.
>>
>> Fixes ticket #6439.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>  libavformat/aacdec.c | 42 ++++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
>> index 5ab5197e33..aee1efe03c 100644
>> --- a/libavformat/aacdec.c
>> +++ b/libavformat/aacdec.c
>> @@ -23,10 +23,11 @@
>>  #include "libavutil/intreadwrite.h"
>>  #include "avformat.h"
>>  #include "internal.h"
>> -#include "rawdec.h"
>>  #include "id3v1.h"
>>  #include "apetag.h"
>>  
>> +#define ADTS_HEADER_SIZE 7
>> +
>>  static int adts_aac_probe(AVProbeData *p)
>>  {
>>      int max_frames = 0, first_frames = 0;
>> @@ -79,6 +80,7 @@ static int adts_aac_probe(AVProbeData *p)
>>  static int adts_aac_read_header(AVFormatContext *s)
>>  {
>>      AVStream *st;
>> +    uint16_t state;
>>  
>>      st = avformat_new_stream(s, NULL);
>>      if (!st)
>> @@ -96,18 +98,54 @@ static int adts_aac_read_header(AVFormatContext *s)
>>          avio_seek(s->pb, cur, SEEK_SET);
>>      }
>>  
>> +    // skip data until the first ADTS frame is found
>> +    state = avio_r8(s->pb);
>> +    while (!avio_feof(s->pb)) {
>> +        state = (state << 8) | avio_r8(s->pb);
>> +        if ((state >> 4) != 0xFFF)
>> +            continue;
>> +        avio_seek(s->pb, -2, SEEK_CUR);
>> +        break;
>> +    }
> 
> this would loop forever with /dev/zero as input

How can i prevent this? Maybe checking a max of
AVFormatContext.probesize or AVFormatContext.format_probesize bytes
before bailing out? Which one if so?

> 
> no more comments from me, seems working with what i tested
> 
> is it easy to add a fate test ? if so please add one

Sure, i'll add one after i push this.

> 
> thx
> 
> [...]
> 
> 
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Michael Niedermayer June 4, 2017, 11:44 a.m. UTC | #3
On Sat, Jun 03, 2017 at 06:14:12PM -0300, James Almer wrote:
> On 6/3/2017 5:16 PM, Michael Niedermayer wrote:
> > On Sat, Jun 03, 2017 at 12:33:33AM -0300, James Almer wrote:
> >> Atempt to read and propagate only full ADTS frames and not other data,
> >> like id3v1 or APETags at the end of the file.
> >>
> >> Fixes ticket #6439.
> >>
> >> Signed-off-by: James Almer <jamrial@gmail.com>
> >> ---
> >>  libavformat/aacdec.c | 42 ++++++++++++++++++++++++++++++++++++++++--
> >>  1 file changed, 40 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
> >> index 5ab5197e33..aee1efe03c 100644
> >> --- a/libavformat/aacdec.c
> >> +++ b/libavformat/aacdec.c
> >> @@ -23,10 +23,11 @@
> >>  #include "libavutil/intreadwrite.h"
> >>  #include "avformat.h"
> >>  #include "internal.h"
> >> -#include "rawdec.h"
> >>  #include "id3v1.h"
> >>  #include "apetag.h"
> >>  
> >> +#define ADTS_HEADER_SIZE 7
> >> +
> >>  static int adts_aac_probe(AVProbeData *p)
> >>  {
> >>      int max_frames = 0, first_frames = 0;
> >> @@ -79,6 +80,7 @@ static int adts_aac_probe(AVProbeData *p)
> >>  static int adts_aac_read_header(AVFormatContext *s)
> >>  {
> >>      AVStream *st;
> >> +    uint16_t state;
> >>  
> >>      st = avformat_new_stream(s, NULL);
> >>      if (!st)
> >> @@ -96,18 +98,54 @@ static int adts_aac_read_header(AVFormatContext *s)
> >>          avio_seek(s->pb, cur, SEEK_SET);
> >>      }
> >>  
> >> +    // skip data until the first ADTS frame is found
> >> +    state = avio_r8(s->pb);
> >> +    while (!avio_feof(s->pb)) {
> >> +        state = (state << 8) | avio_r8(s->pb);
> >> +        if ((state >> 4) != 0xFFF)
> >> +            continue;
> >> +        avio_seek(s->pb, -2, SEEK_CUR);
> >> +        break;
> >> +    }
> > 
> > this would loop forever with /dev/zero as input
> 
> How can i prevent this? Maybe checking a max of
> AVFormatContext.probesize or AVFormatContext.format_probesize bytes
> before bailing out? Which one if so?

id tend toward probesize, but anything will do.

thx

[...]
James Almer June 4, 2017, 2:53 p.m. UTC | #4
On 6/4/2017 8:44 AM, Michael Niedermayer wrote:
> On Sat, Jun 03, 2017 at 06:14:12PM -0300, James Almer wrote:
>> On 6/3/2017 5:16 PM, Michael Niedermayer wrote:
>>> On Sat, Jun 03, 2017 at 12:33:33AM -0300, James Almer wrote:
>>>> Atempt to read and propagate only full ADTS frames and not other data,
>>>> like id3v1 or APETags at the end of the file.
>>>>
>>>> Fixes ticket #6439.

It's ticket 6437, sorry. Amended locally.

>>>>
>>>> Signed-off-by: James Almer <jamrial@gmail.com>
>>>> ---
>>>>  libavformat/aacdec.c | 42 ++++++++++++++++++++++++++++++++++++++++--
>>>>  1 file changed, 40 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
>>>> index 5ab5197e33..aee1efe03c 100644
>>>> --- a/libavformat/aacdec.c
>>>> +++ b/libavformat/aacdec.c
>>>> @@ -23,10 +23,11 @@
>>>>  #include "libavutil/intreadwrite.h"
>>>>  #include "avformat.h"
>>>>  #include "internal.h"
>>>> -#include "rawdec.h"
>>>>  #include "id3v1.h"
>>>>  #include "apetag.h"
>>>>  
>>>> +#define ADTS_HEADER_SIZE 7
>>>> +
>>>>  static int adts_aac_probe(AVProbeData *p)
>>>>  {
>>>>      int max_frames = 0, first_frames = 0;
>>>> @@ -79,6 +80,7 @@ static int adts_aac_probe(AVProbeData *p)
>>>>  static int adts_aac_read_header(AVFormatContext *s)
>>>>  {
>>>>      AVStream *st;
>>>> +    uint16_t state;
>>>>  
>>>>      st = avformat_new_stream(s, NULL);
>>>>      if (!st)
>>>> @@ -96,18 +98,54 @@ static int adts_aac_read_header(AVFormatContext *s)
>>>>          avio_seek(s->pb, cur, SEEK_SET);
>>>>      }
>>>>  
>>>> +    // skip data until the first ADTS frame is found
>>>> +    state = avio_r8(s->pb);
>>>> +    while (!avio_feof(s->pb)) {
>>>> +        state = (state << 8) | avio_r8(s->pb);
>>>> +        if ((state >> 4) != 0xFFF)
>>>> +            continue;
>>>> +        avio_seek(s->pb, -2, SEEK_CUR);
>>>> +        break;
>>>> +    }
>>>
>>> this would loop forever with /dev/zero as input
>>
>> How can i prevent this? Maybe checking a max of
>> AVFormatContext.probesize or AVFormatContext.format_probesize bytes
>> before bailing out? Which one if so?
> 
> id tend toward probesize, but anything will do.
> 
> thx

Done and pushed, thanks.
diff mbox

Patch

diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
index 5ab5197e33..aee1efe03c 100644
--- a/libavformat/aacdec.c
+++ b/libavformat/aacdec.c
@@ -23,10 +23,11 @@ 
 #include "libavutil/intreadwrite.h"
 #include "avformat.h"
 #include "internal.h"
-#include "rawdec.h"
 #include "id3v1.h"
 #include "apetag.h"
 
+#define ADTS_HEADER_SIZE 7
+
 static int adts_aac_probe(AVProbeData *p)
 {
     int max_frames = 0, first_frames = 0;
@@ -79,6 +80,7 @@  static int adts_aac_probe(AVProbeData *p)
 static int adts_aac_read_header(AVFormatContext *s)
 {
     AVStream *st;
+    uint16_t state;
 
     st = avformat_new_stream(s, NULL);
     if (!st)
@@ -96,18 +98,54 @@  static int adts_aac_read_header(AVFormatContext *s)
         avio_seek(s->pb, cur, SEEK_SET);
     }
 
+    // skip data until the first ADTS frame is found
+    state = avio_r8(s->pb);
+    while (!avio_feof(s->pb)) {
+        state = (state << 8) | avio_r8(s->pb);
+        if ((state >> 4) != 0xFFF)
+            continue;
+        avio_seek(s->pb, -2, SEEK_CUR);
+        break;
+    }
+
     // LCM of all possible ADTS sample rates
     avpriv_set_pts_info(st, 64, 1, 28224000);
 
     return 0;
 }
 
+static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    int ret, fsize;
+
+    ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE);
+    if (ret < 0)
+        return ret;
+    if (ret < ADTS_HEADER_SIZE) {
+        av_packet_unref(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) {
+        av_packet_unref(pkt);
+        return AVERROR_INVALIDDATA;
+    }
+
+    return av_append_packet(s->pb, pkt, fsize - ADTS_HEADER_SIZE);
+}
+
 AVInputFormat ff_aac_demuxer = {
     .name         = "aac",
     .long_name    = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"),
     .read_probe   = adts_aac_probe,
     .read_header  = adts_aac_read_header,
-    .read_packet  = ff_raw_read_partial_packet,
+    .read_packet  = adts_aac_read_packet,
     .flags        = AVFMT_GENERIC_INDEX,
     .extensions   = "aac",
     .mime_type    = "audio/aac,audio/aacp,audio/x-aac",