[FFmpeg-devel] [PATCH] lavc/audiotoolbox: avoid relying on consumer-provided params when possible

Rodger Combs rodger.combs at gmail.com
Thu Apr 7 08:22:01 CEST 2016


We now attempt to parse extradata before init when present. In MPEG audio
and (E)AC3, we wait for the first packet and parse its header (unless the
consumer provided a channel count and sample rate at init).
---
 configure                    |   2 +
 libavcodec/Makefile          |   6 +-
 libavcodec/audiotoolboxdec.c | 137 +++++++++++++++++++++++++++++++------------
 3 files changed, 103 insertions(+), 42 deletions(-)

diff --git a/configure b/configure
index 94a66d8..f8ff5ca 100755
--- a/configure
+++ b/configure
@@ -2647,10 +2647,12 @@ mjpeg2jpeg_bsf_select="jpegtables"
 # external libraries
 aac_at_decoder_deps="audiotoolbox"
 ac3_at_decoder_deps="audiotoolbox"
+ac3_at_decoder_select="ac3_parser"
 adpcm_ima_qt_at_decoder_deps="audiotoolbox"
 alac_at_decoder_deps="audiotoolbox"
 amr_nb_at_decoder_deps="audiotoolbox"
 eac3_at_decoder_deps="audiotoolbox"
+eac3_at_decoder_select="ac3_parser"
 gsm_ms_at_decoder_deps="audiotoolbox"
 ilbc_at_decoder_deps="audiotoolbox"
 mp1_at_decoder_deps="audiotoolbox"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8e6563c..ec41446 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -810,9 +810,9 @@ OBJS-$(CONFIG_AMR_NB_AT_DECODER)          += audiotoolboxdec.o
 OBJS-$(CONFIG_EAC3_AT_DECODER)            += audiotoolboxdec.o
 OBJS-$(CONFIG_GSM_MS_AT_DECODER)          += audiotoolboxdec.o
 OBJS-$(CONFIG_ILBC_AT_DECODER)            += audiotoolboxdec.o
-OBJS-$(CONFIG_MP1_AT_DECODER)             += audiotoolboxdec.o
-OBJS-$(CONFIG_MP2_AT_DECODER)             += audiotoolboxdec.o
-OBJS-$(CONFIG_MP3_AT_DECODER)             += audiotoolboxdec.o
+OBJS-$(CONFIG_MP1_AT_DECODER)             += audiotoolboxdec.o mpegaudiodecheader.o
+OBJS-$(CONFIG_MP2_AT_DECODER)             += audiotoolboxdec.o mpegaudiodecheader.o
+OBJS-$(CONFIG_MP3_AT_DECODER)             += audiotoolboxdec.o mpegaudiodecheader.o
 OBJS-$(CONFIG_PCM_MULAW_AT_DECODER)       += audiotoolboxdec.o
 OBJS-$(CONFIG_PCM_ALAW_AT_DECODER)        += audiotoolboxdec.o
 OBJS-$(CONFIG_QDMC_AT_DECODER)            += audiotoolboxdec.o
diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c
index f840a6b..2740648 100644
--- a/libavcodec/audiotoolboxdec.c
+++ b/libavcodec/audiotoolboxdec.c
@@ -24,8 +24,10 @@
 
 #include "config.h"
 #include "avcodec.h"
+#include "ac3_parser.h"
 #include "bytestream.h"
 #include "internal.h"
+#include "mpegaudiodecheader.h"
 #include "libavutil/avassert.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
@@ -220,57 +222,68 @@ static void put_descr(PutByteContext *pb, int tag, unsigned int size)
     bytestream2_put_byte(pb, size & 0x7F);
 }
 
-static int ffat_set_extradata(AVCodecContext *avctx)
+static uint8_t* ffat_get_magic_cookie(AVCodecContext *avctx, UInt32 *cookie_size)
 {
-    ATDecodeContext *at = avctx->priv_data;
-    if (avctx->extradata_size) {
-        OSStatus status;
-        char *extradata = avctx->extradata;
-        int extradata_size = avctx->extradata_size;
-        if (avctx->codec_id == AV_CODEC_ID_AAC) {
-            PutByteContext pb;
-            extradata_size = 5 + 3 + 5+13 + 5+avctx->extradata_size;
-            if (!(extradata = av_malloc(extradata_size)))
-                return AVERROR(ENOMEM);
+    if (avctx->codec_id == AV_CODEC_ID_AAC) {
+        char *extradata;
+        PutByteContext pb;
+        *cookie_size = 5 + 3 + 5+13 + 5+avctx->extradata_size;
+        if (!(extradata = av_malloc(*cookie_size)))
+            return NULL;
 
-            bytestream2_init_writer(&pb, extradata, extradata_size);
+        bytestream2_init_writer(&pb, extradata, *cookie_size);
 
-            // ES descriptor
-            put_descr(&pb, 0x03, 3 + 5+13 + 5+avctx->extradata_size);
-            bytestream2_put_be16(&pb, 0);
-            bytestream2_put_byte(&pb, 0x00); // flags (= no flags)
+        // ES descriptor
+        put_descr(&pb, 0x03, 3 + 5+13 + 5+avctx->extradata_size);
+        bytestream2_put_be16(&pb, 0);
+        bytestream2_put_byte(&pb, 0x00); // flags (= no flags)
 
-            // DecoderConfig descriptor
-            put_descr(&pb, 0x04, 13 + 5+avctx->extradata_size);
+        // DecoderConfig descriptor
+        put_descr(&pb, 0x04, 13 + 5+avctx->extradata_size);
 
-            // Object type indication
-            bytestream2_put_byte(&pb, 0x40);
+        // Object type indication
+        bytestream2_put_byte(&pb, 0x40);
 
-            bytestream2_put_byte(&pb, 0x15); // flags (= Audiostream)
+        bytestream2_put_byte(&pb, 0x15); // flags (= Audiostream)
 
-            bytestream2_put_be24(&pb, 0); // Buffersize DB
+        bytestream2_put_be24(&pb, 0); // Buffersize DB
 
-            bytestream2_put_be32(&pb, 0); // maxbitrate
-            bytestream2_put_be32(&pb, 0); // avgbitrate
+        bytestream2_put_be32(&pb, 0); // maxbitrate
+        bytestream2_put_be32(&pb, 0); // avgbitrate
 
-            // DecoderSpecific info descriptor
-            put_descr(&pb, 0x05, avctx->extradata_size);
-            bytestream2_put_buffer(&pb, avctx->extradata, avctx->extradata_size);
-        }
+        // DecoderSpecific info descriptor
+        put_descr(&pb, 0x05, avctx->extradata_size);
+        bytestream2_put_buffer(&pb, avctx->extradata, avctx->extradata_size);
+        return extradata;
+    } else {
+        *cookie_size = avctx->extradata_size;
+        return avctx->extradata;
+    }
+}
+
+static int ffat_set_extradata(AVCodecContext *avctx)
+{
+    ATDecodeContext *at = avctx->priv_data;
+    if (avctx->extradata_size) {
+        OSStatus status;
+        UInt32 cookie_size;
+        uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size);
+        if (!cookie)
+            return AVERROR(ENOMEM);
 
         status = AudioConverterSetProperty(at->converter,
                                            kAudioConverterDecompressionMagicCookie,
-                                           extradata_size, extradata);
+                                           cookie_size, cookie);
         if (status != 0)
             av_log(avctx, AV_LOG_WARNING, "AudioToolbox cookie error: %i\n", (int)status);
 
-        if (avctx->codec_id == AV_CODEC_ID_AAC)
-            av_free(extradata);
+        if (cookie != avctx->extradata)
+            av_free(cookie);
     }
     return 0;
 }
 
-static av_cold int ffat_create_decoder(AVCodecContext *avctx)
+static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt)
 {
     ATDecodeContext *at = avctx->priv_data;
     OSStatus status;
@@ -280,22 +293,68 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx)
                                      AV_SAMPLE_FMT_S32 : AV_SAMPLE_FMT_S16;
 
     AudioStreamBasicDescription in_format = {
-        .mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100,
         .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
         .mBytesPerPacket = avctx->block_align,
-        .mChannelsPerFrame = avctx->channels ? avctx->channels : 1,
     };
     AudioStreamBasicDescription out_format = {
-        .mSampleRate = in_format.mSampleRate,
         .mFormatID = kAudioFormatLinearPCM,
         .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
         .mFramesPerPacket = 1,
-        .mChannelsPerFrame = in_format.mChannelsPerFrame,
         .mBitsPerChannel = av_get_bytes_per_sample(sample_fmt) * 8,
     };
 
     avctx->sample_fmt = sample_fmt;
 
+    if (avctx->extradata) {
+        UInt32 format_size = sizeof(in_format);
+        UInt32 cookie_size;
+        uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size);
+        if (!cookie)
+            return AVERROR(ENOMEM);
+        status = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
+                                        cookie_size, cookie, &format_size, &in_format);
+        if (cookie != avctx->extradata)
+            av_free(cookie);
+        if (status != 0) {
+            av_log(avctx, AV_LOG_ERROR, "AudioToolbox header-parse error: %i\n", (int)status);
+            return AVERROR_UNKNOWN;
+        }
+#if CONFIG_MP1_AT_DECODER || CONFIG_MP2_AT_DECODER || CONFIG_MP3_AT_DECODER
+    } else if (pkt && pkt->size >= 4 &&
+               (avctx->codec_id == AV_CODEC_ID_MP1 ||
+                avctx->codec_id == AV_CODEC_ID_MP2 ||
+                avctx->codec_id == AV_CODEC_ID_MP3)) {
+        enum AVCodecID codec_id;
+        int bit_rate;
+        if (ff_mpa_decode_header(AV_RB32(pkt->data), &avctx->sample_rate,
+                                 &in_format.mChannelsPerFrame, &avctx->frame_size,
+                                 &bit_rate, &codec_id) < 0)
+            return AVERROR_INVALIDDATA;
+        avctx->bit_rate = bit_rate;
+        in_format.mSampleRate = avctx->sample_rate;
+#endif
+#if CONFIG_AC3_AT_DECODER || CONFIG_EAC3_AT_DECODER
+    } else if (pkt && pkt->size >= 7 &&
+               (avctx->codec_id == AV_CODEC_ID_AC3 ||
+                avctx->codec_id == AV_CODEC_ID_EAC3)) {
+        AC3HeaderInfo hdr, *phdr = &hdr;
+        GetBitContext gbc;
+        init_get_bits(&gbc, pkt->data, pkt->size);
+        if (avpriv_ac3_parse_header(&gbc, &phdr) < 0)
+            return AVERROR_INVALIDDATA;
+        in_format.mSampleRate = hdr.sample_rate;
+        in_format.mChannelsPerFrame = hdr.channels;
+        avctx->frame_size = hdr.num_blocks * 256;
+        avctx->bit_rate = hdr.bit_rate;
+#endif
+    } else {
+        in_format.mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100;
+        in_format.mChannelsPerFrame = avctx->channels ? avctx->channels : 1;
+    }
+
+    avctx->sample_rate = out_format.mSampleRate = in_format.mSampleRate;
+    avctx->channels = out_format.mChannelsPerFrame = in_format.mChannelsPerFrame;
+
     if (avctx->codec_id == AV_CODEC_ID_ADPCM_IMA_QT)
         in_format.mFramesPerPacket = 64;
 
@@ -325,8 +384,8 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx)
 
 static av_cold int ffat_init_decoder(AVCodecContext *avctx)
 {
-    if (avctx->channels || avctx->extradata_size)
-        return ffat_create_decoder(avctx);
+    if ((avctx->channels && avctx->sample_rate) || avctx->extradata_size)
+        return ffat_create_decoder(avctx, NULL);
     else
         return 0;
 }
@@ -421,7 +480,7 @@ static int ffat_decode(AVCodecContext *avctx, void *data,
     }
 
     if (!at->converter) {
-        if ((ret = ffat_create_decoder(avctx)) < 0)
+        if ((ret = ffat_create_decoder(avctx, avpkt)) < 0)
             return ret;
     }
 
-- 
2.7.3



More information about the ffmpeg-devel mailing list