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