Mercurial > libavcodec.hg
view wma.c @ 10874:bcfe2acbf190 libavcodec
AAC: Compress codebook tables and optimise sign bit handling
The codebooks each consist of small number of values repeated in
groups of 2 or 4. Storing the codebooks as a packed list of 2- or
4-bit indexes into a table reduces their size substantially (from 7.5k
to 1.5k), resulting in less cache pressure.
For the band types with sign bits in the bitstream, storing the number
and position of non-zero codebook values using a few bits avoids
multiple get_bits() calls and floating-point comparisons which gcc
handles miserably.
Some float/int type punning also avoids gcc brain damage.
Overall speedup 20-35% on Cortex-A8, 20% on Core i7.
author | mru |
---|---|
date | Wed, 13 Jan 2010 16:46:28 +0000 |
parents | 3d011a01a6a0 |
children | c29ee479e359 |
line wrap: on
line source
/* * WMA compatible codec * Copyright (c) 2002-2007 The FFmpeg Project * * 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 */ #include "avcodec.h" #include "wma.h" #include "wmadata.h" #undef NDEBUG #include <assert.h> /* XXX: use same run/length optimization as mpeg decoders */ //FIXME maybe split decode / encode or pass flag static void init_coef_vlc(VLC *vlc, uint16_t **prun_table, float **plevel_table, uint16_t **pint_table, const CoefVLCTable *vlc_table) { int n = vlc_table->n; const uint8_t *table_bits = vlc_table->huffbits; const uint32_t *table_codes = vlc_table->huffcodes; const uint16_t *levels_table = vlc_table->levels; uint16_t *run_table, *level_table, *int_table; float *flevel_table; int i, l, j, k, level; init_vlc(vlc, VLCBITS, n, table_bits, 1, 1, table_codes, 4, 4, 0); run_table = av_malloc(n * sizeof(uint16_t)); level_table = av_malloc(n * sizeof(uint16_t)); flevel_table= av_malloc(n * sizeof(*flevel_table)); int_table = av_malloc(n * sizeof(uint16_t)); i = 2; level = 1; k = 0; while (i < n) { int_table[k] = i; l = levels_table[k++]; for (j = 0; j < l; j++) { run_table[i] = j; level_table[i] = level; flevel_table[i]= level; i++; } level++; } *prun_table = run_table; *plevel_table = flevel_table; *pint_table = int_table; av_free(level_table); } /** *@brief Get the samples per frame for this stream. *@param sample_rate output sample_rate *@param version wma version *@param decode_flags codec compression features *@return log2 of the number of output samples per frame */ int av_cold ff_wma_get_frame_len_bits(int sample_rate, int version, unsigned int decode_flags) { int frame_len_bits; if (sample_rate <= 16000) { frame_len_bits = 9; } else if (sample_rate <= 22050 || (sample_rate <= 32000 && version == 1)) { frame_len_bits = 10; } else if (sample_rate <= 48000) { frame_len_bits = 11; } else if (sample_rate <= 96000) { frame_len_bits = 12; } else { frame_len_bits = 13; } if (version == 3) { int tmp = decode_flags & 0x6; if (tmp == 0x2) { ++frame_len_bits; } else if (tmp == 0x4) { --frame_len_bits; } else if (tmp == 0x6) { frame_len_bits -= 2; } } return frame_len_bits; } int ff_wma_init(AVCodecContext *avctx, int flags2) { WMACodecContext *s = avctx->priv_data; int i; float bps1, high_freq; volatile float bps; int sample_rate1; int coef_vlc_table; if ( avctx->sample_rate <= 0 || avctx->sample_rate > 50000 || avctx->channels <= 0 || avctx->channels > 8 || avctx->bit_rate <= 0) return -1; s->sample_rate = avctx->sample_rate; s->nb_channels = avctx->channels; s->bit_rate = avctx->bit_rate; s->block_align = avctx->block_align; dsputil_init(&s->dsp, avctx); if (avctx->codec->id == CODEC_ID_WMAV1) { s->version = 1; } else { s->version = 2; } /* compute MDCT block size */ s->frame_len_bits = ff_wma_get_frame_len_bits(s->sample_rate, s->version, 0); s->frame_len = 1 << s->frame_len_bits; if (s->use_variable_block_len) { int nb_max, nb; nb = ((flags2 >> 3) & 3) + 1; if ((s->bit_rate / s->nb_channels) >= 32000) nb += 2; nb_max = s->frame_len_bits - BLOCK_MIN_BITS; if (nb > nb_max) nb = nb_max; s->nb_block_sizes = nb + 1; } else { s->nb_block_sizes = 1; } /* init rate dependent parameters */ s->use_noise_coding = 1; high_freq = s->sample_rate * 0.5; /* if version 2, then the rates are normalized */ sample_rate1 = s->sample_rate; if (s->version == 2) { if (sample_rate1 >= 44100) { sample_rate1 = 44100; } else if (sample_rate1 >= 22050) { sample_rate1 = 22050; } else if (sample_rate1 >= 16000) { sample_rate1 = 16000; } else if (sample_rate1 >= 11025) { sample_rate1 = 11025; } else if (sample_rate1 >= 8000) { sample_rate1 = 8000; } } bps = (float)s->bit_rate / (float)(s->nb_channels * s->sample_rate); s->byte_offset_bits = av_log2((int)(bps * s->frame_len / 8.0 + 0.5)) + 2; /* compute high frequency value and choose if noise coding should be activated */ bps1 = bps; if (s->nb_channels == 2) bps1 = bps * 1.6; if (sample_rate1 == 44100) { if (bps1 >= 0.61) { s->use_noise_coding = 0; } else { high_freq = high_freq * 0.4; } } else if (sample_rate1 == 22050) { if (bps1 >= 1.16) { s->use_noise_coding = 0; } else if (bps1 >= 0.72) { high_freq = high_freq * 0.7; } else { high_freq = high_freq * 0.6; } } else if (sample_rate1 == 16000) { if (bps > 0.5) { high_freq = high_freq * 0.5; } else { high_freq = high_freq * 0.3; } } else if (sample_rate1 == 11025) { high_freq = high_freq * 0.7; } else if (sample_rate1 == 8000) { if (bps <= 0.625) { high_freq = high_freq * 0.5; } else if (bps > 0.75) { s->use_noise_coding = 0; } else { high_freq = high_freq * 0.65; } } else { if (bps >= 0.8) { high_freq = high_freq * 0.75; } else if (bps >= 0.6) { high_freq = high_freq * 0.6; } else { high_freq = high_freq * 0.5; } } dprintf(s->avctx, "flags2=0x%x\n", flags2); dprintf(s->avctx, "version=%d channels=%d sample_rate=%d bitrate=%d block_align=%d\n", s->version, s->nb_channels, s->sample_rate, s->bit_rate, s->block_align); dprintf(s->avctx, "bps=%f bps1=%f high_freq=%f bitoffset=%d\n", bps, bps1, high_freq, s->byte_offset_bits); dprintf(s->avctx, "use_noise_coding=%d use_exp_vlc=%d nb_block_sizes=%d\n", s->use_noise_coding, s->use_exp_vlc, s->nb_block_sizes); /* compute the scale factor band sizes for each MDCT block size */ { int a, b, pos, lpos, k, block_len, i, j, n; const uint8_t *table; if (s->version == 1) { s->coefs_start = 3; } else { s->coefs_start = 0; } for (k = 0; k < s->nb_block_sizes; k++) { block_len = s->frame_len >> k; if (s->version == 1) { lpos = 0; for (i = 0; i < 25; i++) { a = wma_critical_freqs[i]; b = s->sample_rate; pos = ((block_len * 2 * a) + (b >> 1)) / b; if (pos > block_len) pos = block_len; s->exponent_bands[0][i] = pos - lpos; if (pos >= block_len) { i++; break; } lpos = pos; } s->exponent_sizes[0] = i; } else { /* hardcoded tables */ table = NULL; a = s->frame_len_bits - BLOCK_MIN_BITS - k; if (a < 3) { if (s->sample_rate >= 44100) { table = exponent_band_44100[a]; } else if (s->sample_rate >= 32000) { table = exponent_band_32000[a]; } else if (s->sample_rate >= 22050) { table = exponent_band_22050[a]; } } if (table) { n = *table++; for (i = 0; i < n; i++) s->exponent_bands[k][i] = table[i]; s->exponent_sizes[k] = n; } else { j = 0; lpos = 0; for (i = 0; i < 25; i++) { a = wma_critical_freqs[i]; b = s->sample_rate; pos = ((block_len * 2 * a) + (b << 1)) / (4 * b); pos <<= 2; if (pos > block_len) pos = block_len; if (pos > lpos) s->exponent_bands[k][j++] = pos - lpos; if (pos >= block_len) break; lpos = pos; } s->exponent_sizes[k] = j; } } /* max number of coefs */ s->coefs_end[k] = (s->frame_len - ((s->frame_len * 9) / 100)) >> k; /* high freq computation */ s->high_band_start[k] = (int)((block_len * 2 * high_freq) / s->sample_rate + 0.5); n = s->exponent_sizes[k]; j = 0; pos = 0; for (i = 0; i < n; i++) { int start, end; start = pos; pos += s->exponent_bands[k][i]; end = pos; if (start < s->high_band_start[k]) start = s->high_band_start[k]; if (end > s->coefs_end[k]) end = s->coefs_end[k]; if (end > start) s->exponent_high_bands[k][j++] = end - start; } s->exponent_high_sizes[k] = j; #if 0 tprintf(s->avctx, "%5d: coefs_end=%d high_band_start=%d nb_high_bands=%d: ", s->frame_len >> k, s->coefs_end[k], s->high_band_start[k], s->exponent_high_sizes[k]); for (j = 0; j < s->exponent_high_sizes[k]; j++) tprintf(s->avctx, " %d", s->exponent_high_bands[k][j]); tprintf(s->avctx, "\n"); #endif } } #ifdef TRACE { int i, j; for (i = 0; i < s->nb_block_sizes; i++) { tprintf(s->avctx, "%5d: n=%2d:", s->frame_len >> i, s->exponent_sizes[i]); for (j = 0; j < s->exponent_sizes[i]; j++) tprintf(s->avctx, " %d", s->exponent_bands[i][j]); tprintf(s->avctx, "\n"); } } #endif /* init MDCT windows : simple sinus window */ for (i = 0; i < s->nb_block_sizes; i++) { ff_init_ff_sine_windows(s->frame_len_bits - i); s->windows[i] = ff_sine_windows[s->frame_len_bits - i]; } s->reset_block_lengths = 1; if (s->use_noise_coding) { /* init the noise generator */ if (s->use_exp_vlc) { s->noise_mult = 0.02; } else { s->noise_mult = 0.04; } #ifdef TRACE for (i = 0; i < NOISE_TAB_SIZE; i++) s->noise_table[i] = 1.0 * s->noise_mult; #else { unsigned int seed; float norm; seed = 1; norm = (1.0 / (float)(1LL << 31)) * sqrt(3) * s->noise_mult; for (i = 0; i < NOISE_TAB_SIZE; i++) { seed = seed * 314159 + 1; s->noise_table[i] = (float)((int)seed) * norm; } } #endif } /* choose the VLC tables for the coefficients */ coef_vlc_table = 2; if (s->sample_rate >= 32000) { if (bps1 < 0.72) { coef_vlc_table = 0; } else if (bps1 < 1.16) { coef_vlc_table = 1; } } s->coef_vlcs[0]= &coef_vlcs[coef_vlc_table * 2 ]; s->coef_vlcs[1]= &coef_vlcs[coef_vlc_table * 2 + 1]; init_coef_vlc(&s->coef_vlc[0], &s->run_table[0], &s->level_table[0], &s->int_table[0], s->coef_vlcs[0]); init_coef_vlc(&s->coef_vlc[1], &s->run_table[1], &s->level_table[1], &s->int_table[1], s->coef_vlcs[1]); return 0; } int ff_wma_total_gain_to_bits(int total_gain) { if (total_gain < 15) return 13; else if (total_gain < 32) return 12; else if (total_gain < 40) return 11; else if (total_gain < 45) return 10; else return 9; } int ff_wma_end(AVCodecContext *avctx) { WMACodecContext *s = avctx->priv_data; int i; for (i = 0; i < s->nb_block_sizes; i++) ff_mdct_end(&s->mdct_ctx[i]); if (s->use_exp_vlc) { free_vlc(&s->exp_vlc); } if (s->use_noise_coding) { free_vlc(&s->hgain_vlc); } for (i = 0; i < 2; i++) { free_vlc(&s->coef_vlc[i]); av_free(s->run_table[i]); av_free(s->level_table[i]); av_free(s->int_table[i]); } return 0; } /** * Decode an uncompressed coefficient. * @param s codec context * @return the decoded coefficient */ unsigned int ff_wma_get_large_val(GetBitContext* gb) { /** consumes up to 34 bits */ int n_bits = 8; /** decode length */ if (get_bits1(gb)) { n_bits += 8; if (get_bits1(gb)) { n_bits += 8; if (get_bits1(gb)) { n_bits += 7; } } } return get_bits_long(gb, n_bits); } /** * Decode run level compressed coefficients. * @param avctx codec context * @param gb bitstream reader context * @param vlc vlc table for get_vlc2 * @param level_table level codes * @param run_table run codes * @param version 0 for wma1,2 1 for wmapro * @param ptr output buffer * @param offset offset in the output buffer * @param num_coefs number of input coefficents * @param block_len input buffer length (2^n) * @param frame_len_bits number of bits for escaped run codes * @param coef_nb_bits number of bits for escaped level codes * @return 0 on success, -1 otherwise */ int ff_wma_run_level_decode(AVCodecContext* avctx, GetBitContext* gb, VLC *vlc, const float *level_table, const uint16_t *run_table, int version, WMACoef *ptr, int offset, int num_coefs, int block_len, int frame_len_bits, int coef_nb_bits) { int code, level, sign; const uint32_t *ilvl = (const uint32_t*)level_table; uint32_t *iptr = (uint32_t*)ptr; const unsigned int coef_mask = block_len - 1; for (; offset < num_coefs; offset++) { code = get_vlc2(gb, vlc->table, VLCBITS, VLCMAX); if (code > 1) { /** normal code */ offset += run_table[code]; sign = get_bits1(gb) - 1; iptr[offset & coef_mask] = ilvl[code] ^ sign<<31; } else if (code == 1) { /** EOB */ break; } else { /** escape */ if (!version) { level = get_bits(gb, coef_nb_bits); /** NOTE: this is rather suboptimal. reading block_len_bits would be better */ offset += get_bits(gb, frame_len_bits); } else { level = ff_wma_get_large_val(gb); /** escape decode */ if (get_bits1(gb)) { if (get_bits1(gb)) { if (get_bits1(gb)) { av_log(avctx,AV_LOG_ERROR, "broken escape sequence\n"); return -1; } else offset += get_bits(gb, frame_len_bits) + 4; } else offset += get_bits(gb, 2) + 1; } } sign = get_bits1(gb) - 1; ptr[offset & coef_mask] = (level^sign) - sign; } } /** NOTE: EOB can be omitted */ if (offset > num_coefs) { av_log(avctx, AV_LOG_ERROR, "overflow in spectral RLE, ignoring\n"); return -1; } return 0; }