[FFmpeg-soc] [soc]: r4725 - als/alsdec.c

thilo.borgmann subversion at mplayerhq.hu
Thu Jul 16 11:51:29 CEST 2009


Author: thilo.borgmann
Date: Thu Jul 16 11:51:29 2009
New Revision: 4725

Log:
Added basic entropy block decoding.

Modified:
   als/alsdec.c

Modified: als/alsdec.c
==============================================================================
--- als/alsdec.c	Thu Jul 16 03:11:10 2009	(r4724)
+++ als/alsdec.c	Thu Jul 16 11:51:29 2009	(r4725)
@@ -31,6 +31,7 @@
 
 #include "avcodec.h"
 #include "get_bits.h"
+#include "unary.h"
 
 
 typedef struct {
@@ -75,6 +76,8 @@ typedef struct {
     unsigned int      last_frame_length; ///< Length of the last frame to decode. 0 if unknown.
     unsigned int      frame_id;          ///< The frame id / number of the current frame.
     unsigned int      js_switch;         ///< If true, joint-stereo decoding is enforced.
+    unsigned int      num_blocks;        ///< Number of blocks used in the current frame.
+    int64_t           **raw_samples;     ///< Decoded raw samples for each channel.
 } ALSDecContext;
 
 
@@ -119,6 +122,15 @@ static av_cold void dprint_specific_conf
 #endif
 
 
+/** Computes ceil(log2(x)) using av_log2.
+ */
+static inline int ceil_log2(int x) {
+    if (x <= 0)
+        return 0;
+    return av_log2((x - 1) << 1);
+}
+
+
 /** Reads an ALSSpecificConfig from a buffer into the output struct.
  */
 static av_cold int read_specific_config(ALSDecContext *ctx,
@@ -195,8 +207,8 @@ static av_cold int read_specific_config(
 
     // read channel sorting
     if (sconf->chan_sort && sconf->channels > 1) {
-        int chan_pos_bits = av_log2((sconf->channels - 1) << 1);
-        int bytes_needed  = (sconf->channels * chan_pos_bits + 7) / 8;
+        int chan_pos_bits = ceil_log2(sconf->channels);
+        int bytes_needed  = (sconf->channels * chan_pos_bits + 7) >> 3;
         if (buffer_size < bytes_needed)
             return -1;
 
@@ -284,20 +296,217 @@ static void parse_bs_info(uint32_t bs_in
 }
 
 
+/** Reads and decodes a rice codeword.
+ */
+static int64_t decode_rice(GetBitContext *gb, unsigned int k)
+{
+    int64_t value = 0;
+    int64_t q = 0;
+    int     max = gb->size_in_bits - get_bits_count(gb) - k;
+
+    if (!k) {
+        q = get_unary(gb, 0, max);
+        return (q & 1) ? -((q + 1) >> 1) : ((q + 1) >> 1);
+    } else if (k == 1) {
+        q = get_unary(gb, 0, max);
+        return get_bits1(gb) ? q : -(q + 1);
+    } else {
+        unsigned int r, sub_sign;
+
+        q         = get_unary(gb, 0, max);
+        sub_sign  = get_bits1(gb);
+        r         = get_bits_long(gb, k - 1);
+
+        value = (q << (k - 1)) + r;
+
+        return sub_sign ? value : -(value + 1);
+    }
+}
+
+
+/** Reads the block data.
+ */
+static int read_block_data(ALSDecContext *ctx, unsigned int ra_block,
+                            int64_t *raw_samples, unsigned int block_length)
+{
+    ALSSpecificConfig *sconf = &ctx->sconf;
+    AVCodecContext *avctx    = ctx->avctx;
+    GetBitContext *gb        = &ctx->gb;
+    unsigned int block_type;
+    unsigned int js_block;
+    unsigned int k;
+
+    // read block type
+    block_type = get_bits1(gb);
+
+    if (block_type == 0) {
+        unsigned int const_block;
+        int32_t      const_val = 0;
+
+        const_block = get_bits1(gb);    // 1 = constant value, 0 = zero block (silence)
+        js_block    = get_bits1(gb);
+
+        // skip 5 reserved bits
+        skip_bits(gb, 5);
+
+        if (const_block) {
+            unsigned int const_val_bits;
+
+            if (sconf->resolution == 2 || sconf->floating) {
+                const_val_bits = 24;
+            } else {
+                const_val_bits = avctx->bits_per_raw_sample;
+            }
+
+            const_val = get_bits_long(gb, const_val_bits);
+        }
+
+        // write raw samples into buffer
+        for (k = 0; k < block_length; k++) {
+            raw_samples[k] = const_val;
+        }
+    } else {
+        unsigned int s[8];
+        unsigned int sub_blocks, sb_length, shift_lsbs;
+        unsigned int opt_order = 1;
+        unsigned int start = 0;
+        int64_t      res[block_length];
+        unsigned int sb, smp;
+
+
+        js_block = get_bits1(gb);
+
+        // Determine the number of sub blocks for entropy decoding
+        if (!sconf->bgmc_mode && !sconf->sb_part)
+            sub_blocks = 1;
+        else if (sconf->bgmc_mode && sconf->sb_part)
+            sub_blocks = 1 << get_bits(gb, 2);
+        else
+            sub_blocks = get_bits1(gb) ? 4 : 1;
+
+        // Do not continue in case of a damaged stream
+        if (block_length % sub_blocks)
+            return -1;
+
+        sb_length = block_length / sub_blocks;
+
+
+        if (!sconf->bgmc_mode) {
+            s[0] = get_bits(gb, (sconf->resolution > 1) ? 5 : 4);
+            for (k = 1; k < sub_blocks; k++)
+                s[k] = s[k - 1] + decode_rice(gb, 0);
+        } else {
+            // TODO: BGMC mode
+        }
+
+        shift_lsbs = get_bits1(gb);
+
+        if (shift_lsbs) {
+            // TODO: LSBS shifts
+        }
+
+
+        if (!sconf->RLSLMS) {
+            if (sconf->adapt_order) {
+                int opt_order_length =
+                        FFMIN(
+                        ceil_log2(sconf->max_order+1),
+                        FFMAX(ceil_log2((block_length >> 3) - 1), 1)
+                        );
+                opt_order = get_bits(gb, opt_order_length);
+            } else {
+                opt_order = sconf->max_order;
+            }
+
+            for (k = 0; k < opt_order; k++) {
+                // TODO: prediction
+            }
+        }
+
+        if (sconf->long_term_prediction) {
+            // TODO: LTP mode
+        }
+
+        start = 0;
+
+        // read first value and residuals in case of a random access block
+        if (ra_block) {
+            if (opt_order) {
+                raw_samples[0] = decode_rice(gb, avctx->bits_per_raw_sample - 4);
+                res[0] = raw_samples[0];
+            }
+            if (opt_order > 1)
+                res[1] = decode_rice(gb, s[0] + 3);
+            if (opt_order > 2)
+                res[2] = decode_rice(gb, s[0] + 1);
+
+            start = FFMIN(opt_order, 3);
+        } else {
+            // TODO: Non random access blocks
+        }
+
+        // read all residuals
+        if (sconf->bgmc_mode) {
+            // TODO: BGMC mode
+        } else {
+            int64_t *current_res = res;
+
+            for (sb = 0; sb < sub_blocks; sb++) {
+                for (k = start; k < sb_length; k++) {
+                    current_res[k] = decode_rice(gb, s[sb]);
+                }
+                current_res += sb_length;
+                start = 0;
+            }
+         }
+
+        // reconstruct all samples from residuals
+        if (ra_block) {
+            unsigned int progressive = FFMIN(block_length, opt_order);
+
+            for (smp = 0; smp < progressive; smp++) {
+                // TODO: prediction
+            }
+
+            for (; smp < block_length; smp++) {
+                for (sb = 0; sb < progressive; sb++) {
+                    // TODO: prediction
+                }
+
+                raw_samples[smp] = res[smp];
+            }
+        } else {
+            // TODO: non random access blocks
+        }
+    }
+
+    if (sconf->RLSLMS) {
+        // TODO: read RLSLMS extension data
+    }
+
+    if (!sconf->mc_coding || ctx->js_switch) {
+        align_get_bits(gb);
+    }
+
+    return 0;
+}
+
+
 /** Reads the frame data.
  */
-static int read_frame_data(ALSDecContext *ctx)
+static int read_frame_data(ALSDecContext *ctx, unsigned int ra_frame)
 {
     ALSSpecificConfig *sconf = &ctx->sconf;
     GetBitContext *gb = &ctx->gb;
-    int c, b;
+    unsigned int div_blocks[32];                ///< Block sizes.
+    unsigned int c, b, ra_block, block_length;
+    int64_t *raw_samples;
+
     uint32_t bs_info = 0;
-    unsigned int num_blocks;
-    unsigned int div_blocks[32];
     unsigned int *ptr_div_blocks = &div_blocks[0];
 
     // skip ra_unit_size if present
-    if (sconf->ra_flag == 1 && !(ctx->frame_id % sconf->random_access))
+    if (sconf->ra_flag == 1 && ra_frame)
         skip_bits_long(gb, 32);
 
     if (sconf->mc_coding && sconf->joint_stereo) {
@@ -315,14 +524,9 @@ static int read_frame_data(ALSDecContext
                 bs_info <<= (32 - bs_info_len);
             }
 
-            num_blocks = 0;
-            parse_bs_info(bs_info, 0, 0, &ptr_div_blocks, &num_blocks);
-#ifdef DEBUG
-            dprintf(ctx->avctx, "bs_info = %x, block sizes:", bs_info);
-            for (b = 0; b < num_blocks; b++)
-                dprintf(ctx->avctx, " %i", div_blocks[b]);
-            dprintf(ctx->avctx, "\n");
-#endif
+            ctx->num_blocks = 0;
+            parse_bs_info(bs_info, 0, 0, &ptr_div_blocks, &ctx->num_blocks);
+
             // if this is the last channel, it has to be decoded independently
             if (c == sconf->channels - 1)
                 independent_bs = 1;
@@ -333,16 +537,28 @@ static int read_frame_data(ALSDecContext
                 independent_bs = bs_info >> 31;
 
             if (independent_bs) {
-                for (b = 0; b < num_blocks; b++) {
-                    dprintf(ctx->avctx, "reading block A\n");
-                    read_block_data(ctx);
+                raw_samples = ctx->raw_samples[c];
+
+                for (b = 0; b < ctx->num_blocks; b++) {
+                    ra_block = !b && ra_frame;
+                    block_length = sconf->frame_length >> div_blocks[b];
+                    read_block_data(ctx, ra_block, raw_samples, block_length);
+                    raw_samples += block_length;
                 }
             } else {
-                for (b = 0; b < num_blocks; b++) {
-                    dprintf(ctx->avctx, "reading block B\n");
-                    read_block_data(ctx);
-                    dprintf(ctx->avctx, "reading block C\n");
-                    read_block_data(ctx);
+                unsigned int offset = 0;
+
+                for (b = 0; b < ctx->num_blocks; b++) {
+                    ra_block = !b && ra_frame;
+                    block_length = sconf->frame_length >> div_blocks[b];
+
+                    raw_samples = ctx->raw_samples[c] + offset;
+                    read_block_data(ctx, ra_block, raw_samples, block_length);
+
+                    raw_samples = ctx->raw_samples[c + 1] + offset;
+                    read_block_data(ctx, ra_block, raw_samples, block_length);
+
+                    offset += block_length;
                 }
                 c++;
             }
@@ -354,18 +570,18 @@ static int read_frame_data(ALSDecContext
             bs_info <<= (32 - bs_info_len);
         }
 
-        num_blocks = 0;
-        parse_bs_info(bs_info, 0, 0, &ptr_div_blocks, &num_blocks);
-#ifdef DEBUG
-            dprintf(ctx->avctx, "bs_info = %x, block sizes:", bs_info);
-            for (b = 0; b < num_blocks; b++)
-                dprintf(ctx->avctx, " %i", div_blocks[b]);
-            dprintf(ctx->avctx, "\n");
-#endif
+        ctx->num_blocks = 0;
+        parse_bs_info(bs_info, 0, 0, &ptr_div_blocks, &ctx->num_blocks);
 
-        for (b = 0; b < num_blocks; b++) {
-            dprintf(ctx->avctx, "reading block D\n");
-            read_block_data(ctx);
+        // TODO: multi channel coding might use a temporary buffer instead as
+        //       the actual channel is not known when read_block-data is called
+        raw_samples = ctx->raw_samples[0];
+
+        for (b = 0; b < ctx->num_blocks; b++) {
+            ra_block = !b && ra_frame;
+            block_length = sconf->frame_length >> div_blocks[b];
+            read_block_data(ctx, ra_block, raw_samples, block_length);
+            raw_samples += block_length;
             // TODO: read_channel_data
         }
     }
@@ -386,16 +602,62 @@ static int decode_frame(AVCodecContext *
                         AVPacket *avpkt)
 {
     ALSDecContext *ctx       = avctx->priv_data;
+    ALSSpecificConfig *sconf = &ctx->sconf;
     const uint8_t *buffer    = avpkt->data;
     int buffer_size          = avpkt->size;
+    int16_t *dest            = (int16_t*)data;
+    unsigned int c, sample, ra_frame;
 
     init_get_bits(&ctx->gb, buffer, buffer_size * 8);
+    ra_frame = !ctx->frame_id ||
+               (sconf->random_access && !(ctx->frame_id % sconf->random_access));
 
-    if(read_frame_data(ctx)) {
+    // the last frame to decode might have a different length
+    if (ctx->num_frames && ctx->num_frames - 1 == ctx->frame_id) {
+        sconf->frame_length = ctx->last_frame_length;
+    }
+
+    // decode the frame data
+    if (read_frame_data(ctx, ra_frame)) {
         av_log(ctx->avctx, AV_LOG_ERROR, "Reading frame data failed.\n");
         return -1;
     }
 
+    // increment the frame counter
+    ctx->frame_id++;
+
+    // transform decoded frame into output format
+    // TODO: Support other resolutions than 16 bit
+    for (sample = 0; sample < sconf->frame_length; sample++) {
+        for (c = 0; c < sconf->channels; c++) {
+            *(dest++) = (int16_t) (ctx->raw_samples[c][sample]);
+        }
+    }
+
+    *data_size = sconf->frame_length * sconf->channels
+                                     * (avctx->sample_fmt == SAMPLE_FMT_S16 ?
+                                        2 : 4);
+
+    return buffer_size;
+}
+
+
+/** Uninitializes the ALS decoder.
+ */
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+    ALSDecContext *ctx       = avctx->priv_data;
+    ALSSpecificConfig *sconf = &ctx->sconf;
+    unsigned int c;
+
+    av_freep(&ctx->sconf.chan_pos);
+
+    if (ctx->raw_samples)
+        for (c = 0; c < sconf->channels; c++)
+            av_freep(&ctx->raw_samples[c]);
+
+    av_freep(&ctx->raw_samples);
+
     return 0;
 }
 
@@ -404,6 +666,7 @@ static int decode_frame(AVCodecContext *
  */
 static av_cold int decode_init(AVCodecContext *avctx)
 {
+    unsigned int c;
     ALSDecContext *ctx = avctx->priv_data;
     ctx->avctx = avctx;
 
@@ -415,6 +678,7 @@ static av_cold int decode_init(AVCodecCo
     if (read_specific_config(ctx, avctx->extradata + 6,
                              avctx->extradata_size - 6, &ctx->sconf)) {
         av_log(avctx, AV_LOG_ERROR, "Reading ALSSpecificConfig failed.\n");
+        decode_end(avctx);
         return -1;
     }
 
@@ -430,17 +694,22 @@ static av_cold int decode_init(AVCodecCo
         avctx->bits_per_raw_sample = (ctx->sconf.resolution + 1) * 8;
     }
 
-    return 0;
-}
-
+    avctx->frame_size = ctx->sconf.frame_length;
 
-/** Uninitializes the ALS decoder.
- */
-static av_cold int decode_end(AVCodecContext *avctx)
-{
-    ALSDecContext *ctx = avctx->priv_data;
+    if (!(ctx->raw_samples = av_malloc(sizeof(int64_t*) * avctx->channels))) {
+        av_log(avctx, AV_LOG_ERROR, "Allocating buffer array failed.\n");
+        decode_end(avctx);
+        return AVERROR_NOMEM;
+    }
 
-    av_freep(&ctx->sconf.chan_pos);
+    for (c = 0; c < avctx->channels; c++) {
+        if(!(ctx->raw_samples[c] = av_malloc(sizeof(int64_t)
+                                             * ctx->sconf.frame_length))) {
+            av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
+            decode_end(avctx);
+            return AVERROR_NOMEM;
+        }
+    }
 
     return 0;
 }


More information about the FFmpeg-soc mailing list