yading@10: /* yading@10: * AC-3 DSP utils yading@10: * Copyright (c) 2011 Justin Ruggles yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "libavutil/avassert.h" yading@10: #include "avcodec.h" yading@10: #include "ac3.h" yading@10: #include "ac3dsp.h" yading@10: #include "mathops.h" yading@10: yading@10: static void ac3_exponent_min_c(uint8_t *exp, int num_reuse_blocks, int nb_coefs) yading@10: { yading@10: int blk, i; yading@10: yading@10: if (!num_reuse_blocks) yading@10: return; yading@10: yading@10: for (i = 0; i < nb_coefs; i++) { yading@10: uint8_t min_exp = *exp; yading@10: uint8_t *exp1 = exp + 256; yading@10: for (blk = 0; blk < num_reuse_blocks; blk++) { yading@10: uint8_t next_exp = *exp1; yading@10: if (next_exp < min_exp) yading@10: min_exp = next_exp; yading@10: exp1 += 256; yading@10: } yading@10: *exp++ = min_exp; yading@10: } yading@10: } yading@10: yading@10: static int ac3_max_msb_abs_int16_c(const int16_t *src, int len) yading@10: { yading@10: int i, v = 0; yading@10: for (i = 0; i < len; i++) yading@10: v |= abs(src[i]); yading@10: return v; yading@10: } yading@10: yading@10: static void ac3_lshift_int16_c(int16_t *src, unsigned int len, yading@10: unsigned int shift) yading@10: { yading@10: uint32_t *src32 = (uint32_t *)src; yading@10: const uint32_t mask = ~(((1 << shift) - 1) << 16); yading@10: int i; yading@10: len >>= 1; yading@10: for (i = 0; i < len; i += 8) { yading@10: src32[i ] = (src32[i ] << shift) & mask; yading@10: src32[i+1] = (src32[i+1] << shift) & mask; yading@10: src32[i+2] = (src32[i+2] << shift) & mask; yading@10: src32[i+3] = (src32[i+3] << shift) & mask; yading@10: src32[i+4] = (src32[i+4] << shift) & mask; yading@10: src32[i+5] = (src32[i+5] << shift) & mask; yading@10: src32[i+6] = (src32[i+6] << shift) & mask; yading@10: src32[i+7] = (src32[i+7] << shift) & mask; yading@10: } yading@10: } yading@10: yading@10: static void ac3_rshift_int32_c(int32_t *src, unsigned int len, yading@10: unsigned int shift) yading@10: { yading@10: do { yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: *src++ >>= shift; yading@10: len -= 8; yading@10: } while (len > 0); yading@10: } yading@10: yading@10: static void float_to_fixed24_c(int32_t *dst, const float *src, unsigned int len) yading@10: { yading@10: const float scale = 1 << 24; yading@10: do { yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: *dst++ = lrintf(*src++ * scale); yading@10: len -= 8; yading@10: } while (len > 0); yading@10: } yading@10: yading@10: static void ac3_bit_alloc_calc_bap_c(int16_t *mask, int16_t *psd, yading@10: int start, int end, yading@10: int snr_offset, int floor, yading@10: const uint8_t *bap_tab, uint8_t *bap) yading@10: { yading@10: int bin, band, band_end; yading@10: yading@10: /* special case, if snr offset is -960, set all bap's to zero */ yading@10: if (snr_offset == -960) { yading@10: memset(bap, 0, AC3_MAX_COEFS); yading@10: return; yading@10: } yading@10: yading@10: bin = start; yading@10: band = ff_ac3_bin_to_band_tab[start]; yading@10: do { yading@10: int m = (FFMAX(mask[band] - snr_offset - floor, 0) & 0x1FE0) + floor; yading@10: band_end = ff_ac3_band_start_tab[++band]; yading@10: band_end = FFMIN(band_end, end); yading@10: yading@10: for (; bin < band_end; bin++) { yading@10: int address = av_clip((psd[bin] - m) >> 5, 0, 63); yading@10: bap[bin] = bap_tab[address]; yading@10: } yading@10: } while (end > band_end); yading@10: } yading@10: yading@10: static void ac3_update_bap_counts_c(uint16_t mant_cnt[16], uint8_t *bap, yading@10: int len) yading@10: { yading@10: while (len-- > 0) yading@10: mant_cnt[bap[len]]++; yading@10: } yading@10: yading@10: DECLARE_ALIGNED(16, const uint16_t, ff_ac3_bap_bits)[16] = { yading@10: 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 yading@10: }; yading@10: yading@10: static int ac3_compute_mantissa_size_c(uint16_t mant_cnt[6][16]) yading@10: { yading@10: int blk, bap; yading@10: int bits = 0; yading@10: yading@10: for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) { yading@10: // bap=1 : 3 mantissas in 5 bits yading@10: bits += (mant_cnt[blk][1] / 3) * 5; yading@10: // bap=2 : 3 mantissas in 7 bits yading@10: // bap=4 : 2 mantissas in 7 bits yading@10: bits += ((mant_cnt[blk][2] / 3) + (mant_cnt[blk][4] >> 1)) * 7; yading@10: // bap=3 : 1 mantissa in 3 bits yading@10: bits += mant_cnt[blk][3] * 3; yading@10: // bap=5 to 15 : get bits per mantissa from table yading@10: for (bap = 5; bap < 16; bap++) yading@10: bits += mant_cnt[blk][bap] * ff_ac3_bap_bits[bap]; yading@10: } yading@10: return bits; yading@10: } yading@10: yading@10: static void ac3_extract_exponents_c(uint8_t *exp, int32_t *coef, int nb_coefs) yading@10: { yading@10: int i; yading@10: yading@10: for (i = 0; i < nb_coefs; i++) { yading@10: int v = abs(coef[i]); yading@10: exp[i] = v ? 23 - av_log2(v) : 24; yading@10: } yading@10: } yading@10: yading@10: static void ac3_sum_square_butterfly_int32_c(int64_t sum[4], yading@10: const int32_t *coef0, yading@10: const int32_t *coef1, yading@10: int len) yading@10: { yading@10: int i; yading@10: yading@10: sum[0] = sum[1] = sum[2] = sum[3] = 0; yading@10: yading@10: for (i = 0; i < len; i++) { yading@10: int lt = coef0[i]; yading@10: int rt = coef1[i]; yading@10: int md = lt + rt; yading@10: int sd = lt - rt; yading@10: MAC64(sum[0], lt, lt); yading@10: MAC64(sum[1], rt, rt); yading@10: MAC64(sum[2], md, md); yading@10: MAC64(sum[3], sd, sd); yading@10: } yading@10: } yading@10: yading@10: static void ac3_sum_square_butterfly_float_c(float sum[4], yading@10: const float *coef0, yading@10: const float *coef1, yading@10: int len) yading@10: { yading@10: int i; yading@10: yading@10: sum[0] = sum[1] = sum[2] = sum[3] = 0; yading@10: yading@10: for (i = 0; i < len; i++) { yading@10: float lt = coef0[i]; yading@10: float rt = coef1[i]; yading@10: float md = lt + rt; yading@10: float sd = lt - rt; yading@10: sum[0] += lt * lt; yading@10: sum[1] += rt * rt; yading@10: sum[2] += md * md; yading@10: sum[3] += sd * sd; yading@10: } yading@10: } yading@10: yading@10: static void ac3_downmix_c(float **samples, float (*matrix)[2], yading@10: int out_ch, int in_ch, int len) yading@10: { yading@10: int i, j; yading@10: float v0, v1; yading@10: if (out_ch == 2) { yading@10: for (i = 0; i < len; i++) { yading@10: v0 = v1 = 0.0f; yading@10: for (j = 0; j < in_ch; j++) { yading@10: v0 += samples[j][i] * matrix[j][0]; yading@10: v1 += samples[j][i] * matrix[j][1]; yading@10: } yading@10: samples[0][i] = v0; yading@10: samples[1][i] = v1; yading@10: } yading@10: } else if (out_ch == 1) { yading@10: for (i = 0; i < len; i++) { yading@10: v0 = 0.0f; yading@10: for (j = 0; j < in_ch; j++) yading@10: v0 += samples[j][i] * matrix[j][0]; yading@10: samples[0][i] = v0; yading@10: } yading@10: } yading@10: } yading@10: yading@10: av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact) yading@10: { yading@10: c->ac3_exponent_min = ac3_exponent_min_c; yading@10: c->ac3_max_msb_abs_int16 = ac3_max_msb_abs_int16_c; yading@10: c->ac3_lshift_int16 = ac3_lshift_int16_c; yading@10: c->ac3_rshift_int32 = ac3_rshift_int32_c; yading@10: c->float_to_fixed24 = float_to_fixed24_c; yading@10: c->bit_alloc_calc_bap = ac3_bit_alloc_calc_bap_c; yading@10: c->update_bap_counts = ac3_update_bap_counts_c; yading@10: c->compute_mantissa_size = ac3_compute_mantissa_size_c; yading@10: c->extract_exponents = ac3_extract_exponents_c; yading@10: c->sum_square_butterfly_int32 = ac3_sum_square_butterfly_int32_c; yading@10: c->sum_square_butterfly_float = ac3_sum_square_butterfly_float_c; yading@10: c->downmix = ac3_downmix_c; yading@10: yading@10: if (ARCH_ARM) yading@10: ff_ac3dsp_init_arm(c, bit_exact); yading@10: if (ARCH_X86) yading@10: ff_ac3dsp_init_x86(c, bit_exact); yading@10: if (ARCH_MIPS) yading@10: ff_ac3dsp_init_mips(c, bit_exact); yading@10: }