[FFmpeg-devel] [PATCH] ALS decoder

Thilo Borgmann thilo.borgmann
Sat Aug 22 23:36:16 CEST 2009


>> Revision 4 attached.
> [...]
>> +
>> +typedef struct {
>> +    uint32_t als_id;          ///< ALS identifier
> 
>> +    uint32_t samp_freq;       ///< sampling frequency in Hz
> 
> i suspect that is redundant with AVCodecContext.sample_rate
Oh yes it is now... as well as sconf->channels.
Using AVCodecContext fields now for both.


>> +    uint32_t samples;         ///< number of samples (per channel), 0xFFFFFFFF if unknown
> 
> doesnt seem to be needed to be stored in the context
Made local.


>> +    int file_type;            ///< not used, provided for debugging
> 
> if its just for debugging it can also be a local variable
Done.



>> +    int random_access;        ///< distance between RA frames (in frames, 0...255)
> 
> thats the keyframe distance or gop length i assume, it should be named
> accordingly
Done.



>> +    int bgmc_mode;            ///< BGMC Mode: 1 = on, 0 = off (Rice coding only)
> 
> bgmc?
Done.


>> +    int rlslms;               ///< use RLS-LMS predictor: 1 = on, 0 = off
> 
> RLSMLS?
> no i did not read the spec ...
It is correct as it is.


>> +    int aux_data_enabled;     ///< indicates that auxiliary data is present
> 
>> +    int chan_config_info;     ///< mapping of channels to loudspeaker locations
> 
> never read
But a TODO is set to use it in a future release.

>> +    int *chan_pos;            ///< original channel positions
> 
> same
Same.
Do these hurd so much it has to be reinserted later?


>> +    uint32_t crc;             ///< 32-bit CCITT-32 CRC checksum
> 
> and that one as well
Yes. Removed and crc_enabled made local.


> 
> 
> [...]
>> +    // allocate quantized parcor coefficient buffer
>> +    if (!(ctx->quant_cof = av_malloc(sizeof(int64_t) * sconf->max_order))) {
>> +        av_log(ctx->avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
>> +        return AVERROR(ENOMEM);
>> +    }
>> +
>> +    // allocate LPC coefficients
>> +    if (!(ctx->lpc_cof = av_malloc(sizeof(int64_t) * sconf->max_order))) {
>> +        av_log(ctx->avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
>> +        return AVERROR(ENOMEM);
>> +    }
> 
> duplicate and factorizeable code
Factorized.



>> +        if(!(sconf->chan_pos = av_malloc(sconf->channels * sizeof(int))))
>> +            return -1;
> 
> ENOMEM
Done.


>> +    ht_size = sconf->header_size + sconf->trailer_size;
> 
> overflow
Casted explicitly.


>> +    // skip the header and trailer data
>> +    if (buffer_size < ht_size)
>> +        return -1;
>> +
>> +    ht_size <<= 3;
>> +
>> +    while (ht_size > 0) {
>> +        int len = FFMIN(ht_size, INT32_MAX);
>> +        skip_bits_long(&gb, len);
>> +        ht_size -= len;
>> +    }
> 
> i dont think theres sense in supporting skiping of more than 500mb
> as valid packets should not have such sizes
This is done once per stream. Does the loop hurts so much to limit
ourselves to 32-bit?


>> +/** Parses the bs_info item to extract the block partitioning.
>> + */
> 
> without having read the spec, that says nothing to me ...
> can this be clarified in 1 sentance or is the reader required to have read
> the spec?
Reworded a bit. But I think if block partitioning is unclear, a much
better comment would be beyond one sentence and explains block switching.



>> +/** Reads and decodes a Rice codeword.
>> + */
>> +static int64_t decode_rice(GetBitContext *gb, unsigned int k)
>> +{
>> ...
>> +}
> 
> theres some obvious factorizeable code in there
Refactorized as far as I can see.
I rebenchmarked and it still needs around 760 dezicykles.
The skip rate sunk to a fifth, if this indicates something?


>> +/** Converts PARCOR coefficient k to direct filter coefficient.
>> + */
>> +static void parcor_to_lpc(unsigned int k, int64_t *par, int64_t *cof)
>> +{
>> +    int i;
>> +    int64_t tmp1, tmp2;
>> +
>> +    for (i = 0; i < (k+1) >> 1; i++) {
>> +        tmp1 = cof[    i    ] + ((par[k] * cof[k - i - 1] + (1 << 19)) >> 20);
>> +        tmp2 = cof[k - i - 1] + ((par[k] * cof[    i    ] + (1 << 19)) >> 20);
>> +        cof[k - i - 1] = tmp2;
>> +        cof[    i    ] = tmp1;
>> +    }
>> +
>> +    cof[k] = par[k];
>> +}
> 
> doesnt look entirely unfamiliar, dont some of our other audio codecs have
> something that can be used? (no i dont know which, i would have to RTFS too)
RTFS for me too and RTFM about other audio codecs... anyone?



>> +/** Reads the block data for a constant block
>> + */
>> +static void read_const_block(ALSDecContext *ctx, int64_t *raw_samples,
>> +                             unsigned int block_length, unsigned int *js_blocks)
>> +{
>> ...
>> +    // skip 5 reserved bits
>> +    skip_bits(gb, 5);
> 
> if these have a required value like 0 that should be checked, always usefull
> to know early if something unexpected turns up
Not the case here.


> 
> 
>> +
>> +    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;
> 
> why would const_val_bits != avctx->bits_per_raw_sample ?
bits_per_raw_sample = 32 for floating sconf->floating.



>> +/** 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)
>> +{
>> ...
>> +    // 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;
> 
> id write 1 << (2*get_bits1(gb))
> because its more simlar to the others
I like that, too. Done.



>> +    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
>> +    }
> 
> if(x)
> else
> 
> is imho clearer than
> 
> if(!x)
> else
Done.



>> +                quant_index = get_bits(gb, 7) - 64;
>> +                quant_cof[0] = parcor_scaled_values[quant_index + 64];
> 
> -64 + 64 ?
>> +                quant_index = get_bits(gb, 7) - 64;
>> +                quant_cof[1] = -parcor_scaled_values[quant_index + 64];
> 
> same
Done.



>> +                // read coefficients 2 to opt_order
>> +                for (k = 2; k < opt_order; k++) {
>> +                    quant_index = get_bits(gb, 7) - 64;
>> +                    quant_cof[k] = (quant_index << 14) + (1 << 13);
> 
> the +- can be combined
Sorry I can't see that..



>> +                k_max = FFMIN(20, opt_order);
>> +                for (k = 2; k < k_max; k++) {
>> ...
>> +                }
>> ...
>> +                k_max = FFMIN(127, opt_order);
>> +                for (k = 20; k < k_max; k++) {
> 
> k=20 is redundant
> 
> 
>> +                // read coefficients 127 to opt_order
>> +                for (k = 127; k < opt_order; k++) {
> 
> so is k=127
No, this is correct.
 for(; k < 20;)
 for(k = 20;;)



>> +            memcpy(ctx->prev_raw_samples, raw_samples - sconf->max_order,
>> +                   sizeof(int64_t) * sconf->max_order);
> 
> instead of duplicating the type (int64_t) the type of the array should be used
Sorry I don't understand this. Please elaborate.


>> +static int decode_frame(AVCodecContext *avctx,
>> +                        void *data, int *data_size,
>> +                        AVPacket *avpkt)
>> +{
>> ...
>> +    ra_frame = sconf->random_access && ((!ctx->frame_id) ||
>> +               !(ctx->frame_id % sconf->random_access));
> 
> the !ctx->frame_id condition seems unneeded
Indeed. Done.



>> +    // allocate previous raw sample buffer
>> +    if (!(ctx->prev_raw_samples = av_malloc(sizeof(int64_t) * sconf->max_order))) {
>> +        av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
>> +        decode_end(avctx);
>> +        return AVERROR(ENOMEM);
>> +    }
>> +
>> +    // allocate raw and carried sample buffer
>> +    if (!(ctx->raw_buffer = av_mallocz(sizeof(int64_t) *
>> +                                       avctx->channels * channel_size))) {
>> +        av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
>> +        decode_end(avctx);
>> +        return AVERROR(ENOMEM);
>> +    }
> 
> factorizeable with a goto
If you don't veto on a or'd if, I would prefer that.



>> Index: libavutil/common.h
>> ===================================================================
>> --- libavutil/common.h	(revision 19673)
>> +++ libavutil/common.h	(working copy)
>> @@ -225,6 +225,14 @@
>>      else               return a;
>>  }
>>  
>> +/** Computes ceil(log2(x)) using av_log2.
>> + * @param x value used to compute ceil(log2(x))
>> + * @param computed ceiling of log2(x)
>> + */
>> +static inline int ceil_log2(int x) {
>> +    return x > 1 ? av_log2((x - 1) << 1) : 0;
>> +}
>> +
>>  #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
>>  #define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
>>  
> 
> should be a seperate patch
Ok.


All changes included in revision 5.

Thanks!

-Thilo



More information about the ffmpeg-devel mailing list