[FFmpeg-devel] [PATCH] add E-AC-3 support to AC-3 decoder

Michael Niedermayer michaelni
Tue Jun 17 22:14:24 CEST 2008


On Sat, Jun 07, 2008 at 10:30:31AM -0400, Justin Ruggles wrote:
> Hi,
> 
> Here is a patch set to incrementally add support for E-AC-3 to the AC-3
> decoder.  There are 32 total patches.  I'm just attaching them all in
> this email instead of doing the git-send-email thing.
> 
> Commit log messages:
> 

[...]

> [PATCH 22/32] add eac3dec.c

see below


> [PATCH 23/32] share some functions from eac3dec.c

ok (unless some of it becomes unneeded due to other changes ...)


> [PATCH 24/32] prepare header parsing to support E-AC-3

ok


[...]
> [PATCH 27/32] add decoding of transform coefficients for E-AC-3

see below


[...]
> +
> +#include "avcodec.h"
> +#include "ac3.h"
> +#include "ac3_parser.h"
> +#include "ac3dec.h"
> +#include "ac3dec_data.h"
> +
> +/** Channel gain adaptive quantization mode */
> +typedef enum {
> +    EAC3_GAQ_NO =0,
> +    EAC3_GAQ_12,
> +    EAC3_GAQ_14,
> +    EAC3_GAQ_124
> +} EAC3GaqMode;
> +
> +#define EAC3_SR_CODE_REDUCED  3
> +
> +static int idct_cos_tab[6][5];
> +
> +static int gaq_ungroup_tab[32][3];
> +

> +void ff_eac3_log_missing_feature(AVCodecContext *avctx, const char *log){
> +    av_log(avctx, AV_LOG_ERROR, "%s is not implemented. If you want to help, "
> +            "update your FFmpeg version to the newest one from SVN. If the "
> +            "problem still occurs, it means that your file has extension "
> +            "which has not been tested due to a lack of samples exhibiting "
> +            "this feature. Upload a sample of the audio from this file to "
> +            "ftp://upload.mplayerhq.hu/incoming and contact the ffmpeg-devel "
> +            "mailing list.\n", log);
> +}

I think this should be in utils.c it could be used by non ac3 as well


> +
> +void ff_eac3_get_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch){
> +    int bin, blk, gs;
> +    int end_bap, gaq_mode;
> +    GetBitContext *gbc = &s->gbc;
> +    int gaq_gain[AC3_MAX_COEFS];
> +
> +    gaq_mode = get_bits(gbc, 2);
> +    end_bap = (gaq_mode < 2) ? 12 : 17;
> +

> +    /* if GAQ gain is used, decode gain codes for bins with hebap between
> +       8 and end_bap */
> +    if (gaq_mode == EAC3_GAQ_12 || gaq_mode == EAC3_GAQ_14) {
> +        /* read 1-bit GAQ gain codes */
> +        gs = 0;
> +        for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) {
> +            if (s->bap[ch][bin] > 7 && s->bap[ch][bin] < end_bap)
> +                gaq_gain[gs++] = get_bits1(gbc) << (gaq_mode-1);
> +        }
> +    } else if (gaq_mode == EAC3_GAQ_124) {
> +        /* read 1.67-bit GAQ gain codes (3 codes in 5 bits) */
> +        int gc = 2;
> +        gs = 0;

the gs=0 can be factored out


> +        for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) {
> +            if (s->bap[ch][bin] > 7 && s->bap[ch][bin] < end_bap) {
> +                if(gc++ == 2) {
> +                    int group_gain = get_bits(gbc, 5);
> +                    gaq_gain[gs++] = gaq_ungroup_tab[group_gain][0];
> +                    gaq_gain[gs++] = gaq_ungroup_tab[group_gain][1];
> +                    gaq_gain[gs++] = gaq_ungroup_tab[group_gain][2];
> +                    gc = 0;
> +                }
> +            }
> +        }
> +    }
> +
> +    gs=0;
> +    for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) {
> +        int hebap = s->bap[ch][bin];
> +        int bits = ff_eac3_bits_vs_hebap[hebap];

> +        if (!hebap) {
> +            /* hebap=0 */

the comment is redundant, if you prefer use if(hebap == 0) but using !hebap
+ a coment really is worst


> +            for (blk = 0; blk < 6; blk++) {
> +                s->pre_mantissa[blk][ch][bin] = (av_random(&s->dith_state) & 0x7FFFFF) - 4194304;

id write 4194304 in hex as well to make its relation to 0x7FFFFF more clear


> +            }
> +        } else if (hebap < 8) {
> +            /* Vector Quantization */
> +            int v = get_bits(gbc, bits);
> +            for (blk = 0; blk < 6; blk++) {
> +                s->pre_mantissa[blk][ch][bin] = ff_eac3_vq_hebap[hebap][v][blk] << 8;
> +            }
> +        } else {
> +            /* Gain Adaptive Quantization */
> +            int gbits, log_gain;
> +            if (gaq_mode != EAC3_GAQ_NO && hebap < end_bap) {
> +                log_gain = gaq_gain[gs++];
> +            } else {
> +                log_gain = 0;
> +            }
> +            gbits = bits - log_gain;
> +
> +            for (blk = 0; blk < 6; blk++) {

> +                int mant;
> +                int pre_mantissa = get_sbits(gbc, gbits);

You dont need 2 variables here


> +                if (pre_mantissa == -(1 << (gbits-1))) {
> +                    /* large mantissa */
> +                    int64_t a, b;
> +                    mant = get_sbits(gbc, bits-2+log_gain) << (26-log_gain-bits);
> +                    /* remap mantissa value to correct for asymmetric quantization */
> +                    a = ff_eac3_gaq_remap_2_4_a[hebap-8][log_gain-1] + 32768;
> +                    if(mant >= 0)
> +                        b = 32768 >> log_gain;
> +                    else
> +                        b = ff_eac3_gaq_remap_2_4_b[hebap-8][log_gain-1];
> +                    mant = (a * mant + b) >> 15;
> +                } else {
> +                    /* small mantissa, no GAQ, or Gk=1 */
> +                    mant = pre_mantissa << (24 - bits);
> +                    if(!log_gain) {
> +                        /* remap mantissa value for no GAQ or Gk=1 */

> +                        int64_t a = ff_eac3_gaq_remap_1[hebap-8] + 32768;
> +                        mant = (a * mant) >> 15;

mant += (ff_eac3_gaq_remap_1[hebap-8] * mant) >> 15;

maybe with int64 cast as needed
the +32768 can similarly be removed from the other side of the else


> +                    }
> +                }
> +                s->pre_mantissa[blk][ch][bin] = mant;
> +            }
> +        }
> +    }
> +}
> +

> +void ff_eac3_idct_transform_coeffs_ch(AC3DecodeContext *s, int ch, int blk){
> +    int bin, i;

> +    int64_t tmp;
> +    for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) {
> +        tmp = s->pre_mantissa[0][ch][bin];

declaration and init can be merged


> +        for (i = 1; i < 6; i++) {
> +            tmp += ((int64_t)idct_cos_tab[blk][i-1] * (int64_t)s->pre_mantissa[i][ch][bin]) >> 23;
> +        }
> +        s->fixed_coeffs[ch][bin] = tmp >> s->dexps[ch][bin];
> +    }
> +}

there are symmetries in the idct, this brute force solution is a little
umm ...


> +
> +static int parse_bsi(AC3DecodeContext *s){
> +    int i, blk;
> +    GetBitContext *gbc = &s->gbc;
> +
> +    /* an E-AC3 stream can have multiple independent streams which the
> +       application can select from. each independent stream can also contain
> +       dependent streams which are used to add or replace channels. */
> +    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
> +        ff_eac3_log_missing_feature(s->avctx, "Dependent substream");
> +        return AC3_PARSE_ERROR_FRAME_TYPE;
> +    } else if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) {
> +        av_log(s->avctx, AV_LOG_ERROR, "Reserved frame type\n");
> +        return AC3_PARSE_ERROR_FRAME_TYPE;
> +    }
> +
> +    /* the substream id indicates which substream this frame belongs to. each
> +       independent stream has its own substream id, and the dependent streams
> +       associated to an independent stream have matching substream id's */

> +    if (s->substreamid) {
> +        // TODO: allow user to select which substream to decode
> +        av_log(s->avctx, AV_LOG_INFO, "Skipping additional substream #%d\n",
> +               s->substreamid);

These should be split in the demuxer layer, please update the TODO comment
to make this clear, i dont want people working on implementing things the
wrong way ...


[...]
> +    s->bit_allocation_syntax = get_bits1(gbc);
> +    if (!s->bit_allocation_syntax) {
> +        /* set default bit allocation parameters */
> +        s->bit_alloc_params.slow_decay = ff_ac3_slow_decay_tab[2];  /* Table 7.6 */
> +        s->bit_alloc_params.fast_decay = ff_ac3_fast_decay_tab[1];  /* Table 7.7 */
> +        s->bit_alloc_params.slow_gain  = ff_ac3_slow_gain_tab [1];  /* Table 7.8 */
> +        s->bit_alloc_params.db_per_bit = ff_ac3_db_per_bit_tab[2];  /* Table 7.9 */
> +        s->bit_alloc_params.floor      = ff_ac3_floor_tab     [7];  /* Table 7.10 */
> +    }

> +    s->fast_gain_syntax = get_bits1(gbc);
> +    s->dba_syntax = get_bits1(gbc);
> +    s->skip_syntax = get_bits1(gbc);
> +    parse_spx_atten_data = get_bits1(gbc);

vertical align ...


[...]
> +    if (parse_aht_info) {
> +        /* AHT is only available in 6 block mode (numblkscod ==3) */
> +        /* coupling can use AHT only when coupling in use for all blocks */
> +        /* ncplregs derived from cplstre and cplexpstr - see Section E3.3.2 */

> +        int nchregs;
> +        s->channel_uses_aht[CPL_CH]=0;
> +        for (ch = (num_cpl_blocks != 6); ch <= s->channels; ch++) {
> +            nchregs = 0;

declaration and init can be merged


[...]
> +void ff_eac3_tables_init(void) {
> +    int blk, i;
> +
> +    // initialize IDCT cosine table for use with AHT
> +    for(blk=0; blk<6; blk++) {
> +        for(i=1; i<6; i++) {
> +            idct_cos_tab[blk][i-1] = (M_SQRT2 * cos(M_PI*i*(2*blk + 1)/12) * 8388608.0) + 0.5;

8388608 could be replaced by (1<<X)

and instead of + 0.5 with an implicit cast to int, whic results in wrong
rounding this could use the appropriate rint()


> +        }
> +    }
> +

> +    // initialize ungrouping table for 1.67-bit GAQ gain codes
> +    for(i=0; i<32; i++) {
> +        gaq_ungroup_tab[i][0] = i / 9;
> +        gaq_ungroup_tab[i][1] = (i % 9) / 3;
> +        gaq_ungroup_tab[i][2] = i % 3;
> +    }

i guess theres no way to factorize this and b1_mantissas related code without
loosing speed?


[...]
> @@ -496,6 +496,20 @@ static void get_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, mant_grou
>      }
>  }
>  
> +static void get_transform_coeffs_ch(AC3DecodeContext *s, int blk, int ch,
> +                                    mant_groups *m)
> +{

> +    if (!s->eac3 || !s->channel_uses_aht[ch]) {
> +        ac3_get_transform_coeffs_ch(s, ch, m);
> +    } else if (s->channel_uses_aht[ch] == 1) {
> +        ff_eac3_get_transform_coeffs_aht_ch(s, ch);
> +        s->channel_uses_aht[ch] = -1; /* AHT info for this frame has been read - do not read again */
> +    }
> +    if (s->eac3 && s->channel_uses_aht[ch]) {
> +        ff_eac3_idct_transform_coeffs_ch(s, ch, blk);
> +    }

if (s->channel_uses_aht[ch]) {
    if (s->channel_uses_aht[ch] == 1){
        ff_eac3_get_transform_coeffs_aht_ch(s, ch);
        s->channel_uses_aht[ch] = -1; /* AHT info for this frame has been read - do not read again */
    }
    ff_eac3_idct_transform_coeffs_ch(s, ch, blk);
}else
    ac3_get_transform_coeffs_ch(s, ch, m);

And i assume something like blk==0 isnt valid to avoid the 
s->channel_uses_aht[ch] = -1
?

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

Why not whip the teacher when the pupil misbehaves? -- Diogenes of Sinope
-------------- 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/20080617/957ca731/attachment.pgp>



More information about the ffmpeg-devel mailing list