[FFmpeg-devel] [PATCH] ATRAC3+ decoder, 2nd try

Maxim Polijakowski max_pole at gmx.de
Tue Nov 19 13:50:14 CET 2013


Hello Michael,

a new patch has been sent in a separate mail.

My comments are located below...

> [...]
>> +static void add_wordlen_weights(Atrac3pChanUnitCtx *ctx,
>> +                                Atrac3pChanParams *chan, int wtab_idx)
>> +{
>> +    int i;
>> +    const int8_t *weights_tab =
>> +        &ff_atrac3p_wl_weights[chan->ch_num * 3 + wtab_idx - 1][0];
>> +
>> +    for (i = 0; i < ctx->num_quant_units; i++)
>> +        chan->qu_wordlen[i] += weights_tab[i];
> this is probably missing a &7 or some other kind of check
> qu_wordlen[] is used as index into an array

Checks added...

>
>> +}
>> +
>> +static void subtract_sf_weights(Atrac3pChanUnitCtx *ctx,
>> +                                Atrac3pChanParams *chan, int wtab_idx)
>> +{
>> +    int i;
>> +    const int8_t *weights_tab;
>> +
>> +    weights_tab = &ff_atrac3p_sf_weights[wtab_idx - 1][0];
>> +
>> +    for (i = 0; i < ctx->used_quant_units; i++)
>> +        chan->qu_sf_idx[i] -= weights_tab[i];
> this too is probably missing some kind of check or wraparound on the
> limits, also quite possibly other related routines need checks

Yes, added checks and war-arounds...


>
>> +}
>> +
>> +static void unpack_wordlen_shape(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
>> +                                 Atrac3pChanParams *chan)
>> +{
>> +    int i;
>> +    const int8_t *shape_vec;
>> +    int start_val = get_bits(gb, 3);
>> +    int shape_idx = get_bits(gb, 4);
>> +
>> +    if (chan->num_coded_vals) {
>> +        shape_vec = &ff_atrac3p_wl_shapes[start_val][shape_idx][0];
>> +
>> +        /* unpack shape vector values for each quant unit */
>> +        chan->qu_wordlen[0] = start_val;
>> +        chan->qu_wordlen[1] = start_val;
>> +        chan->qu_wordlen[2] = start_val;
>> +
>> +        for (i = 3; i < chan->num_coded_vals; i++)
>> +            chan->qu_wordlen[i] = start_val -
>> +                                  shape_vec[ff_atrac3p_qu_num_to_seg[i] - 1];
>> +    }
>> +}
>> +
>> +static void unpack_scalefactor_shape(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
>> +                                     Atrac3pChanParams *chan)
>> +{
>> +    int i;
>> +    const int8_t *shape_vec;
>> +    int start_val = get_bits(gb, 6);
>> +    int shape_idx = get_bits(gb, 6);
>> +
>> +    if (ctx->used_quant_units) {
>> +        shape_vec = &ff_atrac3p_sf_shapes[shape_idx][0];
>> +
>> +        /* unpack shape vector values for each quant unit */
>> +        chan->qu_sf_idx[0] = start_val;
>> +        chan->qu_sf_idx[1] = start_val;
>> +        chan->qu_sf_idx[2] = start_val;
>> +
>> +        for (i = 3; i < ctx->used_quant_units; i++)
>> +            chan->qu_sf_idx[i] = start_val -
>> +                                 shape_vec[ff_atrac3p_qu_num_to_seg[i] - 1];
>> +    }
>> +}
> the qu_wordlen and qu_sf_idx related code looks quite similar in
> various places of the code, possible it could be factorized to make
> it simpler ?


The above-mentioned vector unpacking operation has been factorized out.

The rest has been left as is. You're right that the code untilizes the 
same operation set again and again. Though its factorization doesn't 
actually worth the hassle because parts to be factorized out are:
--> rather small (1-3 lines)
--> using several parameters (masks, lengths, ranges etc.)

I already tried to do that with "decode_channel_code_tab". The result 
isn't impressive at all and looks like 
"impossible-to-understand-code-magic"...


> [...]
>> +                for (i = pos; i < chan->num_coded_vals; i++)
>> +                    chan->qu_wordlen[i] = min_val + GET_DELTA(gb, delta_bits);
> this is probably missing a &7 or some other kind of check

Yes, checks added...

>
> [...]
>> +static inline void gainc_loc_mode0(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
>> +                                   AtracGainInfo *dst, int pos)
>> +{
>> +    int delta_bits;
>> +
>> +    if (!pos || dst->loc_code[pos - 1] < 15)
>> +        dst->loc_code[pos] = get_bits(gb, 5);
>> +    else if (dst->loc_code[pos - 1] == 30)
>> +        dst->loc_code[pos] = 31;
>> +    else {
>> +        delta_bits         = av_log2(30 - dst->loc_code[pos - 1]) + 1;
> for loc code 30 or larger this looks odd

Yes, it's wrong also.
I've changed the condition from "== 30" to ">= 30" and add validation of 
decoded values at the end of the function.

>
>> +        dst->loc_code[pos] = dst->loc_code[pos - 1] +
>> +                             get_bits(gb, delta_bits) + 1;
> i suspect this should be checked against some max or maybe wrap around

Done...

>
>> +    }
>> +}
>> +
>> +static inline void gainc_loc_mode1(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
>> +                                   AtracGainInfo *dst)
>> +{
>> +    int i;
>> +    VLC *tab;
>> +
>> +    if (dst->num_points > 0) {
>> +        /* 1st coefficient is stored directly */
>> +        dst->loc_code[0] = get_bits(gb, 5);
>> +
>> +        for (i = 1; i < dst->num_points; i++) {
>> +            /* switch VLC according to the curve direction
>> +             * (ascending/descending) */
>> +            tab              = (dst->lev_code[i] <= dst->lev_code[i - 1])
>> +                               ? &gain_vlc_tabs[7]
>> +                               : &gain_vlc_tabs[9];
>> +            dst->loc_code[i] = dst->loc_code[i - 1] +
>> +                               get_vlc2(gb, tab->table, tab->bits, 1);
> like mode0, i suspect this should be checked against some max or maybe wrap around

Done...

>
> [...]
>> +/**
>> + * Decode gain control data for all channels.
>> + *
>> + * @param[in,out] ctx           ptr to the decoder context
>> + * @param[in]     num_channels  number of channels to process
>> + * @param[in]     avctx         ptr to the AVCodecContext
>> + */
>> +static int decode_gainc_data(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
>> +                             int num_channels, AVCodecContext *avctx)
>> +{
>> +    int ch_num, coded_subbands, sb, ret;
>> +
>> +    for (ch_num = 0; ch_num < num_channels; ch_num++) {
>> +        memset(ctx->channels[ch_num].gain_data, 0,
>> +               sizeof(*ctx->channels[ch_num].gain_data) * ATRAC3P_SUBBANDS);
>> +
>> +        if (get_bits1(gb)) { /* gain control data present? */
>> +            coded_subbands = get_bits(gb, 4) + 1;
>> +            if (get_bits1(gb)) /* is high band gain data replication on? */
>> +                ctx->channels[ch_num].num_gain_subbands = get_bits(gb, 4) + 1;
>> +            else
>> +                ctx->channels[ch_num].num_gain_subbands = coded_subbands;
>> +
>> +            if ((ret = decode_gainc_npoints(gb, ctx, ch_num, coded_subbands, avctx)   < 0) ||
>> +                (ret = decode_gainc_levels(gb, ctx, ch_num, coded_subbands, avctx)    < 0) ||
>> +                (ret = decode_gainc_loc_codes(gb, ctx, ch_num, coded_subbands, avctx) < 0))
> this looks like its missing some ()

It actually doesn't do. Otherwise it won't compile....

Best regards
Maxim


More information about the ffmpeg-devel mailing list