[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