The FDK decoder is capable of producing mono and stereo downmix from
multichannel streams. These streams may contain metadata that control
the downmix process. The decoder requires an Ancillary Buffer in order
to correctly apply downmix in streams with Metadata. The decoder does
not have an API interface to inform of the presence of Metadata in the
stream, therefore the Ancillary Buffer is always allocated whenever
a downmix is requested.

When downmixing multichannel streams, the decoder requires the output
buffer (decoder_buffer) to be of fixed size to hold the actual number of
channels contained in the stream. This means for a 5.1ch to stereo
downmix, the decoder requires that decoder_buffer is actually allocated
for 6 channels, regardless of the fact that the output is in fact two
channels. Due to this requirement, decoder_buffer is now allocated for
the entire duration that the FDK decoder is open, and is allocated for
the maximum number of supported channels and frame sizes. To override
this behavior, the decoder_buffer can be preallocated before calling
fdk_aac_decoder_init ().

Signed-off-by: Omer Osman <omer.os...@iis.fraunhofer.de>
---
 libavcodec/libfdk-aacdec.c |   81 +++++++++++++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 31 deletions(-)

diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c
index 27e5712..ffddfde 100644
--- a/libavcodec/libfdk-aacdec.c
+++ b/libavcodec/libfdk-aacdec.c
@@ -36,9 +36,13 @@ typedef struct FDKAACDecContext {
     const AVClass *class;
     HANDLE_AACDECODER handle;
     int initialized;
+    uint16_t* decoder_buffer;
+    uint8_t*  ancBuffer;
     enum ConcealMethod conceal_method;
 } FDKAACDecContext;
 
+#define DMX_ANC_BUFFSIZE (  128  )
+#define DECODER_BUFFSIZE ( 8 * 2048 * sizeof(INT_PCM) )
 #define OFFSET(x) offsetof(FDKAACDecContext, x)
 #define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM
 static const AVOption fdk_aac_dec_options[] = {
@@ -170,6 +174,10 @@ static av_cold int fdk_aac_decode_close(AVCodecContext 
*avctx)
 
     if (s->handle)
         aacDecoder_Close(s->handle);
+    if (s->decoder_buffer)
+        av_free(s->decoder_buffer);
+    if (s->ancBuffer)
+        av_free(s->ancBuffer);
 
     return 0;
 }
@@ -199,6 +207,41 @@ static av_cold int fdk_aac_decode_init(AVCodecContext 
*avctx)
         return AVERROR_UNKNOWN;
     }
 
+    if (avctx->request_channel_layout > 0 &&
+        avctx->request_channel_layout != AV_CH_LAYOUT_NATIVE) {
+        int downmix_channels = 
av_get_channel_layout_nb_channels(avctx->request_channel_layout);
+
+        switch (downmix_channels){
+          case 2:
+          case 1:
+              if(aacDecoder_SetParam(s->handle, AAC_PCM_OUTPUT_CHANNELS, 
downmix_channels) != AAC_DEC_OK){
+                  av_log(avctx, AV_LOG_ERROR, "Unable to set output channels 
in the decoder\n");
+                  return AVERROR_UNKNOWN;
+              }
+              break;
+          default:
+              av_log(avctx, AV_LOG_ERROR, "Invalid request_channel_layout\n");
+              return AVERROR_UNKNOWN;
+        }
+
+        if (!s->ancBuffer){
+            s->ancBuffer = av_malloc(DMX_ANC_BUFFSIZE);
+            if (!s->ancBuffer){
+                av_log(avctx, AV_LOG_ERROR, "Unable to allocate ancillary 
buffer for the decoder\n");
+                return AVERROR(ENOMEM);
+            }
+            if (aacDecoder_AncDataInit(s->handle, s->ancBuffer, 
DMX_ANC_BUFFSIZE)){
+                av_log(avctx, AV_LOG_ERROR, "Unable to register downmix 
ancillary buffer in the decoder\n");
+                return AVERROR_UNKNOWN;
+            }
+        }
+    }
+
+    if (!s->decoder_buffer)
+        s->decoder_buffer = av_malloc(DECODER_BUFFSIZE);
+    if (!s->decoder_buffer)
+        return AVERROR(ENOMEM);
+
     avctx->sample_fmt = AV_SAMPLE_FMT_S16;
 
     return 0;
@@ -212,8 +255,6 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, void 
*data,
     int ret;
     AAC_DECODER_ERROR err;
     UINT valid = avpkt->size;
-    uint8_t *buf, *tmpptr = NULL;
-    int buf_size;
 
     err = aacDecoder_Fill(s->handle, &avpkt->data, &avpkt->size, &valid);
     if (err != AAC_DEC_OK) {
@@ -221,23 +262,7 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, 
void *data,
         return AVERROR_INVALIDDATA;
     }
 
-    if (s->initialized) {
-        frame->nb_samples = avctx->frame_size;
-        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
-            av_log(avctx, AV_LOG_ERROR, "ff_get_buffer() failed\n");
-            return ret;
-        }
-        buf = frame->extended_data[0];
-        buf_size = avctx->channels * frame->nb_samples *
-                   av_get_bytes_per_sample(avctx->sample_fmt);
-    } else {
-        buf_size = 50 * 1024;
-        buf = tmpptr = av_malloc(buf_size);
-        if (!buf)
-            return AVERROR(ENOMEM);
-    }
-
-    err = aacDecoder_DecodeFrame(s->handle, (INT_PCM *) buf, buf_size, 0);
+    err = aacDecoder_DecodeFrame(s->handle, (INT_PCM *) s->decoder_buffer, 
DECODER_BUFFSIZE, 0);
     if (err == AAC_DEC_NOT_ENOUGH_BITS) {
         ret = avpkt->size - valid;
         goto end;
@@ -253,25 +278,19 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, 
void *data,
         if ((ret = get_stream_info(avctx)) < 0)
             goto end;
         s->initialized = 1;
-        frame->nb_samples = avctx->frame_size;
     }
 
-    if (tmpptr) {
-        frame->nb_samples = avctx->frame_size;
-        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
-            av_log(avctx, AV_LOG_ERROR, "ff_get_buffer() failed\n");
-            goto end;
-        }
-        memcpy(frame->extended_data[0], tmpptr,
-               avctx->channels * avctx->frame_size *
-               av_get_bytes_per_sample(avctx->sample_fmt));
-    }
+    frame->nb_samples = avctx->frame_size;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        goto end;
+    memcpy(frame->extended_data[0], s->decoder_buffer,
+           avctx->channels * avctx->frame_size *
+           av_get_bytes_per_sample(avctx->sample_fmt));
 
     *got_frame_ptr = 1;
     ret = avpkt->size - valid;
 
 end:
-    av_free(tmpptr);
     return ret;
 }
 
-- 
1.7.10.4

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to