[FFmpeg-devel] [PATCH] atrac decoder

Michael Niedermayer michaelni
Tue Jun 9 02:13:44 CEST 2009


On Mon, Jun 08, 2009 at 09:40:18PM +0200, Benjamin Larsson wrote:
> Hi, this is working decoder for atrac. The things I have commented in
> the code will be moved to a common file when the code is in shape for
> inclusion. I left them there if people feel the urge to try the decoder.
> 
> I will upload some sample files to the samples archive.
> 
> MvH
> Benjamin Larsson

>  Makefile     |    1 
>  allcodecs.c  |    1 
>  atrac1.c     |  458 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  atrac1data.h |   66 ++++++++
>  avcodec.h    |    1 
>  5 files changed, 527 insertions(+)
> 3a09d49c0308500f877d64526e34ab191372c6af  atrac1.diff
> Index: libavcodec/atrac1data.h
> ===================================================================
> --- libavcodec/atrac1data.h	(revision 0)
> +++ libavcodec/atrac1data.h	(revision 0)
> @@ -0,0 +1,66 @@
> +/*
> + * Atrac 1 compatible decoder data
> + * Copyright (c) 2009 Maxim Poliakovski
> + * Copyright (c) 2009 Benjamin Larsson
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser 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
> + */
> +
> +/**
> + * @file libavcodec/atrac1data.h
> + * Atrac 1 compatible decoder data.
> + */
> +
> +static const uint8_t bfu_amount_tab1[8]  = {20, 28, 32, 36, 40, 44, 48, 52};
> +static const uint8_t bfu_amount_tab2[4]  = { 0, 28, 44, 52};
> +static const uint8_t bfu_amount_tab3[8]  = { 0,  8, 12, 16, 24, 36, 44, 52};
> +
> +static const uint8_t bfu_bands_t[4]  = {0, 20, 36, 52}; // number of BFUs in each QMF band
> +

> +/* idwl to wordlen translation table */
> +static const uint8_t idwl2wordlen[16]= {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

doxy


[...]
> +static DSPContext       dsp;

hmmm, if my memory doesnt fail then dsp cant be saftely used like this


[...]
> +static void at1_imdct_transform(ATRAC1Context *q, float *spec, float *out, int nbits, int reverse_spectrum)
> +{
> +    float* window;
> +    MDCTContext* mdct_context;
> +    int transf_size = 1 << nbits;
> +
> +    switch(nbits) {
> +        case 5:
> +            window = short_window;
> +            mdct_context = &q->mdct_ctx[0];
> +            break;
> +        case 7:
> +            window = mid_window;
> +            mdct_context = &q->mdct_ctx[1];
> +            break;
> +        case 8:
> +        default:
> +            window = long_window;
> +            mdct_context = &q->mdct_ctx[2];
> +    }
> +

> +    if (reverse_spectrum) {
> +        int i;
> +        for (i=0; i<transf_size/2; i++)
> +            FFSWAP(float, spec[i], spec[transf_size-1-i]);
> +    }

i think that can be avoided by decong in reverse order ...


> +
> +    ff_imdct_calc(mdct_context,out,spec);

cant imdct_half be used?


[...]
> +static int at1_parse_block_size_mode(GetBitContext* gb, int bsm[AT1_QMF_BANDS])
> +{
> +    int bsm_tmp;
> +
> +    /* low band */
> +    bsm_tmp = get_bits(gb, 2);
> +    if (bsm_tmp != 0 && bsm_tmp != 2)
> +        return -1;
> +    bsm[IDX_LOW_BAND] = 2 - bsm_tmp;
> +
> +    /* middle band */
> +    bsm_tmp = get_bits(gb, 2);

> +    if (bsm_tmp != 0 && bsm_tmp != 2)
> +        return -1;

bsm_tmp&1

[...]
> +
> +static int at1_unpack_dequant(GetBitContext* gb, AT1SUContext* su, float spec[AT1_SU_SAMPLES])
> +{
> +    int bits_used, band_num, bfu_num, i;
> +
> +    /* parse the info byte (2nd byte) telling how much BFUs were coded */
> +    su->num_bfus = bfu_amount_tab1[get_bits(gb, 3)];
> +
> +    /* calc number of consumed bits:
> +        num_BFUs * (idwl(4bits) + idsf(6bits)) + bsm(8bits) + info_byte(8bits)
> +        + info_byte_copy(8bits) + bsm_copy(8bits) */
> +    bits_used = su->num_bfus * 10 + 32 +
> +                bfu_amount_tab2[get_bits(gb, 2)] * 4 +
> +                bfu_amount_tab3[get_bits(gb, 3)] * 6;
> +
> +    /* get word length index (idwl) for each BFU */
> +    for (i=0 ; i<su->num_bfus ; i++)
> +        su->idwls[i] = get_bits(gb, 4);
> +
> +    /* get scalefactor index (idsf) for each BFU */
> +    for (i=0 ; i<su->num_bfus ; i++)
> +        su->idsfs[i] = get_bits(gb, 6);
> +
> +    /* zero idwl/idsf for empty BFUs */
> +    for (i = su->num_bfus; i < AT1_MAX_BFU; i++)
> +        su->idwls[i] = su->idsfs[i] = 0;
> +
> +    /* read in the spectral data and reconstruct MDCT spectrum of this channel */
> +    for (band_num=0 ; band_num<AT1_QMF_BANDS ; band_num++) {
> +        for (bfu_num=bfu_bands_t[band_num] ; bfu_num<bfu_bands_t[band_num+1] ; bfu_num++) {
> +            int         pos;
> +
> +            int num_specs = specs_per_bfu[bfu_num];

> +            int word_len = idwl2wordlen[su->idwls[bfu_num]];

that remaping could be done outside the loops

[...]
> +
> +static int atrac1_decode_frame(AVCodecContext *avctx,
> +            void *data, int *data_size,
> +            AVPacket *avpkt)
> +{
> +    const uint8_t *buf = avpkt->data;
> +    int buf_size = avpkt->size;
> +    ATRAC1Context *q = avctx->priv_data;
> +    int ch, ret, i;
> +    int16_t* samples = data;
> +
> +//    if ((buf_size<212 && q->channels==1) || (buf_size<424 && q->channels==2))
> +//        return -1;
> +
> +    for (ch=0 ; ch<avctx->channels ; ch++) {
> +        AT1SUContext* su = &q->SUs[ch];
> +
> +        init_get_bits(&q->gb, &buf[212*ch], 212*8);
> +
> +        /* parse block_size_mode, 1st byte */
> +        ret = at1_parse_block_size_mode(&q->gb, su->bsm);
> +        if(ret)
> +            return ret;
> +
> +        ret = at1_unpack_dequant(&q->gb, su, q->spec);
> +        if(ret)
> +            return ret;
> +
> +        ret = at1_imdct(su, q);
> +        if(ret)
> +            return ret;
> +        at1_subband_synthesis(q, su, q->out_samples[ch]);
> +    }
> +
> +    /* round, convert to 16bit and interleave */
> +    if (q->channels == 1) {
> +        /* mono */
> +        for (i = 0; i<AT1_SU_SAMPLES; i++)
> +            samples[i] = av_clip_int16(round(q->out_samples[0][i]));
> +        *data_size = AT1_SU_SAMPLES * sizeof(int16_t);
> +    } else {
> +        /* stereo */
> +        for (i = 0; i < AT1_SU_SAMPLES; i++) {
> +            samples[i*2] = av_clip_int16(round(q->out_samples[0][i]));
> +            samples[i*2+1] = av_clip_int16(round(q->out_samples[1][i]));
> +        }
> +        *data_size = 2 * AT1_SU_SAMPLES * sizeof(int16_t);
> +    }

maybe this should retutn float instead of converting to 16bit?


> +
> +    return avctx->block_align;
> +}
> +
> +static av_cold void init_mdct_windows()
> +{
> +    int i;
> +    /* Generate the short window */
> +    ff_sine_window_init(short_window,32);
> +    for (i=0 ; i<32; i++)
> +        short_window[63-i] = short_window[i];
> +
> +    /** The mid and long windows uses the same sine window splitted
> +     *  in the middle and wrapped into zero/one regions as follows:
> +     *
> +     *                   region of "ones"
> +     *               ---------------------------
> +     *              /                           \
> +     *             / 1st half                    \ 2nd half
> +     *            / of the sine                   \ of the sine window
> +     *           /  window                         \
> +     * ---------/                                   \----------------
> +     * zero region                                      zero region
> +     */
> +
> +    /* Generate the mid window */
> +    memset(mid_window, 0, sizeof(mid_window));
> +    memcpy(&mid_window[48], short_window, sizeof(float) * 32);
> +    for (i = 0; i < 96; i++)
> +        mid_window[80 + i] = 1.0f;
> +    memcpy(&mid_window[176], &short_window[32], sizeof(float) * 32);
> +
> +    /* Generate the long window */
> +    memset(long_window, 0, sizeof(long_window));
> +    memcpy(&long_window[112], short_window, sizeof(float) * 32);
> +    for (i = 0; i < 224; i++)
> +        long_window[144 + i] = 1.0f;

please dont multiply by 1 or 0, its a waste of time


[...]
> +    /* Generate the QMF window. */
> +    for (i=0 ; i<24; i++) {
> +        float s;
> +        s = qmf_48tap_half[i] * 2.0;
> +        qmf_window[i] = s;
> +        qmf_window[47 - i] = s;
> +    }

the intermediate s is useless

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

The worst form of inequality is to try to make unequal things equal.
-- Aristotle
-------------- 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/20090609/a1a72c05/attachment.pgp>



More information about the ffmpeg-devel mailing list