[FFmpeg-devel] [PATCH] ALS decoder

Michael Niedermayer michaelni
Wed Aug 26 16:36:20 CEST 2009


On Tue, Aug 25, 2009 at 07:59:32PM +0200, Thilo Borgmann wrote:
> Revision 10 attached.
[...]

> +typedef struct {
> +    int resolution;           ///< 000 = 8-bit; 001 = 16-bit; 010 = 24-bit; 011 = 32-bit
> +    int floating;             ///< 1 = IEEE 32-bit floating-point, 0 = integer
> +    int frame_length;         ///< frame length for each frame (last frame may differ)
> +    int ra_distance;          ///< distance between RA frames (in frames, 0...255)
> +    enum RA_Flag ra_flag;     ///< indicates where the size of ra units is stored
> +    int adapt_order;          ///< adaptive order: 1 = on, 0 = off
> +    int coef_table;           ///< table index of Rice code parameters
> +    int long_term_prediction; ///< long term prediction (LTP): 1 = on, 0 = off
> +    int max_order;            ///< maximum prediction order (0..1023)
> +    int block_switching;      ///< number of block switching levels
> +    int bgmc;                 ///< "Block Gilbert-Moore Code": 1 = on, 0 = off (Rice coding only)
> +    int sb_part;              ///< sub-block partition
> +    int joint_stereo;         ///< joint Stereo: 1 = on, 0 = off

> +    int mc_coding;            ///< extended inter-channel coding: 1 = on, 0 = off

what does mc stand for? i cant associate that to "extended inter-channel coding"


[...]
> +/** Reads and decodes a Rice codeword.
> + */
> +static int64_t decode_rice(GetBitContext *gb, unsigned int k)
> +{
> +    int max = gb->size_in_bits - get_bits_count(gb) - k;
> +    int q   = get_unary(gb, 0, max);
> +
> +    if (k > 1) {
> +        int64_t value;
> +        unsigned int r, sub_sign;
> +
> +        sub_sign  = get_bits1(gb);
> +        r         = get_bits_long(gb, k - 1);
> +
> +        value = ((int64_t)q << (k - 1)) + r;
> +
> +        return sub_sign ? value : ~value;
> +    } else  if (k) {
> +        return get_bits1(gb) ? q : ~q;
> +    } else {
> +        int r;

> +        r = q & 1;
> +        q = (q >> 1) + r;
> +        return r ? -q : q;

r = q & 1;
q = (q >> 1);
return r ? ~q : q;

and next
return r ? ~q : q;
can be factored out of the 3 cases



[...]
> +/** Reads the block data for a non-constant block
> + */
> +static int read_var_block(ALSDecContext *ctx, unsigned int ra_block,
> +                          int64_t *raw_samples, unsigned int block_length,
> +                          unsigned int *js_blocks, int64_t *raw_other,
> +                          unsigned int *shift_lsbs)
> +{
> +    ALSSpecificConfig *sconf = &ctx->sconf;
> +    AVCodecContext *avctx    = ctx->avctx;
> +    GetBitContext *gb        = &ctx->gb;
> +    unsigned int k;
> +    unsigned int s[8];
> +    unsigned int sub_blocks, sb_length;
> +    unsigned int opt_order  = 1;
> +    int32_t      *quant_cof = ctx->quant_cof;
> +    int32_t      *lpc_cof   = ctx->lpc_cof;
> +    unsigned int start      = 0;
> +    int          sb, smp;
> +    int64_t      y;
> +
> +    *js_blocks  = get_bits1(gb);
> +
> +    // determine the number of sub blocks for entropy decoding
> +    if (!sconf->bgmc && !sconf->sb_part)
> +        sub_blocks = 1;
> +    else if (sconf->bgmc && sconf->sb_part)
> +        sub_blocks = 1 << get_bits(gb, 2);
> +    else
> +        sub_blocks = 1 << (2 * get_bits1(gb));
> +
> +    // do not continue in case of a damaged stream since
> +    // block_length must be evenly divisible by sub_blocks
> +    if (block_length % sub_blocks) {
> +        av_log(avctx, AV_LOG_WARNING,
> +               "Block length is not evenly divisible by the number of sub blocks.\n");
> +        return -1;
> +    }
> +
> +    sb_length = block_length / sub_blocks;
> +
> +
> +    if (sconf->bgmc) {
> +        // TODO: BGMC mode
> +    } else {
> +        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);
> +    }
> +
> +    if (get_bits1(gb))
> +        *shift_lsbs = get_bits(gb, 4) + 1;
> +
> +
> +    if (!sconf->rlslms) {
> +        if (sconf->adapt_order) {

> +            int opt_order_length = FFMIN(av_ceil_log2(sconf->max_order+1),
> +                                   FFMAX(av_ceil_log2((block_length >> 3) - 1), 1));

in this is pretty hard to see what is done, maybe a temporary variable
could be used?


> +            opt_order = get_bits(gb, opt_order_length);
> +        } else {
> +            opt_order = sconf->max_order;
> +        }
> +
> +        if (opt_order) {
> +            if (sconf->coef_table == 3) {
> +                // read coefficient 0

> +                quant_cof[0] = parcor_scaled_values[get_bits(gb, 7)];;

;;


> +
> +                // read coefficient 1
> +                quant_cof[1] = -parcor_scaled_values[get_bits(gb, 7)];
> +
> +                // read coefficients 2 to opt_order
> +                for (k = 2; k < opt_order; k++)
> +                    quant_cof[k] = (get_bits(gb, 7) << 14) - (0x7F << 13);
> +            } else {
> +                int offset, rice_param, k_max;
> +                int64_t quant_index;
> +
> +
> +                // read coefficient 0 to 19
> +                k_max = FFMIN(20, opt_order);
> +                for (k = 0; k < k_max; k++) {
> +                    offset       = parcor_rice_table[sconf->coef_table][k][0];
> +                    rice_param   = parcor_rice_table[sconf->coef_table][k][1];
> +                    quant_cof[k] = decode_rice(gb, rice_param) + offset;
> +                }
> +
> +                quant_cof[0] =  parcor_scaled_values[quant_cof[0] + 64];
> +                quant_cof[1] = -parcor_scaled_values[quant_cof[1] + 64];
> +
> +                for (k = 2; k < k_max; k++)
> +                    quant_cof[k] = (quant_cof[k] << 14) + (1 << 13);
> +
> +                // read coefficients 20 to 126
> +                k_max = FFMIN(127, opt_order);
> +                for (; k < k_max; k++) {
> +                    offset       = k & 1;
> +                    rice_param   = 2;
> +                    quant_index  = decode_rice(gb, rice_param) + offset;
> +                    quant_cof[k] = (quant_index << 14) + (1 << 13);
> +                }
> +
> +                // read coefficients 127 to opt_order
> +                for (; k < opt_order; k++) {
> +                    offset       = 0;
> +                    rice_param   = 1;
> +                    quant_index  = decode_rice(gb, rice_param) + offset;
> +                    quant_cof[k] = (quant_index << 14) + (1 << 13);
> +                }
> +            }
> +        }
> +    }
> +
> +    // 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);
> +        if (opt_order > 1)
> +            raw_samples[1] = decode_rice(gb, s[0] + 3);
> +        if (opt_order > 2)
> +            raw_samples[2] = decode_rice(gb, s[0] + 1);
> +
> +        start = FFMIN(opt_order, 3);
> +    } else {
> +        for (k = 0; k < opt_order; k++)
> +            parcor_to_lpc(k, quant_cof, lpc_cof);
> +    }
> +
> +    // read all residuals
> +    if (sconf->bgmc) {
> +        // TODO: BGMC mode
> +    } else {
> +        int64_t *current_res = raw_samples;
> +
> +        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 < block_length; smp++) {
> +            unsigned int max, dequant;
> +
> +            dequant = smp < progressive;
> +            max     = dequant ? smp : progressive;
> +
> +            y = 1 << 19;
> +
> +            for (sb = 0; sb < max; sb++)
> +                y += lpc_cof[sb] * raw_samples[smp - (sb + 1)];
> +
> +            raw_samples[smp] -= y >> 20;
> +            if (dequant)
> +                parcor_to_lpc(smp, quant_cof, lpc_cof);
> +        }
> +    } else {
> +        int store_prev_samples = (*js_blocks && raw_other) || *shift_lsbs;
> +
> +        // store previous smaples in case that they have to be altered
> +        if (store_prev_samples)
> +            memcpy(ctx->prev_raw_samples, raw_samples - sconf->max_order,
> +                   sizeof(*ctx->prev_raw_samples) * sconf->max_order);
> +
> +        // reconstruct difference signal for prediction (joint-stereo)
> +        if (*js_blocks && raw_other) {
> +            int i;
> +            if (raw_other > raw_samples) {          // D = R - L
> +                for (i = -1; i >= -sconf->max_order; i--)
> +                    raw_samples[i] = raw_other[i] - raw_samples[i];
> +            } else {                                // D = R - L
> +                for (i = -1; i >= -sconf->max_order; i--)
> +                    raw_samples[i] = raw_samples[i] - raw_other[i];
> +            }
> +        }
> +

> +        // reconstruct shifted signal
> +        if (*shift_lsbs)
> +            for (smp = -1; smp >= -sconf->max_order; smp--)
> +                raw_samples[smp] >>= *shift_lsbs;

has that been tested? or is shift_lsbs == 0 for all files we have?


[...]
> +/** Computes the bytes left to decode for the current frame
> + */
> +static inline unsigned int count_remaining(unsigned int b, unsigned int b_max,
> +                                           unsigned int *div_blocks)

this doesnt need to be inline, i belive its not speed critical, but rather
handling just damaged bitstreams or am i misunderstanding the code?

also maybe this one could do the memset as well


[...]
> +/** Decodes an ALS frame.
> + */
> +static int decode_frame(AVCodecContext *avctx,
> +                        void *data, int *data_size,
> +                        AVPacket *avpkt)
> +{
> +    ALSDecContext *ctx       = avctx->priv_data;
> +    ALSSpecificConfig *sconf = &ctx->sconf;
> +    const uint8_t *buffer    = avpkt->data;
> +    int buffer_size          = avpkt->size;
> +    int invalid_frame        = 0;
> +    unsigned int c, sample, ra_frame, bytes_read, shift;
> +
> +    init_get_bits(&ctx->gb, buffer, buffer_size * 8);
> +    ra_frame = sconf->ra_distance && !(ctx->frame_id % sconf->ra_distance);
> +
> +    // the last frame to decode might have a different length
> +    if (ctx->num_frames && ctx->num_frames - 1 == ctx->frame_id) {
> +        ctx->cur_frame_length = ctx->last_frame_length;
> +    }
> +
> +    // decode the frame data
> +    if ((invalid_frame = read_frame_data(ctx, ra_frame)))
> +        av_log(ctx->avctx, AV_LOG_WARNING,
> +               "Reading frame data failed. Skipping RA unit.\n");
> +

> +    // increment the frame counter
> +    ctx->frame_id++;

that wont work with seeking
I think ive not missed some setting of frame_id to a value from the
bitstream


> +
> +    // transform decoded frame into output format
> +    #define INTERLEAVE_OUTPUT(bps)                                 \
> +    {                                                              \
> +        int##bps##_t *dest = (int##bps##_t*) data;                 \
> +        shift = bps - ctx->avctx->bits_per_raw_sample;             \
> +        for (sample = 0; sample < ctx->cur_frame_length; sample++) \
> +            for (c = 0; c < avctx->channels; c++)                  \
> +                *dest++ = ctx->raw_samples[c][sample] << shift;    \
> +    }
> +
> +    if (ctx->avctx->bits_per_raw_sample <= 16) {
> +        INTERLEAVE_OUTPUT(16)
> +    } else {
> +        INTERLEAVE_OUTPUT(32)
> +    }
> +
> +    *data_size = ctx->cur_frame_length * avctx->channels
> +                 * (av_get_bits_per_sample_format(avctx->sample_fmt) >> 3);

i think you dont check data_size for being large enough


[...]
> +/** Initializes the ALS decoder.
> + */
> +static av_cold int decode_init(AVCodecContext *avctx)
> +{
> +    unsigned int c;
> +    unsigned int channel_size;
> +    ALSDecContext *ctx = avctx->priv_data;
> +    ALSSpecificConfig *sconf = &ctx->sconf;
> +    ctx->avctx = avctx;
> +
> +    if (!avctx->extradata) {
> +        av_log(avctx, AV_LOG_ERROR, "Missing required ALS extradata.\n");
> +        return -1;
> +    }
> +
> +    if (read_specific_config(ctx)) {
> +        av_log(avctx, AV_LOG_ERROR, "Reading ALSSpecificConfig failed.\n");
> +        decode_end(avctx);
> +        return -1;
> +    }
> +
> +    if (check_specific_config(ctx)) {
> +        decode_end(avctx);
> +        return -1;
> +    }
> +
> +    if (sconf->floating) {
> +        avctx->sample_fmt          = SAMPLE_FMT_FLT;
> +        avctx->bits_per_raw_sample = 32;
> +    } else {
> +        avctx->sample_fmt          = sconf->resolution > 1
> +                                     ? SAMPLE_FMT_S32 : SAMPLE_FMT_S16;
> +        avctx->bits_per_raw_sample = (sconf->resolution + 1) * 8;
> +    }
> +
> +    avctx->frame_size = sconf->frame_length;
> +    channel_size      = sconf->frame_length + sconf->max_order;
> +
> +    // allocate previous raw sample buffer

> +    if (!(ctx->prev_raw_samples = av_malloc(sizeof(int64_t) * sconf->max_order)) ||
> +        !(ctx->raw_buffer = av_mallocz(sizeof(int64_t) * avctx->channels * channel_size))) {

vertical align

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Observe your enemies, for they first find out your faults. -- Antisthenes
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090826/a9bf9fc0/attachment.pgp>



More information about the ffmpeg-devel mailing list