[FFmpeg-devel] [PATCH] atrac decoder
Benjamin Larsson
banan
Mon Aug 10 23:10:40 CEST 2009
Michael Niedermayer wrote:
> 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
>
Fixed.
>
> [...]
>> +static DSPContext dsp;
>
> hmmm, if my memory doesnt fail then dsp cant be saftely used like this
>
Fixed.
>
> [...]
>> +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 ...
>
Would be possible if there where no short blocks. The logic to untangle
those are not worth it.
>
>> +
>> + ff_imdct_calc(mdct_context,out,spec);
>
> cant imdct_half be used?
>
Changed to
memset
fmul
fmul_rev
memset
It was slightly faster and uses less memory.
>
> [...]
>> +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
Fixed.
>
> [...]
>> +
>> +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
I think I understood this one time, now I just don't see how that could
be done.
>
> [...]
>> +
>> +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?
Fixed.
>
>
>> +
>> + 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
>
Fixed.
>
> [...]
>> + /* 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
>
Fixed.
I hope this is in a state so I can start merging the code. How should I
split out the code shared by atrac3 ? svn copy or just move the needed
code, it is just one function (iqmf)) and a table.
MvH
Benjamin Larsson
-------------- next part --------------
A non-text attachment was scrubbed...
Name: atrac.diff
Type: text/x-patch
Size: 19313 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090810/67c11efc/attachment.bin>
More information about the ffmpeg-devel
mailing list