[FFmpeg-cvslog] alac: split element parsing into a separate function

Justin Ruggles git at videolan.org
Thu Jul 19 23:35:55 CEST 2012


ffmpeg | branch: master | Justin Ruggles <justin.ruggles at gmail.com> | Mon Jul  9 16:05:53 2012 -0400| [81c9e2e6d074ccbf94e19c67d38b7b62e7c3f820] | committer: Justin Ruggles

alac: split element parsing into a separate function

This will make multi-channel implementation simpler.
Based partially on a patch by Andrew D'Addesio <modchipv12 at gmail.com>.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=81c9e2e6d074ccbf94e19c67d38b7b62e7c3f820
---

 libavcodec/alac.c |  121 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 40 deletions(-)

diff --git a/libavcodec/alac.c b/libavcodec/alac.c
index b44b5c4..1e37290 100644
--- a/libavcodec/alac.c
+++ b/libavcodec/alac.c
@@ -78,6 +78,18 @@ typedef struct {
     int nb_samples;                         /**< number of samples in the current frame */
 } ALACContext;
 
+enum RawDataBlockType {
+    /* At the moment, only SCE, CPE, LFE, and END are recognized. */
+    TYPE_SCE,
+    TYPE_CPE,
+    TYPE_CCE,
+    TYPE_LFE,
+    TYPE_DSE,
+    TYPE_PCE,
+    TYPE_FIL,
+    TYPE_END
+};
+
 static inline unsigned int decode_scalar(GetBitContext *gb, int k,
                                          int readsamplesize)
 {
@@ -268,27 +280,18 @@ static void append_extra_bits(int32_t *buffer[MAX_CHANNELS],
             buffer[ch][i] = (buffer[ch][i] << extra_bits) | extra_bits_buffer[ch][i];
 }
 
-static int alac_decode_frame(AVCodecContext *avctx, void *data,
-                             int *got_frame_ptr, AVPacket *avpkt)
+static int decode_element(AVCodecContext *avctx, void *data, int ch_index,
+                          int channels)
 {
     ALACContext *alac = avctx->priv_data;
-
-    int channels;
     int hassize;
     unsigned int readsamplesize;
     int is_compressed;
     uint8_t interlacing_shift;
     uint8_t interlacing_leftweight;
+    uint32_t output_samples;
     int i, ch, ret;
 
-    init_get_bits(&alac->gb, avpkt->data, avpkt->size * 8);
-
-    channels = get_bits(&alac->gb, 3) + 1;
-    if (channels != avctx->channels) {
-        av_log(avctx, AV_LOG_ERROR, "frame header channel count mismatch\n");
-        return AVERROR_INVALIDDATA;
-    }
-
     skip_bits(&alac->gb, 4);  /* element instance tag */
     skip_bits(&alac->gb, 12); /* unused header bits */
 
@@ -305,28 +308,32 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
     /* whether the frame is compressed */
     is_compressed = !get_bits1(&alac->gb);
 
-    if (hassize) {
-        /* now read the number of samples as a 32bit integer */
-        uint32_t output_samples = get_bits_long(&alac->gb, 32);
-        if (!output_samples || output_samples > alac->max_samples_per_frame) {
-            av_log(avctx, AV_LOG_ERROR, "invalid samples per frame: %d\n",
-                   output_samples);
-            return AVERROR_INVALIDDATA;
-        }
-        alac->nb_samples = output_samples;
-    } else
-        alac->nb_samples = alac->max_samples_per_frame;
-
-    /* get output buffer */
-    alac->frame.nb_samples = alac->nb_samples;
-    if ((ret = avctx->get_buffer(avctx, &alac->frame)) < 0) {
-        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
-        return ret;
+    if (hassize)
+        output_samples = get_bits_long(&alac->gb, 32);
+    else
+        output_samples = alac->max_samples_per_frame;
+    if (!output_samples || output_samples > alac->max_samples_per_frame) {
+        av_log(avctx, AV_LOG_ERROR, "invalid samples per frame: %d\n",
+               output_samples);
+        return AVERROR_INVALIDDATA;
     }
-    if (alac->sample_size > 16) {
-        for (ch = 0; ch < alac->channels; ch++)
-            alac->output_samples_buffer[ch] = (int32_t *)alac->frame.data[ch];
+    if (!alac->nb_samples) {
+        /* get output buffer */
+        alac->frame.nb_samples = output_samples;
+        if ((ret = avctx->get_buffer(avctx, &alac->frame)) < 0) {
+            av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+            return ret;
+        }
+        if (alac->sample_size > 16) {
+            for (ch = 0; ch < channels; ch++)
+                alac->output_samples_buffer[ch] = (int32_t *)alac->frame.data[ch_index + ch];
+        }
+    } else if (output_samples != alac->nb_samples) {
+        av_log(avctx, AV_LOG_ERROR, "sample count mismatch: %u != %d\n",
+               output_samples, alac->nb_samples);
+        return AVERROR_INVALIDDATA;
     }
+    alac->nb_samples = output_samples;
 
     if (is_compressed) {
         int16_t predictor_coef_table[MAX_CHANNELS][32];
@@ -391,16 +398,13 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
         /* not compressed, easy case */
         for (i = 0; i < alac->nb_samples; i++) {
             for (ch = 0; ch < channels; ch++) {
-                alac->output_samples_buffer[ch][i] = get_sbits_long(&alac->gb,
-                                                                    alac->sample_size);
+                alac->output_samples_buffer[ch][i] = get_sbits_long(&alac->gb, alac->sample_size);
             }
         }
         alac->extra_bits = 0;
         interlacing_shift = 0;
         interlacing_leftweight = 0;
     }
-    if (get_bits(&alac->gb, 3) != 7)
-        av_log(avctx, AV_LOG_ERROR, "Error : Wrong End Of Frame\n");
 
     if (channels == 2 && interlacing_leftweight) {
         decorrelate_stereo(alac->output_samples_buffer, alac->nb_samples,
@@ -409,25 +413,62 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
 
     if (alac->extra_bits) {
         append_extra_bits(alac->output_samples_buffer, alac->extra_bits_buffer,
-                          alac->extra_bits, alac->channels, alac->nb_samples);
+                          alac->extra_bits, channels, alac->nb_samples);
     }
 
     switch(alac->sample_size) {
     case 16: {
-        for (ch = 0; ch < alac->channels; ch++) {
-            int16_t *outbuffer = (int16_t *)alac->frame.data[ch];
+        for (ch = 0; ch < channels; ch++) {
+            int16_t *outbuffer = (int16_t *)alac->frame.data[ch_index + ch];
             for (i = 0; i < alac->nb_samples; i++)
                 *outbuffer++ = alac->output_samples_buffer[ch][i];
         }}
         break;
     case 24: {
-        for (ch = 0; ch < alac->channels; ch++) {
+        for (ch = 0; ch < channels; ch++) {
             for (i = 0; i < alac->nb_samples; i++)
                 alac->output_samples_buffer[ch][i] <<= 8;
         }}
         break;
     }
 
+    return 0;
+}
+
+static int alac_decode_frame(AVCodecContext *avctx, void *data,
+                             int *got_frame_ptr, AVPacket *avpkt)
+{
+    ALACContext *alac = avctx->priv_data;
+    enum RawDataBlockType element;
+    int channels;
+    int ch, ret;
+
+    init_get_bits(&alac->gb, avpkt->data, avpkt->size * 8);
+
+    alac->nb_samples = 0;
+    ch = 0;
+    while (get_bits_left(&alac->gb)) {
+        element = get_bits(&alac->gb, 3);
+        if (element == TYPE_END)
+            break;
+        if (element > TYPE_CPE && element != TYPE_LFE) {
+            av_log(avctx, AV_LOG_ERROR, "syntax element unsupported: %d", element);
+            return AVERROR_PATCHWELCOME;
+        }
+
+        channels = (element == TYPE_CPE) ? 2 : 1;
+        if (ch + channels > alac->channels) {
+            av_log(avctx, AV_LOG_ERROR, "invalid element channel count\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ret = decode_element(avctx, data, ch, channels);
+        if (ret < 0)
+            return ret;
+
+        ch += channels;
+    }
+
     if (avpkt->size * 8 - get_bits_count(&alac->gb) > 8)
         av_log(avctx, AV_LOG_ERROR, "Error : %d bits left\n",
                avpkt->size * 8 - get_bits_count(&alac->gb));



More information about the ffmpeg-cvslog mailing list