diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2017-02-20 23:22:51 +0000 |
---|---|---|
committer | Rostislav Pehlivanov <atomnuker@gmail.com> | 2017-05-08 05:56:14 +0100 |
commit | b8c2b9c39279171f647d9c81f34ffa3d3ae93c47 (patch) | |
tree | fc50e13f8009274c05ab06eeeb80757b6dc10a94 | |
parent | 5f928c5201c077b9765610bc5304235c3f1d9bd6 (diff) | |
download | ffmpeg-b8c2b9c39279171f647d9c81f34ffa3d3ae93c47.tar.gz |
avcodec/dcaenc: Initial implementation of ADPCM encoding for DCA encoder
-rw-r--r-- | libavcodec/Makefile | 3 | ||||
-rw-r--r-- | libavcodec/dca_core.c | 46 | ||||
-rw-r--r-- | libavcodec/dca_core.h | 25 | ||||
-rw-r--r-- | libavcodec/dcaadpcm.c | 228 | ||||
-rw-r--r-- | libavcodec/dcaadpcm.h | 54 | ||||
-rw-r--r-- | libavcodec/dcadata.c | 2 | ||||
-rw-r--r-- | libavcodec/dcadata.h | 5 | ||||
-rw-r--r-- | libavcodec/dcaenc.c | 247 | ||||
-rw-r--r-- | libavcodec/dcaenc.h | 11 | ||||
-rw-r--r-- | libavcodec/dcamath.h | 1 |
10 files changed, 546 insertions, 76 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index b5c8cc1f98..44acc95394 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -244,7 +244,8 @@ OBJS-$(CONFIG_CYUV_DECODER) += cyuv.o OBJS-$(CONFIG_DCA_DECODER) += dcadec.o dca.o dcadata.o dcahuff.o \ dca_core.o dca_exss.o dca_xll.o dca_lbr.o \ dcadsp.o dcadct.o synth_filter.o -OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.o dcadata.o dcahuff.o +OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.o dcadata.o dcahuff.o \ + dcaadpcm.o OBJS-$(CONFIG_DDS_DECODER) += dds.o OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab.o \ dirac_arith.o dirac_dwt.o dirac_vlc.o diff --git a/libavcodec/dca_core.c b/libavcodec/dca_core.c index d5e628e763..36040f6f9d 100644 --- a/libavcodec/dca_core.c +++ b/libavcodec/dca_core.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "dcaadpcm.h" #include "dcadec.h" #include "dcadata.h" #include "dcahuff.h" @@ -670,46 +671,21 @@ static inline int extract_audio(DCACoreDecoder *s, int32_t *audio, int abits, in return 0; } -static inline void dequantize(int32_t *output, const int32_t *input, - int32_t step_size, int32_t scale, int residual) -{ - // Account for quantizer step size - int64_t step_scale = (int64_t)step_size * scale; - int n, shift = 0; - - // Limit scale factor resolution to 22 bits - if (step_scale > (1 << 23)) { - shift = av_log2(step_scale >> 23) + 1; - step_scale >>= shift; - } - - // Scale the samples - if (residual) { - for (n = 0; n < DCA_SUBBAND_SAMPLES; n++) - output[n] += clip23(norm__(input[n] * step_scale, 22 - shift)); - } else { - for (n = 0; n < DCA_SUBBAND_SAMPLES; n++) - output[n] = clip23(norm__(input[n] * step_scale, 22 - shift)); - } -} - static inline void inverse_adpcm(int32_t **subband_samples, const int16_t *vq_index, const int8_t *prediction_mode, int sb_start, int sb_end, int ofs, int len) { - int i, j, k; + int i, j; for (i = sb_start; i < sb_end; i++) { if (prediction_mode[i]) { - const int16_t *coeff = ff_dca_adpcm_vb[vq_index[i]]; + const int pred_id = vq_index[i]; int32_t *ptr = subband_samples[i] + ofs; for (j = 0; j < len; j++) { - int64_t err = 0; - for (k = 0; k < DCA_ADPCM_COEFFS; k++) - err += (int64_t)ptr[j - k - 1] * coeff[k]; - ptr[j] = clip23(ptr[j] + clip23(norm13(err))); + int32_t x = ff_dcaadpcm_predict(pred_id, ptr + j - DCA_ADPCM_COEFFS); + ptr[j] = clip23(ptr[j] + x); } } } @@ -817,8 +793,8 @@ static int parse_subframe_audio(DCACoreDecoder *s, int sf, enum HeaderType heade scale = clip23(adj * scale >> 22); } - dequantize(s->subband_samples[ch][band] + ofs, - audio, step_size, scale, 0); + ff_dca_core_dequantize(s->subband_samples[ch][band] + ofs, + audio, step_size, scale, 0, DCA_SUBBAND_SAMPLES); } } @@ -1146,8 +1122,8 @@ static int parse_xbr_subframe(DCACoreDecoder *s, int xbr_base_ch, int xbr_nchann else scale = xbr_scale_factors[ch][band][1]; - dequantize(s->subband_samples[ch][band] + ofs, - audio, step_size, scale, 1); + ff_dca_core_dequantize(s->subband_samples[ch][band] + ofs, + audio, step_size, scale, 1, DCA_SUBBAND_SAMPLES); } } @@ -1326,8 +1302,8 @@ static int parse_x96_subframe_audio(DCACoreDecoder *s, int sf, int xch_base, int // Get the scale factor scale = s->scale_factors[ch][band >> 1][band & 1]; - dequantize(s->x96_subband_samples[ch][band] + ofs, - audio, step_size, scale, 0); + ff_dca_core_dequantize(s->x96_subband_samples[ch][band] + ofs, + audio, step_size, scale, 0, DCA_SUBBAND_SAMPLES); } } diff --git a/libavcodec/dca_core.h b/libavcodec/dca_core.h index e84bdab18e..7dcfb13bc7 100644 --- a/libavcodec/dca_core.h +++ b/libavcodec/dca_core.h @@ -33,6 +33,7 @@ #include "dca_exss.h" #include "dcadsp.h" #include "dcadct.h" +#include "dcamath.h" #include "dcahuff.h" #include "fft.h" #include "synth_filter.h" @@ -43,7 +44,6 @@ #define DCA_SUBFRAMES 16 #define DCA_SUBBAND_SAMPLES 8 #define DCA_PCMBLOCK_SAMPLES 32 -#define DCA_ADPCM_COEFFS 4 #define DCA_LFE_HISTORY 8 #define DCA_ABITS_MAX 26 @@ -195,6 +195,29 @@ static inline int ff_dca_core_map_spkr(DCACoreDecoder *core, int spkr) return -1; } +static inline void ff_dca_core_dequantize(int32_t *output, const int32_t *input, + int32_t step_size, int32_t scale, int residual, int len) +{ + // Account for quantizer step size + int64_t step_scale = (int64_t)step_size * scale; + int n, shift = 0; + + // Limit scale factor resolution to 22 bits + if (step_scale > (1 << 23)) { + shift = av_log2(step_scale >> 23) + 1; + step_scale >>= shift; + } + + // Scale the samples + if (residual) { + for (n = 0; n < len; n++) + output[n] += clip23(norm__(input[n] * step_scale, 22 - shift)); + } else { + for (n = 0; n < len; n++) + output[n] = clip23(norm__(input[n] * step_scale, 22 - shift)); + } +} + int ff_dca_core_parse(DCACoreDecoder *s, uint8_t *data, int size); int ff_dca_core_parse_exss(DCACoreDecoder *s, uint8_t *data, DCAExssAsset *asset); int ff_dca_core_filter_fixed(DCACoreDecoder *s, int x96_synth); diff --git a/libavcodec/dcaadpcm.c b/libavcodec/dcaadpcm.c new file mode 100644 index 0000000000..8742c7ccf6 --- /dev/null +++ b/libavcodec/dcaadpcm.c @@ -0,0 +1,228 @@ +/* + * DCA ADPCM engine + * Copyright (C) 2017 Daniil Cherednik + * + * 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 "dcaadpcm.h" +#include "dcaenc.h" +#include "dca_core.h" +#include "mathops.h" + +typedef int32_t premultiplied_coeffs[10]; + +//assume we have DCA_ADPCM_COEFFS values before x +static inline int64_t calc_corr(const int32_t *x, int len, int j, int k) +{ + int n; + int64_t s = 0; + for (n = 0; n < len; n++) + s += MUL64(x[n-j], x[n-k]); + return s; +} + +static inline int64_t apply_filter(const int16_t a[DCA_ADPCM_COEFFS], const int64_t corr[15], const int32_t aa[10]) +{ + int64_t err = 0; + int64_t tmp = 0; + + err = corr[0]; + + tmp += MUL64(a[0], corr[1]); + tmp += MUL64(a[1], corr[2]); + tmp += MUL64(a[2], corr[3]); + tmp += MUL64(a[3], corr[4]); + + tmp = norm__(tmp, 13); + tmp += tmp; + + err -= tmp; + tmp = 0; + + tmp += MUL64(corr[5], aa[0]); + tmp += MUL64(corr[6], aa[1]); + tmp += MUL64(corr[7], aa[2]); + tmp += MUL64(corr[8], aa[3]); + + tmp += MUL64(corr[9], aa[4]); + tmp += MUL64(corr[10], aa[5]); + tmp += MUL64(corr[11], aa[6]); + + tmp += MUL64(corr[12], aa[7]); + tmp += MUL64(corr[13], aa[8]); + + tmp += MUL64(corr[14], aa[9]); + + tmp = norm__(tmp, 26); + + err += tmp; + + return llabs(err); +} + +static int64_t find_best_filter(const DCAADPCMEncContext *s, const int32_t *in, int len) +{ + const premultiplied_coeffs *precalc_data = s->private_data; + int i, j, k = 0; + int vq; + int64_t err; + int64_t min_err = 1ll << 62; + int64_t corr[15]; + + for (i = 0; i <= DCA_ADPCM_COEFFS; i++) + for (j = i; j <= DCA_ADPCM_COEFFS; j++) + corr[k++] = calc_corr(in+4, len, i, j); + + for (i = 0; i < DCA_ADPCM_VQCODEBOOK_SZ; i++) { + err = apply_filter(ff_dca_adpcm_vb[i], corr, *precalc_data); + if (err < min_err) { + min_err = err; + vq = i; + } + precalc_data++; + } + + return vq; +} + +static inline int64_t calc_prediction_gain(int pred_vq, const int32_t *in, int32_t *out, int len) +{ + int i; + int32_t error; + + int64_t signal_energy = 0; + int64_t error_energy = 0; + + for (i = 0; i < len; i++) { + error = in[DCA_ADPCM_COEFFS + i] - ff_dcaadpcm_predict(pred_vq, in + i); + out[i] = error; + signal_energy += MUL64(in[DCA_ADPCM_COEFFS + i], in[DCA_ADPCM_COEFFS + i]); + error_energy += MUL64(error, error); + } + + if (!error_energy) + return -1; + + return signal_energy / error_energy; +} + +int ff_dcaadpcm_subband_analysis(const DCAADPCMEncContext *s, const int32_t *in, int len, int *diff) +{ + int pred_vq, i; + int32_t input_buffer[16 + DCA_ADPCM_COEFFS]; + int32_t input_buffer2[16 + DCA_ADPCM_COEFFS]; + + int32_t max = 0; + int shift_bits; + uint64_t pg = 0; + + for (i = 0; i < len + DCA_ADPCM_COEFFS; i++) + max |= FFABS(in[i]); + + // normalize input to simplify apply_filter + shift_bits = av_log2(max) - 11; + + for (i = 0; i < len + DCA_ADPCM_COEFFS; i++) { + input_buffer[i] = norm__(in[i], 7); + input_buffer2[i] = norm__(in[i], shift_bits); + } + + pred_vq = find_best_filter(s, input_buffer2, len); + + if (pred_vq < 0) + return -1; + + pg = calc_prediction_gain(pred_vq, input_buffer, diff, len); + + // Greater than 10db (10*log(10)) prediction gain to use ADPCM. + // TODO: Tune it. + if (pg < 10) + return -1; + + for (i = 0; i < len; i++) + diff[i] <<= 7; + + return pred_vq; +} + +static void precalc(premultiplied_coeffs *data) +{ + int i, j, k; + + for (i = 0; i < DCA_ADPCM_VQCODEBOOK_SZ; i++) { + int id = 0; + int32_t t = 0; + for (j = 0; j < DCA_ADPCM_COEFFS; j++) { + for (k = j; k < DCA_ADPCM_COEFFS; k++) { + t = (int32_t)ff_dca_adpcm_vb[i][j] * (int32_t)ff_dca_adpcm_vb[i][k]; + if (j != k) + t *= 2; + (*data)[id++] = t; + } + } + data++; + } +} + +int ff_dcaadpcm_do_real(int pred_vq_index, + softfloat quant, int32_t scale_factor, int32_t step_size, + const int32_t *prev_hist, const int32_t *in, int32_t *next_hist, int32_t *out, + int len, int32_t peak) +{ + int i; + int64_t delta; + int32_t dequant_delta; + int32_t work_bufer[16 + DCA_ADPCM_COEFFS]; + + memcpy(work_bufer, prev_hist, sizeof(int32_t) * DCA_ADPCM_COEFFS); + + for (i = 0; i < len; i++) { + work_bufer[DCA_ADPCM_COEFFS + i] = ff_dcaadpcm_predict(pred_vq_index, &work_bufer[i]); + + delta = (int64_t)in[i] - ((int64_t)work_bufer[DCA_ADPCM_COEFFS + i] << 7); + + out[i] = quantize_value(av_clip64(delta, -peak, peak), quant); + + ff_dca_core_dequantize(&dequant_delta, &out[i], step_size, scale_factor, 0, 1); + + work_bufer[DCA_ADPCM_COEFFS+i] += dequant_delta; + } + + memcpy(next_hist, &work_bufer[len], sizeof(int32_t) * DCA_ADPCM_COEFFS); + + return 0; +} + +av_cold int ff_dcaadpcm_init(DCAADPCMEncContext *s) +{ + if (!s) + return -1; + + s->private_data = av_malloc(sizeof(premultiplied_coeffs) * DCA_ADPCM_VQCODEBOOK_SZ); + precalc(s->private_data); + return 0; +} + +av_cold void ff_dcaadpcm_free(DCAADPCMEncContext *s) +{ + if (!s) + return; + + av_freep(&s->private_data); +} diff --git a/libavcodec/dcaadpcm.h b/libavcodec/dcaadpcm.h new file mode 100644 index 0000000000..23bfa79636 --- /dev/null +++ b/libavcodec/dcaadpcm.h @@ -0,0 +1,54 @@ +/* + * DCA ADPCM engine + * Copyright (C) 2017 Daniil Cherednik + * + * 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 + */ + +#ifndef AVCODEC_DCAADPCM_H +#define AVCODEC_DCAADPCM_H + +#include "dcamath.h" +#include "dcadata.h" +#include "dcaenc.h" + +typedef struct DCAADPCMEncContext { + void *private_data; +} DCAADPCMEncContext; + +static inline int64_t ff_dcaadpcm_predict(int pred_vq_index, const int32_t *input) +{ + int i; + const int16_t *coeff = ff_dca_adpcm_vb[pred_vq_index]; + int64_t pred = 0; + for (i = 0; i < DCA_ADPCM_COEFFS; i++) + pred += (int64_t)input[DCA_ADPCM_COEFFS - 1 - i] * coeff[i]; + + return clip23(norm13(pred)); +} + +int ff_dcaadpcm_subband_analysis(const DCAADPCMEncContext *s, const int32_t *input, int len, int *diff); + +int ff_dcaadpcm_do_real(int pred_vq_index, + softfloat quant, int32_t scale_factor, int32_t step_size, + const int32_t *prev_hist, const int32_t *in, int32_t *next_hist, int32_t *out, + int len, int32_t peak); + +av_cold int ff_dcaadpcm_init(DCAADPCMEncContext *s); +av_cold void ff_dcaadpcm_free(DCAADPCMEncContext *s); + +#endif /* AVCODEC_DCAADPCM_H */ diff --git a/libavcodec/dcadata.c b/libavcodec/dcadata.c index 193247b18b..eaef01875a 100644 --- a/libavcodec/dcadata.c +++ b/libavcodec/dcadata.c @@ -61,7 +61,7 @@ const uint8_t ff_dca_quant_index_group_size[DCA_CODE_BOOKS] = { /* ADPCM data */ /* 16 bits signed fractional Q13 binary codes */ -const int16_t ff_dca_adpcm_vb[4096][4] = { +const int16_t ff_dca_adpcm_vb[DCA_ADPCM_VQCODEBOOK_SZ][DCA_ADPCM_COEFFS] = { { 9928, -2618, -1093, -1263 }, { 11077, -2876, -1747, -308 }, { 10503, -1082, -1426, -1167 }, diff --git a/libavcodec/dcadata.h b/libavcodec/dcadata.h index c838867bff..9dd6eba7f1 100644 --- a/libavcodec/dcadata.h +++ b/libavcodec/dcadata.h @@ -25,6 +25,9 @@ #include "dcahuff.h" +#define DCA_ADPCM_COEFFS 4 +#define DCA_ADPCM_VQCODEBOOK_SZ 4096 + extern const uint32_t ff_dca_bit_rates[32]; extern const uint8_t ff_dca_channels[16]; @@ -36,7 +39,7 @@ extern const uint8_t ff_dca_dmix_primary_nch[8]; extern const uint8_t ff_dca_quant_index_sel_nbits[DCA_CODE_BOOKS]; extern const uint8_t ff_dca_quant_index_group_size[DCA_CODE_BOOKS]; -extern const int16_t ff_dca_adpcm_vb[4096][4]; +extern const int16_t ff_dca_adpcm_vb[DCA_ADPCM_VQCODEBOOK_SZ][DCA_ADPCM_COEFFS]; extern const uint32_t ff_dca_scale_factor_quant6[64]; extern const uint32_t ff_dca_scale_factor_quant7[128]; diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index 3c5c33cda2..3af0ec1e75 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -25,8 +25,12 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/ffmath.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "dca.h" +#include "dcaadpcm.h" +#include "dcamath.h" +#include "dca_core.h" #include "dcadata.h" #include "dcaenc.h" #include "internal.h" @@ -44,8 +48,15 @@ #define SUBBAND_SAMPLES (SUBFRAMES * SUBSUBFRAMES * 8) #define AUBANDS 25 +typedef struct CompressionOptions { + int adpcm_mode; +} CompressionOptions; + typedef struct DCAEncContext { + AVClass *class; PutBitContext pb; + DCAADPCMEncContext adpcm_ctx; + CompressionOptions options; int frame_size; int frame_bits; int fullband_channels; @@ -61,10 +72,13 @@ typedef struct DCAEncContext { int32_t lfe_peak_cb; const int8_t *channel_order_tab; ///< channel reordering table, lfe and non lfe + int32_t prediction_mode[MAX_CHANNELS][DCAENC_SUBBANDS]; + int32_t adpcm_history[MAX_CHANNELS][DCAENC_SUBBANDS][DCA_ADPCM_COEFFS * 2]; int32_t history[MAX_CHANNELS][512]; /* This is a circular buffer */ - int32_t subband[MAX_CHANNELS][DCAENC_SUBBANDS][SUBBAND_SAMPLES]; + int32_t *subband[MAX_CHANNELS][DCAENC_SUBBANDS]; int32_t quantized[MAX_CHANNELS][DCAENC_SUBBANDS][SUBBAND_SAMPLES]; int32_t peak_cb[MAX_CHANNELS][DCAENC_SUBBANDS]; + int32_t diff_peak_cb[MAX_CHANNELS][DCAENC_SUBBANDS]; ///< expected peak of residual signal int32_t downsampled_lfe[DCA_LFE_SAMPLES]; int32_t masking_curve_cb[SUBSUBFRAMES][256]; int32_t bit_allocation_sel[MAX_CHANNELS]; @@ -77,6 +91,7 @@ typedef struct DCAEncContext { int32_t worst_quantization_noise; int32_t worst_noise_ever; int consumed_bits; + int consumed_adpcm_bits; ///< Number of bits to transmit ADPCM related info } DCAEncContext; static int32_t cos_table[2048]; @@ -107,18 +122,52 @@ static double gammafilter(int i, double f) return 20 * log10(h); } +static int subband_bufer_alloc(DCAEncContext *c) +{ + int ch, band; + int32_t *bufer = av_calloc(MAX_CHANNELS * DCAENC_SUBBANDS * + (SUBBAND_SAMPLES + DCA_ADPCM_COEFFS), + sizeof(int32_t)); + if (!bufer) + return -1; + + /* we need a place for DCA_ADPCM_COEFF samples from previous frame + * to calc prediction coefficients for each subband */ + for (ch = 0; ch < MAX_CHANNELS; ch++) { + for (band = 0; band < DCAENC_SUBBANDS; band++) { + c->subband[ch][band] = bufer + + ch * DCAENC_SUBBANDS * (SUBBAND_SAMPLES + DCA_ADPCM_COEFFS) + + band * (SUBBAND_SAMPLES + DCA_ADPCM_COEFFS) + DCA_ADPCM_COEFFS; + } + } + return 0; +} + +static void subband_bufer_free(DCAEncContext *c) +{ + int32_t *bufer = c->subband[0][0] - DCA_ADPCM_COEFFS; + av_freep(&bufer); +} + static int encode_init(AVCodecContext *avctx) { DCAEncContext *c = avctx->priv_data; uint64_t layout = avctx->channel_layout; int i, j, min_frame_bits; + if (subband_bufer_alloc(c)) + return AVERROR(ENOMEM); + c->fullband_channels = c->channels = avctx->channels; c->lfe_channel = (avctx->channels == 3 || avctx->channels == 6); c->band_interpolation = band_interpolation[1]; c->band_spectrum = band_spectrum[1]; c->worst_quantization_noise = -2047; c->worst_noise_ever = -2047; + c->consumed_adpcm_bits = 0; + + if (ff_dcaadpcm_init(&c->adpcm_ctx)) + return AVERROR(ENOMEM); if (!layout) { av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The " @@ -150,6 +199,12 @@ static int encode_init(AVCodecContext *avctx) } /* 6 - no Huffman */ c->bit_allocation_sel[i] = 6; + + for (j = 0; j < DCAENC_SUBBANDS; j++) { + /* -1 - no ADPCM */ + c->prediction_mode[i][j] = -1; + memset(c->adpcm_history[i][j], 0, sizeof(int32_t)*DCA_ADPCM_COEFFS); + } } for (i = 0; i < 9; i++) { @@ -238,6 +293,16 @@ static int encode_init(AVCodecContext *avctx) return 0; } +static av_cold int encode_close(AVCodecContext *avctx) +{ + if (avctx->priv_data) { + DCAEncContext *c = avctx->priv_data; + subband_bufer_free(c); + ff_dcaadpcm_free(&c->adpcm_ctx); + } + return 0; +} + static inline int32_t cos_t(int x) { return cos_table[x & 2047]; @@ -253,12 +318,6 @@ static inline int32_t half32(int32_t a) return (a + 1) >> 1; } -static inline int32_t mul32(int32_t a, int32_t b) -{ - int64_t r = (int64_t)a * b + 0x80000000ULL; - return r >> 32; -} - static void subband_transform(DCAEncContext *c, const int32_t *input) { int ch, subs, i, k, j; @@ -545,31 +604,53 @@ static void calc_masking(DCAEncContext *c, const int32_t *input) } } +static inline int32_t find_peak(const int32_t *in, int len) { + int sample; + int32_t m = 0; + for (sample = 0; sample < len; sample++) { + int32_t s = abs(in[sample]); + if (m < s) { + m = s; + } + } + return get_cb(m); +} + static void find_peaks(DCAEncContext *c) { int band, ch; - for (ch = 0; ch < c->fullband_channels; ch++) + for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { - int sample; - int32_t m = 0; - - for (sample = 0; sample < SUBBAND_SAMPLES; sample++) { - int32_t s = abs(c->subband[ch][band][sample]); - if (m < s) - m = s; - } - c->peak_cb[ch][band] = get_cb(m); + c->peak_cb[ch][band] = find_peak(c->subband[ch][band], SUBBAND_SAMPLES); } + } if (c->lfe_channel) { - int sample; - int32_t m = 0; + c->lfe_peak_cb = find_peak(c->downsampled_lfe, DCA_LFE_SAMPLES); + } +} + +static void adpcm_analysis(DCAEncContext *c) +{ + int ch, band; + int pred_vq_id; + int32_t *samples; + int32_t estimated_diff[SUBBAND_SAMPLES]; - for (sample = 0; sample < DCA_LFE_SAMPLES; sample++) - if (m < abs(c->downsampled_lfe[sample])) - m = abs(c->downsampled_lfe[sample]); - c->lfe_peak_cb = get_cb(m); + c->consumed_adpcm_bits = 0; + for (ch = 0; ch < c->fullband_channels; ch++) { + for (band = 0; band < 32; band++) { + samples = c->subband[ch][band] - DCA_ADPCM_COEFFS; + pred_vq_id = ff_dcaadpcm_subband_analysis(&c->adpcm_ctx, samples, SUBBAND_SAMPLES, estimated_diff); + if (pred_vq_id >= 0) { + c->prediction_mode[ch][band] = pred_vq_id; + c->consumed_adpcm_bits += 12; //12 bits to transmit prediction vq index + c->diff_peak_cb[ch][band] = find_peak(estimated_diff, 16); + } else { + c->prediction_mode[ch][band] = -1; + } + } } } @@ -578,13 +659,16 @@ static const int snr_fudge = 128; #define USED_NABITS 2 #define USED_26ABITS 4 -static int32_t quantize_value(int32_t value, softfloat quant) +static inline int32_t get_step_size(const DCAEncContext *c, int ch, int band) { - int32_t offset = 1 << (quant.e - 1); + int32_t step_size; - value = mul32(value, quant.m) + offset; - value = value >> quant.e; - return value; + if (c->bitrate_index == 3) + step_size = ff_dca_lossless_quant[c->abits[ch][band]]; + else + step_size = ff_dca_lossy_quant[c->abits[ch][band]]; + + return step_size; } static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) @@ -619,14 +703,40 @@ static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) return our_nscale; } -static void quantize_all(DCAEncContext *c) +static inline void quantize_adpcm_subband(DCAEncContext *c, int ch, int band) +{ + int32_t step_size; + int32_t diff_peak_cb = c->diff_peak_cb[ch][band]; + c->scale_factor[ch][band] = calc_one_scale(diff_peak_cb, + c->abits[ch][band], + &c->quant[ch][band]); + + step_size = get_step_size(c, ch, band); + ff_dcaadpcm_do_real(c->prediction_mode[ch][band], + c->quant[ch][band], ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], step_size, + c->adpcm_history[ch][band], c->subband[ch][band], c->adpcm_history[ch][band]+4, c->quantized[ch][band], + SUBBAND_SAMPLES, cb_to_level[-diff_peak_cb]); +} + +static void quantize_adpcm(DCAEncContext *c) +{ + int band, ch; + + for (ch = 0; ch < c->fullband_channels; ch++) + for (band = 0; band < 32; band++) + if (c->prediction_mode[ch][band] >= 0) + quantize_adpcm_subband(c, ch, band); +} + +static void quantize_pcm(DCAEncContext *c) { int sample, band, ch; for (ch = 0; ch < c->fullband_channels; ch++) for (band = 0; band < 32; band++) - for (sample = 0; sample < SUBBAND_SAMPLES; sample++) - c->quantized[ch][band][sample] = quantize_value(c->subband[ch][band][sample], c->quant[ch][band]); + if (c->prediction_mode[ch][band] == -1) + for (sample = 0; sample < SUBBAND_SAMPLES; sample++) + c->quantized[ch][band][sample] = quantize_value(c->subband[ch][band][sample], c->quant[ch][band]); } static void accumulate_huff_bit_consumption(int abits, int32_t *quantized, uint32_t *result) @@ -710,6 +820,7 @@ static int init_quantization_noise(DCAEncContext *c, int noise) uint32_t bits_counter = 0; c->consumed_bits = 132 + 333 * c->fullband_channels; + c->consumed_bits += c->consumed_adpcm_bits; if (c->lfe_channel) c->consumed_bits += 72; @@ -740,12 +851,15 @@ static int init_quantization_noise(DCAEncContext *c, int noise) /* TODO: May be cache scaled values */ for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { - c->scale_factor[ch][band] = calc_one_scale(c->peak_cb[ch][band], - c->abits[ch][band], - &c->quant[ch][band]); + if (c->prediction_mode[ch][band] == -1) { + c->scale_factor[ch][band] = calc_one_scale(c->peak_cb[ch][band], + c->abits[ch][band], + &c->quant[ch][band]); + } } } - quantize_all(c); + quantize_adpcm(c); + quantize_pcm(c); memset(huff_bit_count_accum, 0, MAX_CHANNELS * DCA_CODE_BOOKS * 7 * sizeof(uint32_t)); memset(clc_bit_count_accum, 0, MAX_CHANNELS * DCA_CODE_BOOKS * sizeof(uint32_t)); @@ -819,6 +933,41 @@ static void shift_history(DCAEncContext *c, const int32_t *input) } } +static void fill_in_adpcm_bufer(DCAEncContext *c) +{ + int ch, band; + int32_t step_size; + /* We fill in ADPCM work buffer for subbands which hasn't been ADPCM coded + * in current frame - we need this data if subband of next frame is + * ADPCM + */ + for (ch = 0; ch < c->channels; ch++) { + for (band = 0; band < 32; band++) { + int32_t *samples = c->subband[ch][band] - DCA_ADPCM_COEFFS; + if (c->prediction_mode[ch][band] == -1) { + step_size = get_step_size(c, ch, band); + + ff_dca_core_dequantize(c->adpcm_history[ch][band], + c->quantized[ch][band]+12, step_size, ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], 0, 4); + } else { + AV_COPY128U(c->adpcm_history[ch][band], c->adpcm_history[ch][band]+4); + } + /* Copy dequantized values for LPC analysis. + * It reduces artifacts in case of extreme quantization, + * example: in current frame abits is 1 and has no prediction flag, + * but end of this frame is sine like signal. In this case, if LPC analysis uses + * original values, likely LPC analysis returns good prediction gain, and sets prediction flag. + * But there are no proper value in decoder history, so likely result will be no good. + * Bitstream has "Predictor history flag switch", but this flag disables history for all subbands + */ + samples[0] = c->adpcm_history[ch][band][0] << 7; + samples[1] = c->adpcm_history[ch][band][1] << 7; + samples[2] = c->adpcm_history[ch][band][2] << 7; + samples[3] = c->adpcm_history[ch][band][3] << 7; + } + } +} + static void calc_lfe_scales(DCAEncContext *c) { if (c->lfe_channel) @@ -1001,9 +1150,14 @@ static void put_subframe(DCAEncContext *c, int subframe) /* Prediction mode: no ADPCM, in each channel and subband */ for (ch = 0; ch < c->fullband_channels; ch++) for (band = 0; band < DCAENC_SUBBANDS; band++) - put_bits(&c->pb, 1, 0); + put_bits(&c->pb, 1, !(c->prediction_mode[ch][band] == -1)); + + /* Prediction VQ address */ + for (ch = 0; ch < c->fullband_channels; ch++) + for (band = 0; band < DCAENC_SUBBANDS; band++) + if (c->prediction_mode[ch][band] >= 0) + put_bits(&c->pb, 12, c->prediction_mode[ch][band]); - /* Prediction VQ address: not transmitted */ /* Bit allocation index */ for (ch = 0; ch < c->fullband_channels; ch++) { if (c->bit_allocation_sel[ch] == 6) { @@ -1068,12 +1222,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt, lfe_downsample(c, samples); calc_masking(c, samples); + if (c->options.adpcm_mode) + adpcm_analysis(c); find_peaks(c); assign_bits(c); calc_lfe_scales(c); shift_history(c, samples); init_put_bits(&c->pb, avpkt->data, avpkt->size); + fill_in_adpcm_bufer(c); put_frame_header(c); put_primary_audio_header(c); for (i = 0; i < SUBFRAMES; i++) @@ -1092,6 +1249,20 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt, return 0; } +#define DCAENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM + +static const AVOption options[] = { + { "dca_adpcm", "Use ADPCM encoding", offsetof(DCAEncContext, options.adpcm_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DCAENC_FLAGS }, + { NULL }, +}; + +static const AVClass dcaenc_class = { + .class_name = "DCA (DTS Coherent Acoustics)", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + static const AVCodecDefault defaults[] = { { "b", "1411200" }, { NULL }, @@ -1104,6 +1275,7 @@ AVCodec ff_dca_encoder = { .id = AV_CODEC_ID_DTS, .priv_data_size = sizeof(DCAEncContext), .init = encode_init, + .close = encode_close, .encode2 = encode_frame, .capabilities = AV_CODEC_CAP_EXPERIMENTAL, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, @@ -1116,4 +1288,5 @@ AVCodec ff_dca_encoder = { AV_CH_LAYOUT_5POINT1, 0 }, .defaults = defaults, + .priv_class = &dcaenc_class, }; diff --git a/libavcodec/dcaenc.h b/libavcodec/dcaenc.h index 06816c233d..63fdaf074e 100644 --- a/libavcodec/dcaenc.h +++ b/libavcodec/dcaenc.h @@ -24,6 +24,8 @@ #include <stdint.h> +#include "dcamath.h" + typedef struct { int32_t m; int32_t e; @@ -144,4 +146,13 @@ static const int8_t channel_reorder_nolfe[16][9] = { { 3, 2, 4, 0, 1, 5, 7, 6, -1 }, }; +static inline int32_t quantize_value(int32_t value, softfloat quant) +{ + int32_t offset = 1 << (quant.e - 1); + + value = mul32(value, quant.m) + offset; + value = value >> quant.e; + return value; +} + #endif /* AVCODEC_DCAENC_H */ diff --git a/libavcodec/dcamath.h b/libavcodec/dcamath.h index e0d6f4fdaa..38fa9a6235 100644 --- a/libavcodec/dcamath.h +++ b/libavcodec/dcamath.h @@ -49,6 +49,7 @@ static inline int32_t mul17(int32_t a, int32_t b) { return mul__(a, b, 17); } static inline int32_t mul22(int32_t a, int32_t b) { return mul__(a, b, 22); } static inline int32_t mul23(int32_t a, int32_t b) { return mul__(a, b, 23); } static inline int32_t mul31(int32_t a, int32_t b) { return mul__(a, b, 31); } +static inline int32_t mul32(int32_t a, int32_t b) { return mul__(a, b, 32); } static inline int32_t clip23(int32_t a) { return av_clip_intp2(a, 23); } |