[FFmpeg-devel] [PATCH] [UNFINISHED] libavcodec: Implementation of AC3 fixed point decoder.
Nedeljko Babic
nbabic at mips.com
Tue Sep 18 15:13:44 CEST 2012
AC3 fixed point decoder is based on AC3 floating point
decoder that is already part of FFmpeg.
Signed-off-by: Nedeljko Babic <nbabic at mips.com>
---
libavcodec/Makefile | 3 +-
libavcodec/ac3.h | 59 ++++++++++++
libavcodec/ac3dec.c | 221 +++++++++++++++++++++------------------------
libavcodec/ac3dec.h | 22 +++---
libavcodec/ac3dec_fixed.c | 167 ++++++++++++++++++++++++++++++++++
libavcodec/ac3dec_float.c | 105 +++++++++++++++++++++
libavcodec/ac3dsp.c | 26 ++++++
libavcodec/ac3dsp.h | 2 +
libavcodec/allcodecs.c | 1 +
libavcodec/dsputil.c | 19 ++++
libavcodec/dsputil.h | 1 +
libavcodec/fft-internal.h | 6 +-
libavcodec/fmtconvert.c | 72 +++++++++++++++
libavcodec/fmtconvert.h | 52 +++++++++++
libavcodec/kbdwin.c | 30 ++++++
libavcodec/kbdwin.h | 2 +-
libavutil/common.h | 10 ++
17 files changed, 664 insertions(+), 134 deletions(-)
create mode 100644 libavcodec/ac3dec_fixed.c
create mode 100644 libavcodec/ac3dec_float.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index dd881b6..44ec7b5 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -80,7 +80,8 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o \
mpeg4audio.o kbdwin.o \
audio_frame_queue.o
OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o
-OBJS-$(CONFIG_AC3_DECODER) += ac3dec.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_FIXED_DECODER) += ac3dec_fixed.o ac3dec_data.o ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \
ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o
diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h
index b9f34b9..0a1ff23 100644
--- a/libavcodec/ac3.h
+++ b/libavcodec/ac3.h
@@ -27,6 +27,10 @@
#ifndef AVCODEC_AC3_H
#define AVCODEC_AC3_H
+#ifndef CONFIG_AC3_FIXED
+# define CONFIG_AC3_FIXED 0
+#endif
+
#define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */
#define AC3_MAX_CHANNELS 7 /**< maximum number of channels, including coupling channel */
#define CPL_CH 0 /**< coupling channel index */
@@ -51,6 +55,41 @@
#define EXP_D25 2
#define EXP_D45 3
+#if CONFIG_AC3_FIXED
+
+#define CONFIG_FFT_FLOAT 0
+
+/* pre-defined gain values */
+#define LEVEL_PLUS_3DB 5793
+#define LEVEL_PLUS_1POINT5DB 4871
+#define LEVEL_MINUS_1POINT5DB 3444
+#define LEVEL_MINUS_3DB 2896
+#define LEVEL_MINUS_4POINT5DB 2435
+#define LEVEL_MINUS_6DB 2048
+#define LEVEL_MINUS_9DB 1448
+#define LEVEL_ZERO 0
+#define LEVEL_ONE 4096
+
+#define MUL_BIAS1 65536
+#define MUL_BIAS2 2147418112
+
+#define AC3_RENAME(x) x ## _fixed
+#define AC3_CENTER(x) center_levels[x]
+#define AC3_SURROUND(x) surround_levels[x]
+#define AC3_LEVEL(x) ((x)*23170 + 0x4000) >> 15
+#define AC3_NORM(x,norm) ((x)<<12)/norm
+#define AC3_DYNAMIC_RANGE(x) (x)
+#define AC3_SPX_BLEND(x) (x)
+#define TYPE_PREFIX(x) fixed_ ## x
+
+#define AC3_DYNAMIC_RANGE1 0
+#define INTFLOAT int
+#define SHORTFLOAT int16_t
+
+#define ROUND12(x) ((x)+2048)>>12
+
+#else
+
/* pre-defined gain values */
#define LEVEL_PLUS_3DB 1.4142135623730950
#define LEVEL_PLUS_1POINT5DB 1.1892071150027209
@@ -62,6 +101,26 @@
#define LEVEL_ZERO 0.0000000000000000
#define LEVEL_ONE 1.0000000000000000
+#define MUL_BIAS1 1.0f
+#define MUL_BIAS2 32767.0f
+
+#define AC3_RENAME(x) x
+#define AC3_CENTER(x) (x)
+#define AC3_SURROUND(x) (x)
+#define AC3_LEVEL(x) (x)*LEVEL_MINUS_3DB
+#define AC3_NORM(x,norm) (x)*(1.0f/norm)
+#define AC3_DYNAMIC_RANGE(x) ((dynamic_range_tab[x] - 1.0) * s->drc_scale) + 1.0
+#define AC3_SPX_BLEND(x) (x)* (1.0f/32)
+#define TYPE_PREFIX(x) float_ ## x
+
+#define AC3_DYNAMIC_RANGE1 1.0f
+#define INTFLOAT float
+#define SHORTFLOAT float
+
+#define ROUND12(x) (x)
+
+#endif /* CONFIG_AC3_FIXED */
+
/** Delta bit allocation strategy */
typedef enum {
DBA_REUSE = 0,
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index c608de8..0d72c54 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -64,7 +64,7 @@ static const uint8_t quantization_tab[16] = {
static float dynamic_range_tab[256];
/** Adjustments in dB gain */
-static const float gain_levels[9] = {
+static const INTFLOAT AC3_RENAME(gain_levels)[9] = {
LEVEL_PLUS_3DB,
LEVEL_PLUS_1POINT5DB,
LEVEL_ONE,
@@ -157,16 +157,16 @@ static av_cold void ac3_tables_init(void)
/**
* AVCodec initialization
*/
-static av_cold int ac3_decode_init(AVCodecContext *avctx)
+static av_cold int AC3_RENAME(ac3_decode_init)(AVCodecContext *avctx)
{
AC3DecodeContext *s = avctx->priv_data;
s->avctx = avctx;
ff_ac3_common_init();
ac3_tables_init();
- ff_mdct_init(&s->imdct_256, 8, 1, 1.0);
- ff_mdct_init(&s->imdct_512, 9, 1, 1.0);
- ff_kbd_window_init(s->window, 5.0, 256);
+ AC3_RENAME(ff_mdct_init)(&s->imdct_256, 8, 1, 1.0);
+ AC3_RENAME(ff_mdct_init)(&s->imdct_512, 9, 1, 1.0);\
+ AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256);
ff_dsputil_init(&s->dsp, avctx);
ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
ff_fmt_convert_init(&s->fmt_conv, avctx);
@@ -174,10 +174,10 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx)
/* set scale value for float to int16 conversion */
if (avctx->request_sample_fmt == AV_SAMPLE_FMT_FLT) {
- s->mul_bias = 1.0f;
+ s->mul_bias = MUL_BIAS1;
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
} else {
- s->mul_bias = 32767.0f;
+ s->mul_bias = MUL_BIAS2;
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
}
@@ -300,23 +300,23 @@ static int parse_frame_header(AC3DecodeContext *s)
* Set stereo downmixing coefficients based on frame header info.
* reference: Section 7.8.2 Downmixing Into Two Channels
*/
-static void set_downmix_coeffs(AC3DecodeContext *s)
+static void AC3_RENAME(set_downmix_coeffs)(AC3DecodeContext *s)
{
int i;
- float cmix = gain_levels[s-> center_mix_level];
- float smix = gain_levels[s->surround_mix_level];
- float norm0, norm1;
+ INTFLOAT cmix = AC3_RENAME(gain_levels)[s-> center_mix_level];
+ INTFLOAT smix = AC3_RENAME(gain_levels)[s->surround_mix_level];
+ INTFLOAT norm0, norm1;
for (i = 0; i < s->fbw_channels; i++) {
- s->downmix_coeffs[i][0] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]];
- s->downmix_coeffs[i][1] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]];
+ s->downmix_coeffs[i][0] = AC3_RENAME(gain_levels)[ac3_default_coeffs[s->channel_mode][i][0]];
+ s->downmix_coeffs[i][1] = AC3_RENAME(gain_levels)[ac3_default_coeffs[s->channel_mode][i][1]];
}
if (s->channel_mode > 1 && s->channel_mode & 1) {
s->downmix_coeffs[1][0] = s->downmix_coeffs[1][1] = cmix;
}
if (s->channel_mode == AC3_CHMODE_2F1R || s->channel_mode == AC3_CHMODE_3F1R) {
int nf = s->channel_mode - 2;
- s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf][1] = smix * LEVEL_MINUS_3DB;
+ s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf][1] = AC3_LEVEL(smix);
}
if (s->channel_mode == AC3_CHMODE_2F2R || s->channel_mode == AC3_CHMODE_3F2R) {
int nf = s->channel_mode - 4;
@@ -324,22 +324,20 @@ static void set_downmix_coeffs(AC3DecodeContext *s)
}
/* renormalize */
- norm0 = norm1 = 0.0;
+ norm0 = norm1 = (INTFLOAT)0.0;
for (i = 0; i < s->fbw_channels; i++) {
norm0 += s->downmix_coeffs[i][0];
norm1 += s->downmix_coeffs[i][1];
}
- norm0 = 1.0f / norm0;
- norm1 = 1.0f / norm1;
+
for (i = 0; i < s->fbw_channels; i++) {
- s->downmix_coeffs[i][0] *= norm0;
- s->downmix_coeffs[i][1] *= norm1;
+ s->downmix_coeffs[i][0] = AC3_NORM(s->downmix_coeffs[i][0],norm0);
+ s->downmix_coeffs[i][1] = AC3_NORM(s->downmix_coeffs[i][1],norm1);
}
if (s->output_mode == AC3_CHMODE_MONO) {
for (i = 0; i < s->fbw_channels; i++)
- s->downmix_coeffs[i][0] = (s->downmix_coeffs[i][0] +
- s->downmix_coeffs[i][1]) * LEVEL_MINUS_3DB;
+ s->downmix_coeffs[i][0] = AC3_LEVEL(s->downmix_coeffs[i][0] + s->downmix_coeffs[i][1]);
}
}
@@ -602,51 +600,25 @@ static inline void do_imdct(AC3DecodeContext *s, int channels)
for (ch = 1; ch <= channels; ch++) {
if (s->block_switch[ch]) {
int i;
- float *x = s->tmp_output + 128;
+ FFTSample *x = s->tmp_output+128;
for (i = 0; i < 128; i++)
x[i] = s->transform_coeffs[ch][2 * i];
s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x);
- s->dsp.vector_fmul_window(s->output[ch - 1], s->delay[ch - 1],
+ s->dsp.AC3_RENAME(vector_fmul_window)(s->output[ch - 1], s->delay[ch - 1],
s->tmp_output, s->window, 128);
for (i = 0; i < 128; i++)
x[i] = s->transform_coeffs[ch][2 * i + 1];
s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1], x);
} else {
s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]);
- s->dsp.vector_fmul_window(s->output[ch - 1], s->delay[ch - 1],
+ s->dsp.AC3_RENAME(vector_fmul_window)(s->output[ch - 1], s->delay[ch - 1],
s->tmp_output, s->window, 128);
- memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(float));
+ memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(FFTSample));
}
}
}
-/**
- * Upmix delay samples from stereo to original channel layout.
- */
-static void ac3_upmix_delay(AC3DecodeContext *s)
-{
- int channel_data_size = sizeof(s->delay[0]);
- switch (s->channel_mode) {
- case AC3_CHMODE_DUALMONO:
- case AC3_CHMODE_STEREO:
- /* upmix mono to stereo */
- memcpy(s->delay[1], s->delay[0], channel_data_size);
- break;
- case AC3_CHMODE_2F2R:
- memset(s->delay[3], 0, channel_data_size);
- case AC3_CHMODE_2F1R:
- memset(s->delay[2], 0, channel_data_size);
- break;
- case AC3_CHMODE_3F2R:
- memset(s->delay[4], 0, channel_data_size);
- case AC3_CHMODE_3F1R:
- memset(s->delay[3], 0, channel_data_size);
- case AC3_CHMODE_3F:
- memcpy(s->delay[2], s->delay[1], channel_data_size);
- memset(s->delay[1], 0, channel_data_size);
- break;
- }
-}
+
/**
* Decode band structure for coupling, spectral extension, or enhanced coupling.
@@ -748,10 +720,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
i = !s->channel_mode;
do {
if (get_bits1(gbc)) {
- s->dynamic_range[i] = ((dynamic_range_tab[get_bits(gbc, 8)] - 1.0) *
- s->drc_scale) + 1.0;
+ s->dynamic_range[i] = AC3_DYNAMIC_RANGE(get_bits(gbc, 8));
} else if (blk == 0) {
- s->dynamic_range[i] = 1.0f;
+ s->dynamic_range[i] = AC3_DYNAMIC_RANGE1;
}
} while (i--);
@@ -777,6 +748,10 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (start_subband > 7)
start_subband += start_subband - 7;
end_subband = get_bits(gbc, 3) + 5;
+#if CONFIG_AC3_FIXED
+ s->spx_dst_end_freq = end_freq_inv_tab[end_subband];
+ end_subband += 5;
+#endif
if (end_subband > 7)
end_subband += end_subband - 7;
dst_start_freq = dst_start_freq * 12 + 25;
@@ -797,7 +772,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
s->spx_dst_start_freq = dst_start_freq;
s->spx_src_start_freq = src_start_freq;
+#if !CONFIG_AC3_FIXED
s->spx_dst_end_freq = dst_end_freq;
+#endif
decode_band_structure(gbc, blk, s->eac3, 0,
start_subband, end_subband,
@@ -817,18 +794,45 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
for (ch = 1; ch <= fbw_channels; ch++) {
if (s->channel_uses_spx[ch]) {
if (s->first_spx_coords[ch] || get_bits1(gbc)) {
- float spx_blend;
+ INTFLOAT spx_blend;
int bin, master_spx_coord;
s->first_spx_coords[ch] = 0;
- spx_blend = get_bits(gbc, 5) * (1.0f/32);
+ spx_blend = AC3_SPX_BLEND(get_bits(gbc, 5));
master_spx_coord = get_bits(gbc, 2) * 3;
bin = s->spx_src_start_freq;
for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
int bandsize;
int spx_coord_exp, spx_coord_mant;
- float nratio, sblend, nblend, spx_coord;
+ INTFLOAT nratio, sblend, nblend;
+#if CONFIG_AC3_FIXED
+ int64_t accu;
+ /* calculate blending factors */
+ bandsize = s->spx_band_sizes[bnd];
+ accu = (long long)((bin << 23) + (bandsize << 22)) * s->spx_dst_end_freq;
+ nratio = (int)(accu >> 32);
+ nratio -= spx_blend << 18;
+
+ if (nratio < 0)
+ {
+ nblend = 0;
+ sblend = 0x800000;
+ }
+ else if (nratio > 0x7fffff)
+ {
+ nblend = 0x800000;
+ sblend = 0;
+ }
+ else
+ {
+ nblend = ac3_fixed_sqrt(nratio);
+ accu = (long long)nblend * 1859775393;
+ nblend = (int)((accu + (1<<29)) >> 30);
+ sblend = ac3_fixed_sqrt(0x800000 - nratio);
+ }
+#else
+ float spx_coord;
/* calculate blending factors */
bandsize = s->spx_band_sizes[bnd];
@@ -837,6 +841,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
nblend = sqrtf(3.0f * nratio); // noise is scaled by sqrt(3)
// to give unity variance
sblend = sqrtf(1.0f - nratio);
+#endif
bin += bandsize;
/* decode spx coordinates */
@@ -845,11 +850,18 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (spx_coord_exp == 15) spx_coord_mant <<= 1;
else spx_coord_mant += 4;
spx_coord_mant <<= (25 - spx_coord_exp - master_spx_coord);
- spx_coord = spx_coord_mant * (1.0f / (1 << 23));
/* multiply noise and signal blending factors by spx coordinate */
+#if CONFIG_AC3_FIXED
+ accu = (long long)nblend * spx_coord_mant;
+ s->spx_noise_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23);
+ accu = (long long)sblend * spx_coord_mant;
+ s->spx_signal_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23);
+#else
+ spx_coord = spx_coord_mant * (1.0f / (1 << 23));
s->spx_noise_blend [ch][bnd] = nblend * spx_coord;
s->spx_signal_blend[ch][bnd] = sblend * spx_coord;
+#endif
}
}
} else {
@@ -1206,7 +1218,28 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
/* apply scaling to coefficients (headroom, dynrng) */
for (ch = 1; ch <= s->channels; ch++) {
+#if CONFIG_AC3_FIXED
+ int dynrng;
+
+ if(s->channel_mode == AC3_CHMODE_DUALMONO) {
+ dynrng = s->dynamic_range[2-ch];
+ } else {
+ dynrng = s->dynamic_range[0];
+ }
+ scale_coefs(s->transform_coeffs[ch], s->fixed_coeffs[ch], dynrng, 256);
+ }
+
+ do_imdct(s, s->channels);
+
+ downmix_output = s->channels != s->out_channels &&
+ !((s->output_mode & AC3_OUTPUT_LFEON) &&
+ s->fbw_channels == s->out_channels);
+
+ if (downmix_output)
+ s->ac3dsp.downmix_fixed(s->output, s->downmix_coeffs, s->out_channels, s->fbw_channels, 256);
+#else
float gain = s->mul_bias / 4194304.0f;
+
if (s->channel_mode == AC3_CHMODE_DUALMONO) {
gain *= s->dynamic_range[2 - ch];
} else {
@@ -1255,24 +1288,24 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
do_imdct(s, s->out_channels);
}
-
+#endif
return 0;
}
/**
* Decode a single AC-3 frame.
*/
-static int ac3_decode_frame(AVCodecContext * avctx, void *data,
+static int AC3_RENAME(ac3_decode_frame)(AVCodecContext * avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
AC3DecodeContext *s = avctx->priv_data;
- float *out_samples_flt;
+ INTFLOAT *out_samples_flt;
int16_t *out_samples_s16;
int blk, ch, err, ret;
const uint8_t *channel_map;
- const float *output[AC3_MAX_CHANNELS];
+ const INTFLOAT *output[AC3_MAX_CHANNELS];
/* copy input buffer to decoder context to avoid reading past the end
of the buffer, which can be caused by a damaged input stream. */
@@ -1353,14 +1386,14 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
avctx->channels = s->out_channels;
avctx->channel_layout = s->channel_layout;
- s->loro_center_mix_level = gain_levels[s-> center_mix_level];
- s->loro_surround_mix_level = gain_levels[s->surround_mix_level];
+ s->loro_center_mix_level = AC3_RENAME(gain_levels)[s-> center_mix_level];
+ s->loro_surround_mix_level = AC3_RENAME(gain_levels)[s->surround_mix_level];
s->ltrt_center_mix_level = LEVEL_MINUS_3DB;
s->ltrt_surround_mix_level = LEVEL_MINUS_3DB;
/* set downmixing coefficients if needed */
if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) &&
s->fbw_channels == s->out_channels)) {
- set_downmix_coeffs(s);
+ AC3_RENAME(set_downmix_coeffs)(s);
}
} else if (!s->out_channels) {
s->out_channels = avctx->channels;
@@ -1382,7 +1415,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
- out_samples_flt = (float *)s->frame.data[0];
+ out_samples_flt = (INTFLOAT *)s->frame.data[0];
out_samples_s16 = (int16_t *)s->frame.data[0];
/* decode the audio blocks */
@@ -1395,11 +1428,11 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
err = 1;
}
if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) {
- s->fmt_conv.float_interleave(out_samples_flt, output, 256,
+ s->fmt_conv.TYPE_PREFIX(interleave)(out_samples_flt, output, 256,
s->out_channels);
out_samples_flt += 256 * s->out_channels;
} else {
- s->fmt_conv.float_to_int16_interleave(out_samples_s16, output, 256,
+ s->fmt_conv.TYPE_PREFIX(to_int16_interleave)(out_samples_s16, output, 256,
s->out_channels);
out_samples_s16 += 256 * s->out_channels;
}
@@ -1416,7 +1449,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
/**
* Uninitialize the AC-3 decoder.
*/
-static av_cold int ac3_decode_end(AVCodecContext *avctx)
+static av_cold int AC3_RENAME(ac3_decode_end)(AVCodecContext *avctx)
{
AC3DecodeContext *s = avctx->priv_data;
ff_mdct_end(&s->imdct_512);
@@ -1438,51 +1471,3 @@ static const AVOption options[] = {
{ NULL},
};
-
-static const AVClass ac3_decoder_class = {
- .class_name = "AC3 decoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_ac3_decoder = {
- .name = "ac3",
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_AC3,
- .priv_data_size = sizeof (AC3DecodeContext),
- .init = ac3_decode_init,
- .close = ac3_decode_end,
- .decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
- .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
- AV_SAMPLE_FMT_S16,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &ac3_decoder_class,
-};
-
-#if CONFIG_EAC3_DECODER
-static const AVClass eac3_decoder_class = {
- .class_name = "E-AC3 decoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_eac3_decoder = {
- .name = "eac3",
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_EAC3,
- .priv_data_size = sizeof (AC3DecodeContext),
- .init = ac3_decode_init,
- .close = ac3_decode_end,
- .decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
- .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
- AV_SAMPLE_FMT_S16,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &eac3_decoder_class,
-};
-#endif
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index e0f3dc7..a215878 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -130,8 +130,8 @@ typedef struct {
int num_spx_bands; ///< number of spx bands (nspxbnds)
uint8_t spx_band_sizes[SPX_MAX_BANDS]; ///< number of bins in each spx band
uint8_t first_spx_coords[AC3_MAX_CHANNELS]; ///< first spx coordinates states (firstspxcos)
- float spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact)
- float spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
+ INTFLOAT spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact)
+ INTFLOAT spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
///@}
///@name Adaptive hybrid transform
@@ -143,15 +143,15 @@ typedef struct {
int fbw_channels; ///< number of full-bandwidth channels
int channels; ///< number of total channels
int lfe_ch; ///< index of LFE channel
- float downmix_coeffs[AC3_MAX_CHANNELS][2]; ///< stereo downmix coefficients
+ INTFLOAT downmix_coeffs[AC3_MAX_CHANNELS][2]; ///< stereo downmix coefficients
int downmixed; ///< indicates if coeffs are currently downmixed
int output_mode; ///< output channel configuration
int out_channels; ///< number of output channels
///@}
///@name Dynamic range
- float dynamic_range[2]; ///< dynamic range
- float drc_scale; ///< percentage of dynamic range compression to be applied
+ INTFLOAT dynamic_range[2]; ///< dynamic range
+ INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied
///@}
///@name Bandwidth
@@ -201,16 +201,16 @@ typedef struct {
DSPContext dsp; ///< for optimization
AC3DSPContext ac3dsp;
FmtConvertContext fmt_conv; ///< optimized conversion functions
- float mul_bias; ///< scaling for float_to_int16 conversion
+ INTFLOAT mul_bias; ///< scaling for float_to_int16 conversion
///@}
///@name Aligned arrays
DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients
- DECLARE_ALIGNED(32, float, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients
- DECLARE_ALIGNED(32, float, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block
- DECLARE_ALIGNED(32, float, window)[AC3_BLOCK_SIZE]; ///< window coefficients
- DECLARE_ALIGNED(32, float, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing
- DECLARE_ALIGNED(32, float, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing
+ DECLARE_ALIGNED(32, FFTSample, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients
+ DECLARE_ALIGNED(32, SHORTFLOAT, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block
+ DECLARE_ALIGNED(32, SHORTFLOAT, window)[AC3_BLOCK_SIZE]; ///< window coefficients
+ DECLARE_ALIGNED(32, SHORTFLOAT, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing
+ DECLARE_ALIGNED(32, INTFLOAT, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing
DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread
///@}
} AC3DecodeContext;
diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c
new file mode 100644
index 0000000..ffe9f7c
--- /dev/null
+++ b/libavcodec/ac3dec_fixed.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Stanislav Ocovaj (socovaj at mips.com)
+ *
+ * AC3 fixed-point decoder for MIPS platforms
+ *
+ * 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
+ */
+
+#define CONFIG_FFT_FLOAT 0
+#define CONFIG_AC3_FIXED 1
+#include "ac3dec.h"
+
+
+/**
+ * Table for center mix levels
+ * reference: Section 5.4.2.4 cmixlev
+ */
+static const uint8_t center_levels[4] = { 4, 5, 6, 5 };
+
+/**
+ * Table for surround mix levels
+ * reference: Section 5.4.2.5 surmixlev
+ */
+static const uint8_t surround_levels[4] = { 4, 6, 7, 6 };
+
+int end_freq_inv_tab[8] =
+{
+ 50529027, 44278013, 39403370, 32292987, 27356480, 23729101, 20951060, 18755316
+};
+
+static void scale_coefs (
+ int16_t *dst,
+ const int *src,
+ int dynrng,
+ int len)
+{
+ int i, shift, round;
+ int16_t mul;
+ int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ mul = (dynrng & 0x1f) + 0x20;
+ shift = 12 - ((dynrng << 24) >> 29);
+ round = 1 << (shift-1);
+ for (i=0; i<len; i+=8) {
+
+ temp = src[i] * mul;
+ temp1 = src[i+1] * mul;
+ temp = temp + round;
+ temp2 = src[i+2] * mul;
+
+ temp1 = temp1 + round;
+ dst[i] = temp >> shift;
+ temp3 = src[i+3] * mul;
+ temp2 = temp2 + round;
+
+ dst[i+1] = temp1 >> shift;
+ temp4 = src[i + 4] * mul;
+ temp3 = temp3 + round;
+ dst[i+2] = temp2 >> shift;
+
+ temp5 = src[i+5] * mul;
+ temp4 = temp4 + round;
+ dst[i+3] = temp3 >> shift;
+ temp6 = src[i+6] * mul;
+
+ dst[i+4] = temp4 >> shift;
+ temp5 = temp5 + round;
+ temp7 = src[i+7] * mul;
+ temp6 = temp6 + round;
+
+ dst[i+5] = temp5 >> shift;
+ temp7 = temp7 + round;
+ dst[i+6] = temp6 >> shift;
+ dst[i+7] = temp7 >> shift;
+
+ }
+}
+
+static int ac3_fixed_sqrt(int x)
+{
+ int retval;
+ int bit_mask;
+ int guess;
+ int square;
+ int i;
+ long long accu;
+
+ retval = 0;
+ bit_mask = 0x400000;
+
+ for (i=0; i<23; i++)
+ {
+ guess = retval + bit_mask;
+ accu = (long long)guess * guess;
+ square = (int)(accu >> 23);
+ if (x >= square)
+ retval += bit_mask;
+ bit_mask >>= 1;
+ }
+ return retval;
+}
+
+#include "ac3dec.c"
+
+static const AVClass ac3_decoder_class = {
+ .class_name = "AC3 fixed decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_fixed_decoder = {
+ .name = "ac3_fixed",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = CODEC_ID_AC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init_fixed,
+ .close = ac3_decode_end_fixed,
+ .decode = ac3_decode_frame_fixed,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &ac3_decoder_class,
+};
diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c
new file mode 100644
index 0000000..f051cc0
--- /dev/null
+++ b/libavcodec/ac3dec_float.c
@@ -0,0 +1,105 @@
+/*
+ * AC-3 Audio Decoder
+ * This code was developed as part of Google Summer of Code 2006.
+ * E-AC-3 support was added as part of Google Summer of Code 2007.
+ *
+ * Copyright (c) 2006 Kartikey Mahendra BHATT (bhattkm at gmail dot com)
+ * Copyright (c) 2007-2008 Bartlomiej Wolowiec <bartek.wolowiec at gmail.com>
+ * Copyright (c) 2007 Justin Ruggles <justin.ruggles at gmail.com>
+ *
+ * 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
+ */
+
+/**
+ * Upmix delay samples from stereo to original channel layout.
+ */
+#include "ac3dec.h"
+
+static void ac3_upmix_delay(AC3DecodeContext *s)
+{
+ int channel_data_size = sizeof(s->delay[0]);
+ switch (s->channel_mode) {
+ case AC3_CHMODE_DUALMONO:
+ case AC3_CHMODE_STEREO:
+ /* upmix mono to stereo */
+ memcpy(s->delay[1], s->delay[0], channel_data_size);
+ break;
+ case AC3_CHMODE_2F2R:
+ memset(s->delay[3], 0, channel_data_size);
+ case AC3_CHMODE_2F1R:
+ memset(s->delay[2], 0, channel_data_size);
+ break;
+ case AC3_CHMODE_3F2R:
+ memset(s->delay[4], 0, channel_data_size);
+ case AC3_CHMODE_3F1R:
+ memset(s->delay[3], 0, channel_data_size);
+ case AC3_CHMODE_3F:
+ memcpy(s->delay[2], s->delay[1], channel_data_size);
+ memset(s->delay[1], 0, channel_data_size);
+ break;
+ }
+}
+
+#include "ac3dec.c"
+
+static const AVClass ac3_decoder_class = {
+ .class_name = "AC3 decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_decoder = {
+ .name = "ac3",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_AC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init,
+ .close = ac3_decode_end,
+ .decode = ac3_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &ac3_decoder_class,
+};
+
+#if CONFIG_EAC3_DECODER
+static const AVClass eac3_decoder_class = {
+ .class_name = "E-AC3 decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_eac3_decoder = {
+ .name = "eac3",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_EAC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init,
+ .close = ac3_decode_end,
+ .decode = ac3_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &eac3_decoder_class,
+};
+#endif
diff --git a/libavcodec/ac3dsp.c b/libavcodec/ac3dsp.c
index 4e1e4bd..e044ce1 100644
--- a/libavcodec/ac3dsp.c
+++ b/libavcodec/ac3dsp.c
@@ -239,6 +239,31 @@ static void ac3_downmix_c(float (*samples)[256], float (*matrix)[2],
}
}
+static void ac3_downmix_c_fixed(int (*samples)[256], int (*matrix)[2],
+ int out_ch, int in_ch, int len)
+{
+ int i, j;
+ int v0, v1;
+ if (out_ch == 2) {
+ for (i = 0; i < len; i++) {
+ v0 = v1 = 0;
+ for (j = 0; j < in_ch; j++) {
+ v0 += samples[j][i] * matrix[j][0];
+ v1 += samples[j][i] * matrix[j][1];
+ }
+ samples[0][i] = (v0+2048)>>12;
+ samples[1][i] = (v1+2048)>>12;
+ }
+ } else if (out_ch == 1) {
+ for (i = 0; i < len; i++) {
+ v0 = 0;
+ for (j = 0; j < in_ch; j++)
+ v0 += samples[j][i] * matrix[j][0];
+ samples[0][i] = (v0+2048)>>12;
+ }
+ }
+}
+
av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact)
{
c->ac3_exponent_min = ac3_exponent_min_c;
@@ -253,6 +278,7 @@ av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact)
c->sum_square_butterfly_int32 = ac3_sum_square_butterfly_int32_c;
c->sum_square_butterfly_float = ac3_sum_square_butterfly_float_c;
c->downmix = ac3_downmix_c;
+ c->downmix_fixed = ac3_downmix_c_fixed;
if (ARCH_ARM)
ff_ac3dsp_init_arm(c, bit_exact);
diff --git a/libavcodec/ac3dsp.h b/libavcodec/ac3dsp.h
index fbc63f6..eb51d84 100644
--- a/libavcodec/ac3dsp.h
+++ b/libavcodec/ac3dsp.h
@@ -134,6 +134,8 @@ typedef struct AC3DSPContext {
void (*downmix)(float (*samples)[256], float (*matrix)[2], int out_ch,
int in_ch, int len);
+ void (*downmix_fixed)(int (*samples)[256], int (*matrix)[2], int out_ch,
+ int in_ch, int len);
} AC3DSPContext;
void ff_ac3dsp_init (AC3DSPContext *c, int bit_exact);
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 8806c6a..96b73ab 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -278,6 +278,7 @@ void avcodec_register_all(void)
REGISTER_DECODER (AAC_LATM, aac_latm);
REGISTER_ENCDEC (AC3, ac3);
REGISTER_ENCODER (AC3_FIXED, ac3_fixed);
+ REGISTER_DECODER (AC3_FIXED, ac3_fixed);
REGISTER_ENCDEC (ALAC, alac);
REGISTER_DECODER (ALS, als);
REGISTER_DECODER (AMRNB, amrnb);
diff --git a/libavcodec/dsputil.c b/libavcodec/dsputil.c
index af939b1..f813bb8 100644
--- a/libavcodec/dsputil.c
+++ b/libavcodec/dsputil.c
@@ -2514,6 +2514,24 @@ static void vector_fmul_window_c(float *dst, const float *src0,
}
}
+static void vector_fmul_window_fixed_c(int *dst, const int16_t *src0,
+ const int16_t *src1, const int16_t *win, int len)
+{
+ int i,j;
+ dst += len;
+ win += len;
+ src0+= len;
+
+ for (i=-len, j=len-1; i<0; i++, j--) {
+ int s0 = src0[i];
+ int s1 = src1[j];
+ int wi = win[i];
+ int wj = win[j];
+ dst[i] = (s0*wj - s1*wi + 0x4000) >> 15;
+ dst[j] = (s0*wi + s1*wj + 0x4000) >> 15;
+ }
+}
+
static void vector_fmul_scalar_c(float *dst, const float *src, float mul,
int len)
{
@@ -3035,6 +3053,7 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
c->vector_fmul_reverse = vector_fmul_reverse_c;
c->vector_fmul_add = vector_fmul_add_c;
c->vector_fmul_window = vector_fmul_window_c;
+ c->vector_fmul_window_fixed = vector_fmul_window_fixed_c;
c->vector_clipf = vector_clipf_c;
c->scalarproduct_int16 = scalarproduct_int16_c;
c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_c;
diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h
index 2173508..0eb1023 100644
--- a/libavcodec/dsputil.h
+++ b/libavcodec/dsputil.h
@@ -390,6 +390,7 @@ typedef struct DSPContext {
void (*vector_fmul_add)(float *dst, const float *src0, const float *src1, const float *src2, int len);
/* assume len is a multiple of 4, and arrays are 16-byte aligned */
void (*vector_fmul_window)(float *dst, const float *src0, const float *src1, const float *win, int len);
+ void (*vector_fmul_window_fixed)(int *dst, const int16_t *src0, const int16_t *src1, const int16_t *win, int len);
/* assume len is a multiple of 8, and arrays are 16-byte aligned */
void (*vector_clipf)(float *dst /* align 16 */, const float *src /* align 16 */, float min, float max, int len /* align 16 */);
/**
diff --git a/libavcodec/fft-internal.h b/libavcodec/fft-internal.h
index 61066bb..8965b5d 100644
--- a/libavcodec/fft-internal.h
+++ b/libavcodec/fft-internal.h
@@ -46,9 +46,9 @@ void ff_mdct_calcw_c(FFTContext *s, FFTDouble *output, const FFTSample *input);
#define sqrthalf ((int16_t)((1<<15)*M_SQRT1_2))
-#define BF(x, y, a, b) do { \
- x = (a - b) >> 1; \
- y = (a + b) >> 1; \
+#define BF(x, y, a, b) do { \
+ x = (a - b); \
+ y = (a + b); \
} while (0)
#define CMULS(dre, dim, are, aim, bre, bim, sh) do { \
diff --git a/libavcodec/fmtconvert.c b/libavcodec/fmtconvert.c
index 372f2a3..951a2e5 100644
--- a/libavcodec/fmtconvert.c
+++ b/libavcodec/fmtconvert.c
@@ -30,10 +30,21 @@ static void int32_to_float_fmul_scalar_c(float *dst, const int *src, float mul,
dst[i] = src[i] * mul;
}
+static void int32_to_fixed_fmul_scalar_c(int16_t *dst, const int *src, int mul, int len) {
+ int i;
+ for(i=0; i<len; i++)
+ dst[i] = (src[i] * mul + 0x8000) >> 16;
+}
+
static av_always_inline int float_to_int16_one(const float *src){
return av_clip_int16(lrintf(*src));
}
+static av_always_inline int fixed_to_int16_one(const int *src)
+{
+ return av_clip_int16_c_fixed(*src);
+}
+
static void float_to_int16_c(int16_t *dst, const float *src, long len)
{
int i;
@@ -57,6 +68,35 @@ static void float_to_int16_interleave_c(int16_t *dst, const float **src,
}
}
+static void fixed_to_int16_interleave_c(int16_t *dst, const int **src,
+ long len, int channels)
+{
+ int i,j,c;
+ if(channels==2) {
+ for(i=0; i<len; i++) {
+ dst[2*i] = fixed_to_int16_one(src[0]+i);
+ dst[2*i+1] = fixed_to_int16_one(src[1]+i);
+ }
+ }
+ else {
+ if(channels==6) {
+ for(i=0; i<len; i++) {
+ dst[6*i] = fixed_to_int16_one(src[0]+i);
+ dst[6*i+1] = fixed_to_int16_one(src[1]+i);
+ dst[6*i+2] = fixed_to_int16_one(src[2]+i);
+ dst[6*i+3] = fixed_to_int16_one(src[3]+i);
+ dst[6*i+4] = fixed_to_int16_one(src[4]+i);
+ dst[6*i+5] = fixed_to_int16_one(src[5]+i);
+ }
+ }
+ else {
+ for(c=0; c<channels; c++)
+ for(i=0, j=c; i<len; i++, j+=channels)
+ dst[j] = fixed_to_int16_one(src[c]+i);
+ }
+ }
+}
+
void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
int channels)
{
@@ -76,9 +116,41 @@ void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
}
}
+void ff_fixed_interleave_c(int *dst, const int **src, unsigned int len,
+ int channels)
+{
+ int j, c;
+ unsigned int i;
+ if (channels == 6) {
+ for (i = 0; i < len; i++) {
+ dst[6*i] = src[0][i];
+ dst[6*i+1] = src[1][i];
+ dst[6*i+2] = src[2][i];
+ dst[6*i+3] = src[3][i];
+ dst[6*i+4] = src[4][i];
+ dst[6*i+5] = src[5][i];
+ }
+ }
+ else if (channels == 2) {
+ for (i = 0; i < len; i++) {
+ dst[2*i] = src[0][i];
+ dst[2*i+1] = src[1][i];
+ }
+ } else if (channels == 1 && len < INT_MAX / sizeof(int)) {
+ memcpy(dst, src[0], len * sizeof(int));
+ } else {
+ for (c = 0; c < channels; c++)
+ for (i = 0, j = c; i < len; i++, j += channels)
+ dst[j] = src[c][i];
+ }
+}
+
av_cold void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx)
{
c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_c;
+ c->int32_to_fixed_fmul_scalar = int32_to_fixed_fmul_scalar_c;
+ c->fixed_to_int16_interleave = fixed_to_int16_interleave_c;
+ c->fixed_interleave = ff_fixed_interleave_c;
c->float_to_int16 = float_to_int16_c;
c->float_to_int16_interleave = float_to_int16_interleave_c;
c->float_interleave = ff_float_interleave_c;
diff --git a/libavcodec/fmtconvert.h b/libavcodec/fmtconvert.h
index ab2caa2..8bda1e7 100644
--- a/libavcodec/fmtconvert.h
+++ b/libavcodec/fmtconvert.h
@@ -38,6 +38,54 @@ typedef struct FmtConvertContext {
void (*int32_to_float_fmul_scalar)(float *dst, const int *src, float mul, int len);
/**
+ * Multiply a array of int32_t by a int32_t value and convert to int16_t.
+ * @param dst destination array of int16_t.
+ * constraints: 16-byte aligned
+ * @param src source array of int32_t.
+ * constraints: 16-byte aligned
+ * @param len number of elements in array.
+ * constraints: multiple of 8
+ */
+ void (*int32_to_fixed_fmul_scalar)(int16_t *dst, const int *src, int mul, int len);
+ /**
+ * Convert an array of int32_t to an array of int16_t.
+ *
+ * @param dst destination array of int16_t.
+ * constraints: 16-byte aligned
+ * @param src source array of int32_t.
+ * constraints: 16-byte aligned
+ * @param len number of elements to convert.
+ * constraints: multiple of 8
+ */
+ void (*fixed_to_int16)(int16_t *dst, const int *src, long len);
+ /**
+ * Convert multiple arrays of int32_t to an interleaved array of int16_t.
+ *
+ * @param dst destination array of interleaved int16_t.
+ * constraints: 16-byte aligned
+ * @param src source array of int32_t arrays, one for each channel.
+ * constraints: 16-byte aligned
+ * @param len number of elements to convert.
+ * constraints: multiple of 8
+ * @param channels number of channels
+ */
+ void (*fixed_to_int16_interleave)(int16_t *dst, const int **src,
+ long len, int channels);
+ /**
+ * Convert multiple arrays of int32_t to an array of interleaved int32_t.
+ *
+ * @param dst destination array of interleaved int32_t.
+ * constraints: 16-byte aligned
+ * @param src source array of int32_t arrays, one for each channel.
+ * constraints: 16-byte aligned
+ * @param len number of elements to convert.
+ * constraints: multiple of 8
+ * @param channels number of channels
+ */
+ void (*fixed_interleave)(int *dst, const int **src, unsigned int len,
+ int channels);
+
+ /**
* Convert an array of float to an array of int16_t.
*
* Convert floats from in the range [-32768.0,32767.0] to ints
@@ -87,6 +135,10 @@ typedef struct FmtConvertContext {
void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
int channels);
+void ff_fixed_interleave_c(int *dst, const int **src, unsigned int len,
+ int channels);
+void fixed_interleave(int *dst, const int **src, unsigned int len, int channels);
+
av_cold void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx);
void ff_fmt_convert_init_arm(FmtConvertContext *c, AVCodecContext *avctx);
diff --git a/libavcodec/kbdwin.c b/libavcodec/kbdwin.c
index 2722312..7e90714 100644
--- a/libavcodec/kbdwin.c
+++ b/libavcodec/kbdwin.c
@@ -46,3 +46,33 @@ av_cold void ff_kbd_window_init(float *window, float alpha, int n)
for (i = 0; i < n; i++)
window[i] = sqrt(local_window[i] / sum);
}
+
+av_cold void ff_kbd_window_init_fixed(int16_t *window, float alpha, int n)
+{
+ int i, j;
+ double sum = 0.0, bessel, tmp;
+ double local_window[FF_KBD_WINDOW_MAX];
+ double alpha2 = (alpha * M_PI / n) * (alpha * M_PI / n);
+
+ assert(n <= FF_KBD_WINDOW_MAX);
+
+ for (i = 0; i < n; i++) {
+ tmp = i * (n - i) * alpha2;
+ bessel = 1.0;
+ for (j = BESSEL_I0_ITER; j > 0; j--)
+ bessel = bessel * tmp / (j * j) + 1;
+ sum += bessel;
+ local_window[i] = sum;
+ }
+
+ sum++;
+ for (i = 0; i < n; i++)
+ {
+ int tmp;
+
+ tmp = (int)(32767*sqrt(local_window[i] / sum) + 0.5);
+ if (tmp > 32767)
+ tmp = 32767;
+ window[i] = (int16_t)tmp;
+ }
+}
diff --git a/libavcodec/kbdwin.h b/libavcodec/kbdwin.h
index 4b93975..fea8187 100644
--- a/libavcodec/kbdwin.h
+++ b/libavcodec/kbdwin.h
@@ -31,5 +31,5 @@
* @param n size of half window, max FF_KBD_WINDOW_MAX
*/
void ff_kbd_window_init(float *window, float alpha, int n);
-
+void ff_kbd_window_init_fixed(int16_t *window, float alpha, int n);
#endif /* AVCODEC_KBDWIN_H */
diff --git a/libavutil/common.h b/libavutil/common.h
index 3e3baab..7637b64 100644
--- a/libavutil/common.h
+++ b/libavutil/common.h
@@ -164,6 +164,16 @@ static av_always_inline av_const int16_t av_clip_int16_c(int a)
}
/**
+ * Clip a signed integer value into the 0, 65536 range
+ * @param a value to clip
+ * @return clipped value
+ */
+static av_always_inline av_const int16_t av_clip_int16_c_fixed(int a)
+{
+ return (a > 0xefff ? 0xefff : a);
+}
+
+/**
* Clip a signed 64-bit integer value into the -2147483648,2147483647 range.
* @param a value to clip
* @return clipped value
--
1.7.3.4
More information about the ffmpeg-devel
mailing list