[FFmpeg-devel] [PATCH] E-AC-3 decoder, round 3

Michael Niedermayer michaelni
Wed Aug 20 15:28:55 CEST 2008


On Tue, Aug 19, 2008 at 09:16:24PM -0400, Justin Ruggles wrote:
> Michael Niedermayer wrote:
> > On Tue, Aug 19, 2008 at 07:43:31PM -0400, Justin Ruggles wrote:
> >> Michael Niedermayer wrote:
> >>> On Tue, Aug 19, 2008 at 06:54:35PM -0400, Justin Ruggles wrote:
> >>>> Hi,
> >>>>
> >>>> Thanks for the review.
> >>>>
> >>>> Michael Niedermayer wrote:
> >>>>> On Sun, Aug 17, 2008 at 07:30:26PM -0400, Justin Ruggles wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> Here is a new patch to complete support for E-AC-3 decoding within the
> >>>>>> current AC-3 decoder.  It will be followed up by a cosmetic commit to
> >>>>>> indent and align.
> >>>>>>
> >>>>>> -Justin
> >>>>>>
> >>>>> [...]
> >>>>>> @@ -533,10 +547,27 @@
> >>>>>>      }
> >>>>>>  }
> >>>>>>  
> >>>>>> +static void get_transform_coeffs_ch(AC3DecodeContext *s, int blk, int ch,
> >>>>>> +                                    mant_groups *m)
> >>>>>> +{
> >>>>>> +    if (!s->channel_uses_aht[ch]) {
> >>>>>> +        ac3_get_transform_coeffs_ch(s, ch, m);
> >>>>>> +    } else {
> >>>>>> +        /* if AHT is used, mantissas for all blocks are encoded in the first
> >>>>>> +           block of the frame. */
> >>>>>> +        int bin;
> >>>>>> +        if (!blk)
> >>>>>> +            ff_eac3_get_transform_coeffs_aht_ch(s, ch);
> >>>>> am i blind? or where is this function, i cannot find it in this patch
> >>>>> nor in svn
> >>>> oops! I forgot to svn add eac3dec.c.  I have attached the whole file
> >>>> here.  It would be applied in the same commit with the rest of these
> >>>> changes (minus the part you said to commit separately).
> >>> does any of the changes i ok-ed depend on eac3dec.c ?
> >>> if not you could commit them and resubmit what is left + eac3dec.c
> >> Well, sort of.  I could apply all the parts OKed so far, but I would
> >> have to comment out the 2 calls to functions which are in eac3dec.c and
> >> leave out the part which actually detects the frame as being E-AC-3.
> > 
> > fine
> > every part commited moves us a step closer to full EAC3 support
> 
> done. new patch attached.
> 
> 

> Index: libavcodec/ac3dec.c
> ===================================================================
> --- libavcodec/ac3dec.c	(revision 14863)
> +++ libavcodec/ac3dec.c	(working copy)
[...]

> @@ -761,9 +758,23 @@
>          }
>      } while(i--);
>  
> +    /* spectral extension strategy */
> +    if (s->eac3 && (!blk || get_bits1(gbc))) {
> +        if (get_bits1(gbc)) {
> +            av_log_missing_feature(s->avctx, "Spectral extension", 1);
> +            return -1;
> +        }
> +        /* TODO: parse spectral extension strategy info */
> +    }
> +
> +    /* TODO: spectral extension coordinates */
> +

ok


>      /* coupling strategy */
> -    if (get_bits1(gbc)) {
> +    if (!s->eac3)
> +        s->cpl_strategy_exists[blk] = get_bits1(gbc);
> +    if (s->cpl_strategy_exists[blk]) {

wouldnt 
if(s->cpl_strategy_exists[blk] || get_bits1(gbc)){

work as well?


>          memset(bit_alloc_stages, 3, AC3_MAX_CHANNELS);
> +        if (!s->eac3)
>          s->cpl_in_use[blk] = get_bits1(gbc);
>          if (s->cpl_in_use[blk]) {
>              /* coupling in use */

ugly but i see no other way so its ok


> @@ -774,15 +785,28 @@
>                  return -1;
>              }
>  
> +            /* check for enhanced coupling */
> +            if (s->eac3 && get_bits1(gbc)) {
> +                /* TODO: parse enhanced coupling strategy info */
> +                av_log_missing_feature(s->avctx, "Enhanced coupling", 1);
> +                return -1;
> +            }
> +
>              /* determine which channels are coupled */
> +            if (s->eac3 && s->channel_mode == AC3_CHMODE_STEREO) {
> +                s->channel_in_cpl[1] = 1;
> +                s->channel_in_cpl[2] = 1;
> +            } else {
>              for (ch = 1; ch <= fbw_channels; ch++)
>                  s->channel_in_cpl[ch] = get_bits1(gbc);
> +            }
>  
>              /* phase flags in use */
>              if (channel_mode == AC3_CHMODE_STEREO)
>                  s->phase_flags_in_use = get_bits1(gbc);
>  
> -            /* coupling frequency range and band structure */
> +            /* coupling frequency range */
> +            /* TODO: modify coupling end freq if spectral extension is used */
>              cpl_begin_freq = get_bits(gbc, 4);
>              cpl_end_freq = get_bits(gbc, 4);
>              if (3 + cpl_end_freq - cpl_begin_freq < 0) {
> @@ -792,24 +816,40 @@
>              s->num_cpl_bands = s->num_cpl_subbands = 3 + cpl_end_freq - cpl_begin_freq;
>              s->start_freq[CPL_CH] = cpl_begin_freq * 12 + 37;
>              s->end_freq[CPL_CH] = cpl_end_freq * 12 + 73;
> +
> +            /* coupling band structure */
> +            if (!s->eac3 || get_bits1(gbc)) {
>              for (bnd = 0; bnd < s->num_cpl_subbands - 1; bnd++) {
> -                if (get_bits1(gbc)) {
> -                    s->cpl_band_struct[bnd] = 1;
> -                    s->num_cpl_bands--;
> +                    s->cpl_band_struct[bnd] = get_bits1(gbc);
>                  }
> +            } else if (!blk) {

ok

> +                for (bnd = 0; bnd < s->num_cpl_subbands - 1; bnd++) {
> +                    s->cpl_band_struct[bnd] = ff_eac3_default_cpl_band_struct[bnd+cpl_begin_freq+1];
> +                }

memcpy


>              }
>              s->cpl_band_struct[s->num_cpl_subbands-1] = 0;
> +
> +            /* calculate number of coupling bands based on band structure */
> +            for (bnd = 0; bnd < s->num_cpl_subbands-1; bnd++) {
> +                s->num_cpl_bands -= s->cpl_band_struct[bnd];
> +            }
>          } else {
>              /* coupling not in use */
> -            for (ch = 1; ch <= fbw_channels; ch++)
> +            for (ch = 1; ch <= fbw_channels; ch++) {
>                  s->channel_in_cpl[ch] = 0;
> +                s->first_cpl_coords[ch] = 1;
> +            }
> +            s->first_cpl_leak = 1;
> +            s->phase_flags_in_use = 0;
>          }
> -    } else if (!blk) {
> +    } else if (!s->eac3) {
> +        if(!blk) {
>          av_log(s->avctx, AV_LOG_ERROR, "new coupling strategy must be present in block 0\n");
>          return -1;
>      } else {
>          s->cpl_in_use[blk] = s->cpl_in_use[blk-1];
>      }
> +    }
>      cpl_in_use = s->cpl_in_use[blk];
>  
>      /* coupling coordinates */

ok



[...]

> @@ -847,7 +900,7 @@
>  
>      /* stereo rematrixing strategy and band structure */
>      if (channel_mode == AC3_CHMODE_STEREO) {
> -        if (get_bits1(gbc)) {
> +        if ((s->eac3 && !blk) || get_bits1(gbc)) {
>              s->num_rematrixing_bands = 4;
>              if(cpl_in_use && s->start_freq[CPL_CH] <= 61)
>                  s->num_rematrixing_bands -= 1 + (s->start_freq[CPL_CH] == 37);

ok


> @@ -860,10 +913,14 @@
>      }
>  
>      /* exponent strategies for each channel */
> -    s->exp_strategy[blk][CPL_CH] = EXP_REUSE;
> -    s->exp_strategy[blk][s->lfe_ch] = EXP_REUSE;

> +    if (!s->eac3) {
> +        for (ch = !cpl_in_use; ch <= s->channels; ch++) {
> +            s->exp_strategy[blk][ch] = get_bits(gbc, 2 - (ch == s->lfe_ch));
> +        }
> +    }
> +
> +    /* check exponent strategies to set bit allocation stages */
>      for (ch = !cpl_in_use; ch <= s->channels; ch++) {
> -        s->exp_strategy[blk][ch] = get_bits(gbc, 2 - (ch == s->lfe_ch));
>          if(s->exp_strategy[blk][ch] != EXP_REUSE)

why is that loop seperated? wouldnt a 
if (!s->eac3) in there work as well?


>              bit_alloc_stages[ch] = 3;
>      }
> @@ -890,7 +947,7 @@
>                  memset(bit_alloc_stages, 3, AC3_MAX_CHANNELS);
>          }
>      }
> -    if (cpl_in_use && s->exp_strategy[blk][CPL_CH] != EXP_REUSE) {
> +    if (cpl_in_use) {
>          s->num_exp_groups[CPL_CH] = (s->end_freq[CPL_CH] - s->start_freq[CPL_CH]) /
>                                      (3 << (s->exp_strategy[blk][CPL_CH] - 1));
>      }

ok


> @@ -924,29 +981,71 @@
>      }
>  
>      /* signal-to-noise ratio offsets and fast gains (signal-to-mask ratios) */


> -    if (get_bits1(gbc)) {
> +    if (s->snr_offset_strategy && (!s->eac3 || !blk) && get_bits1(gbc)) {
> +        int snr = 0;
>          int csnr;
>          csnr = (get_bits(gbc, 6) - 15) << 4;
> -        for (ch = !cpl_in_use; ch <= s->channels; ch++) { /* snr offset and fast gain */
> -            s->snr_offset[ch] = (csnr + get_bits(gbc, 4)) << 2;

> -            s->fast_gain[ch] = ff_ac3_fast_gain_tab[get_bits(gbc, 3)];
[...]
> +                s->fast_gain[ch] = ff_ac3_fast_gain_tab[get_bits(gbc, 3)];

cosmtic


> +                /* run last 2 bit allocation stages if fast gain changes */
> +                if(blk && prev != s->fast_gain[ch])
> +                    bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2);
> +            }
>          }
> -        memset(bit_alloc_stages, 3, AC3_MAX_CHANNELS);
> -    } else if (!blk) {
> +    } else if (!s->eac3 && !blk) {
>          av_log(s->avctx, AV_LOG_ERROR, "new snr offsets must be present in block 0\n");
>          return -1;
>      }

i was thinking a little about:

if(!s->eac3 || !blk){
    if (s->snr_offset_strategy && get_bits1(gbc)) {
    } else if(!s->eac3 && !blk){
    }
}

but iam not sure at all if its cleaner or not, just a random idea


>  
> +    /* fast gain (E-AC-3 only) */
> +    if (s->fast_gain_syntax && get_bits1(gbc)) {
> +        for (ch = !cpl_in_use; ch <= s->channels; ch++) {
> +            int prev = s->fast_gain[ch];
> +            s->fast_gain[ch] = ff_ac3_fast_gain_tab[get_bits(gbc, 3)];
> +            /* run last 2 bit allocation stages if fast gain changes */
> +            if(blk && prev != s->fast_gain[ch])
> +                bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2);
> +        }
> +    } else if (s->eac3 && !blk) {
> +        for (ch = !cpl_in_use; ch <= s->channels; ch++)
> +            s->fast_gain[ch] = ff_ac3_fast_gain_tab[4];
> +    }


> +
> +    /* E-AC-3 to AC-3 converter SNR offset */
> +    if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && get_bits1(gbc)) {
> +        skip_bits(gbc, 10); // skip converter snr offset
> +    }
> +

ok


>      /* coupling leak information */
>      if (cpl_in_use) {
> -        if (get_bits1(gbc)) {
> +        if (s->first_cpl_leak || get_bits1(gbc)) {

> +            int prev_fl = s->bit_alloc_params.cpl_fast_leak;
> +            int prev_sl = s->bit_alloc_params.cpl_slow_leak;
>              s->bit_alloc_params.cpl_fast_leak = get_bits(gbc, 3);
>              s->bit_alloc_params.cpl_slow_leak = get_bits(gbc, 3);
> +            /* run last 2 bit allocation stages for coupling channel if
> +               coupling leak changes */

> +            if(blk && (prev_fl != s->bit_alloc_params.cpl_fast_leak ||
> +                    prev_sl != s->bit_alloc_params.cpl_slow_leak)) {
>              bit_alloc_stages[CPL_CH] = FFMAX(bit_alloc_stages[CPL_CH], 2);
> +            }

i think following is cleaner

int fl= get_bits(gbc, 3);
int sl= get_bits(gbc, 3);

if(blk && (fl != s->bit_alloc_params.cpl_fast_leak ||
           sl != s->bit_alloc_params.cpl_slow_leak)) {
    bit_alloc_stages[CPL_CH] = FFMAX(bit_alloc_stages[CPL_CH], 2);
}
s->bit_alloc_params.cpl_fast_leak = fl;
s->bit_alloc_params.cpl_slow_leak = sl;



[...]
> Index: libavcodec/eac3dec.c
> ===================================================================
> --- libavcodec/eac3dec.c	(revision 0)
> +++ libavcodec/eac3dec.c	(revision 0)
> @@ -0,0 +1,482 @@
> +/*
> + * E-AC-3 decoder
> + * Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec at gmail.com>
> + * Copyright (c) 2008 Justin Ruggles
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "avcodec.h"
> +#include "ac3.h"
> +#include "ac3_parser.h"
> +#include "ac3dec.h"
> +#include "ac3dec_data.h"
> +
> +/** 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
> +
> +/** lrint(M_SQRT2*cos(2*M_PI/12)*(1<<23)) */
> +#define COEFF_0 10273905LL
> +
> +/** lrint(M_SQRT2*cos(0*M_PI/12)*(1<<23)) = lrint(M_SQRT2*(1<<23)) */
> +#define COEFF_1 11863283LL
> +
> +/** lrint(M_SQRT2*cos(5*M_PI/12)*(1<<23)) */
> +#define COEFF_2  3070444LL
> +
> +/**
> + * Calculate 6-point IDCT of the pre-mantissas.
> + * All calculations are 24-bit fixed-point.
> + */
> +static void idct6(int pre_mant[6])
> +{
> +    int tmp;
> +    int even0, even1, even2, odd0, odd1, odd2;
> +
> +    odd1 = pre_mant[1] - pre_mant[3] - pre_mant[5];
> +
> +    even2 = ( pre_mant[2]                * COEFF_0) >> 23;
> +    tmp   = ( pre_mant[4]                * COEFF_1) >> 23;
> +    odd0  = ((pre_mant[1] + pre_mant[5]) * COEFF_2) >> 23;
> +
> +    even0 = pre_mant[0] + (tmp >> 1);
> +    even1 = pre_mant[0] - tmp;
> +
> +    tmp = even0;
> +    even0 = tmp + even2;
> +    even2 = tmp - even2;
> +
> +    tmp = odd0;
> +    odd0 = tmp + pre_mant[1] + pre_mant[3];
> +    odd2 = tmp + pre_mant[5] - pre_mant[3];
> +
> +    pre_mant[0] = even0 + odd0;
> +    pre_mant[1] = even1 + odd1;
> +    pre_mant[2] = even2 + odd2;
> +    pre_mant[3] = even2 - odd2;
> +    pre_mant[4] = even1 - odd1;
> +    pre_mant[5] = even0 - odd0;
> +}

ok


> +
> +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 */
> +    gs = 0;
> +    if (gaq_mode == EAC3_GAQ_12 || gaq_mode == EAC3_GAQ_14) {
> +        /* read 1-bit GAQ gain codes */
> +        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;
> +        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++] = ff_ac3_ungroup_3_in_5_bits_tab[group_gain][0];
> +                    gaq_gain[gs++] = ff_ac3_ungroup_3_in_5_bits_tab[group_gain][1];
> +                    gaq_gain[gs++] = ff_ac3_ungroup_3_in_5_bits_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) {
> +            /* zero-mantissa dithering */
> +            for (blk = 0; blk < 6; blk++) {
> +                s->pre_mantissa[ch][bin][blk] = (av_lfg_get(&s->dith_state) & 0x7FFFFF) - 0x400000;
> +            }
> +        } else if (hebap < 8) {
> +            /* Vector Quantization */
> +            int v = get_bits(gbc, bits);
> +            for (blk = 0; blk < 6; blk++) {
> +                s->pre_mantissa[ch][bin][blk] = 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;

this is maybe missing a check for gbits<=0, iam not certain it can happen
but i think it can


> +
> +            for (blk = 0; blk < 6; blk++) {
> +                int mant = get_sbits(gbc, gbits);
> +                if (mant == -(1 << (gbits-1))) {
> +                    /* large mantissa */
> +                    int64_t b;
> +                    mant = get_sbits(gbc, bits-2+log_gain) << (26-log_gain-bits);
> +                    /* remap mantissa value to correct for asymmetric quantization */
> +                    if (mant >= 0)
> +                        b = 32768 >> log_gain;
> +                    else
> +                        b = ff_eac3_gaq_remap_2_4_b[hebap-8][log_gain-1];
> +                    mant += ((int64_t)ff_eac3_gaq_remap_2_4_a[hebap-8][log_gain-1] * mant + b) >> 15;

this can be done without a 64 bit multiple i think


> +                } else {
> +                    /* small mantissa, no GAQ, or Gk=1 */
> +                    mant <<= 24 - bits;
> +                    if (!log_gain) {
> +                        /* remap mantissa value for no GAQ or Gk=1 */
> +                        mant += ((int64_t)ff_eac3_gaq_remap_1[hebap-8] * mant) >> 15;
> +                    }

mant <<= 24 - bits;
if (!log_gain) {
    /* remap mantissa value for no GAQ or Gk=1 */
    mant = (ff_eac3_gaq_remap_1[hebap-8] * (mant>>8)) >> 7;
}



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

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

Breaking DRM is a little like attempting to break through a door even
though the window is wide open and the only thing in the house is a bunch
of things you dont want and which you would get tomorrow for free anyway
-------------- 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/20080820/73a27656/attachment.pgp>



More information about the ffmpeg-devel mailing list