diff mbox

[FFmpeg-devel] aacdec: Allow SBR after DRC.

Message ID 1481072883-23152-1-git-send-email-alex.converse@gmail.com
State Accepted
Commit d3795926876bae7c0421585708f9ade573a1f54a
Headers show

Commit Message

Alex Converse Dec. 7, 2016, 1:08 a.m. UTC
Fixes https://www2.iis.fraunhofer.de/AAC/7.1auditionOutLeader_v2_rtb.mp4

Reported-by: rcombs on IRC
---
 libavcodec/aacdec_template.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Comments

Rostislav Pehlivanov Dec. 8, 2016, 10:14 a.m. UTC | #1
On 7 December 2016 at 01:08, Alex Converse <alex.converse@gmail.com> wrote:

> Fixes https://www2.iis.fraunhofer.de/AAC/7.1auditionOutLeader_v2_rtb.mp4
>
> Reported-by: rcombs on IRC
> ---
>  libavcodec/aacdec_template.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/libavcodec/aacdec_template.c b/libavcodec/aacdec_template.c
> index 8cfa34b..64d46e3 100644
> --- a/libavcodec/aacdec_template.c
> +++ b/libavcodec/aacdec_template.c
> @@ -3038,8 +3038,10 @@ static int aac_decode_frame_int(AVCodecContext
> *avctx, void *data,
>              break;
>          }
>
> -        che_prev       = che;
> -        elem_type_prev = elem_type;
> +        if (elem_type < TYPE_DSE) {
> +            che_prev       = che;
> +            elem_type_prev = elem_type;
> +        }
>
>          if (err)
>              goto fail;
>

I'm not quite following. So it prevents TYPE_DSE and above from getting
into che_prev which goes into decode_extension_payload() which then decodes
extensions. But DSE isn't the last in the enum, what about PCE, FIL and END
elements?
Alex Converse Dec. 8, 2016, 7:42 p.m. UTC | #2
On Thu, Dec 8, 2016 at 2:14 AM, Rostislav Pehlivanov
<atomnuker@gmail.com> wrote:
> On 7 December 2016 at 01:08, Alex Converse <alex.converse@gmail.com> wrote:
>
>> Fixes https://www2.iis.fraunhofer.de/AAC/7.1auditionOutLeader_v2_rtb.mp4
>>
>> Reported-by: rcombs on IRC
>> ---
>>  libavcodec/aacdec_template.c | 6 ++++--
>>  1 file changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavcodec/aacdec_template.c b/libavcodec/aacdec_template.c
>> index 8cfa34b..64d46e3 100644
>> --- a/libavcodec/aacdec_template.c
>> +++ b/libavcodec/aacdec_template.c
>> @@ -3038,8 +3038,10 @@ static int aac_decode_frame_int(AVCodecContext
>> *avctx, void *data,
>>              break;
>>          }
>>
>> -        che_prev       = che;
>> -        elem_type_prev = elem_type;
>> +        if (elem_type < TYPE_DSE) {
>> +            che_prev       = che;
>> +            elem_type_prev = elem_type;
>> +        }
>>
>>          if (err)
>>              goto fail;
>>
>
> I'm not quite following. So it prevents TYPE_DSE and above from getting
> into che_prev which goes into decode_extension_payload() which then decodes
> extensions. But DSE isn't the last in the enum, what about PCE, FIL and END
> elements?

The actual use of elem_type_prev is to describe the element type of
che_prev, but che only updates for element types SCE, CPE, CCE, and
LFE (0, 1, 2, and 3). (che_prev is currently updated every element,
but if che isn't updated on an element then it's a noop.)

>        if (elem_type < TYPE_DSE) {
>            if (!(che=get_che(ac, elem_type, elem_id))) {
>                av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n",
>                       elem_type, elem_id);
>                err = AVERROR_INVALIDDATA;
>                goto fail;
>            }
>            samples = 1024;
>            che->present = 1;
>        }


Allowing elem_type_prev to desynchronize from che_prev means that the
SBR decoder is provided a che but incorrectly informed of the type of
element the che represents.

For example, the frames of the stream look like this:
[aac @ 0x25659c0] Elem type:0 id:0  // SCE
[aac @ 0x25659c0] Elem type:6 id:3  // FIL
[aac @ 0x25659c0] extension type: 11 len:3  // FIL payload DRC
[aac @ 0x25659c0] Elem type:6 id:9  // FIL
[aac @ 0x25659c0] extension type: 13 len:9  // FIL payload SBR
[aac @ 0x25659c0] Invalid bitstream - cannot apply SBR to element type 6
[aac @ 0x25659c0] Elem type:1 id:0  // CPE
[aac @ 0x25659c0] Elem type:6 id:f  // FIL
[aac @ 0x25659c0] extension type: 13 len:18  // FIL payload SBR
[aac @ 0x25659c0] Elem type:1 id:1  // CPE
[aac @ 0x25659c0] Elem type:6 id:f  // FIL
[aac @ 0x25659c0] extension type: 13 len:18 // FIL payload SBR
[aac @ 0x25659c0] Elem type:1 id:2  // CPE
[aac @ 0x25659c0] Elem type:6 id:f  // FIL
[aac @ 0x25659c0] extension type: 13 len:18  // FIL payload SBR
[aac @ 0x25659c0] Elem type:3 id:0  // LFE
[aac @ 0x25659c0] Elem type:4 id:0  // DSE
[aac @ 0x25659c0] Elem type:7  // END
[aac @ 0x25659c0] element type mismatch 3 != 0
[aac @ 0x25659c0] element type mismatch 0 != 6

In this case we clearly want to apply the first SBR element to the
first SCE element. But the DRC element between them means that we are
going to attempt to apply it the the first SCE element, but we are
going to tell the SBR decoder that the SCE element is a FIL element
which is nonsense.

Assuming we want to support streams like this (generated by
"Fraunhofer IIS MPEG-4 Audio Encoder 03.02.15_MPEGScbr_hdaac") the
che_prev should stay live across FIL elements.

The 2009 spec says:
> 4.5.2.8.2.2 SBR extension payload for the audio object
> types AAC main, AAC SSR, AAC LC and AAC LTP
>
> One SBR fill element is used per AAC syntactic element
> that is to be enhanced by SBR. SBR elements are
> inserted into the raw_data_block() after the
> corresponding AAC elements. Each AAC SCE, CPE or
> independently switched CCE must be succeeded by a
> corresponding SBR element. LFE elements are decoded
> according to standard AAC procedures but must be delay
> adjusted and re-sampled to match the output sample
> rate. Given below is an example of the structure of
> syntactic elements within a raw data block of a 5.1
> (multichannel) configuration, where SBR is used
> without a CRC check.
>
> <SCE> <FIL <EXT_SBR_DATA(SCE)>> // center
> <CPE> <FIL <EXT_SBR_DATA(CPE)>> // front L/R
> <CPE> <FIL <EXT_SBR_DATA(CPE)>> // back L/R
> <LFE> // sub
> <END> // (end of raw data block)

If someone really wanted to be pedantic about it, they could argue
that the SBR data has to follow the SCE, CPE, or CCE, but it doesn't
have to immediately follow the element. I think this is an awkward
interpretation of the text, but the text doesn't seem to otherwise
address having a different FIL element between the SCE, CPE, or CCE
and the FIL-SBR.

I could go either way on allowing DSEs and PCEs between SCE/CPE/CCE
and SBR but am not particularly motivated to add extra logic to forbid
it when the spec is ambiguous.

Regardless of whether or not we allow the DSEs and PCEs between
SCE/CPE/CCEs and their SBR elements, we should keep elem_type_prev in
sync with che_prev. If this means renaming (perhaps to che_type_prev)
it so be it. I had previously suggested that maybe it would be better
to make the element type a member of the che struct, but the
(elem_type, elem_id) pair is essentially the address of the che so
eveywhere else we already know the type of the che before we even get
its pointer. This seems to be the awkward exception.
Alex Converse Dec. 9, 2016, 12:18 a.m. UTC | #3
On Thu, Dec 8, 2016 at 12:36 PM, Rostislav Pehlivanov
<atomnuker@gmail.com> wrote:
>
> On 8 December 2016 at 19:42, Alex Converse <alex.converse@gmail.com> wrote:
>>
>> On Thu, Dec 8, 2016 at 2:14 AM, Rostislav Pehlivanov
>> <atomnuker@gmail.com> wrote:
>> > On 7 December 2016 at 01:08, Alex Converse <alex.converse@gmail.com>
>> > wrote:
>> >
>> >> Fixes
>> >> https://www2.iis.fraunhofer.de/AAC/7.1auditionOutLeader_v2_rtb.mp4
>> >>
>> >> Reported-by: rcombs on IRC
>> >> ---
>> >>  libavcodec/aacdec_template.c | 6 ++++--
>> >>  1 file changed, 4 insertions(+), 2 deletions(-)
>> >>
>> >> diff --git a/libavcodec/aacdec_template.c
>> >> b/libavcodec/aacdec_template.c
>> >> index 8cfa34b..64d46e3 100644
>> >> --- a/libavcodec/aacdec_template.c
>> >> +++ b/libavcodec/aacdec_template.c
>> >> @@ -3038,8 +3038,10 @@ static int aac_decode_frame_int(AVCodecContext
>> >> *avctx, void *data,
>> >>              break;
>> >>          }
>> >>
>> >> -        che_prev       = che;
>> >> -        elem_type_prev = elem_type;
>> >> +        if (elem_type < TYPE_DSE) {
>> >> +            che_prev       = che;
>> >> +            elem_type_prev = elem_type;
>> >> +        }
>> >>
>> >>          if (err)
>> >>              goto fail;
>> >>
>> >
>> > I'm not quite following. So it prevents TYPE_DSE and above from getting
>> > into che_prev which goes into decode_extension_payload() which then
>> > decodes
>> > extensions. But DSE isn't the last in the enum, what about PCE, FIL and
>> > END
>> > elements?
>>
>> The actual use of elem_type_prev is to describe the element type of
>> che_prev, but che only updates for element types SCE, CPE, CCE, and
>> LFE (0, 1, 2, and 3). (che_prev is currently updated every element,
>> but if che isn't updated on an element then it's a noop.)
>>
>
> Thanks for the great explanation, now it all makes sense.
> Patch LGTM, feel free to push whenever you can.
>

Pushed
diff mbox

Patch

diff --git a/libavcodec/aacdec_template.c b/libavcodec/aacdec_template.c
index 8cfa34b..64d46e3 100644
--- a/libavcodec/aacdec_template.c
+++ b/libavcodec/aacdec_template.c
@@ -3038,8 +3038,10 @@  static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
             break;
         }
 
-        che_prev       = che;
-        elem_type_prev = elem_type;
+        if (elem_type < TYPE_DSE) {
+            che_prev       = che;
+            elem_type_prev = elem_type;
+        }
 
         if (err)
             goto fail;