[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