---
This is an updated patch which removes some unrelated hunks and also makes it
easier to add block switching support to the ac3_fixed encoder once we have
a fixed-point iir filter.
Still depends on the channel coupling patch.
doc/encoders.texi | 7 +
libavcodec/ac3enc.c | 297 +++++++++++++++++++++++++++++++++++++++++++-
libavcodec/ac3enc_fixed.c | 4 +-
libavcodec/ac3enc_float.c | 24 +++-
libavcodec/iirfilter.c | 6 +
libavcodec/iirfilter.h | 10 ++
6 files changed, 336 insertions(+), 12 deletions(-)
diff --git a/doc/encoders.texi b/doc/encoders.texi
index 3f6b4c9..aa3871a 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -357,6 +357,13 @@ HDCD A/D Converter
@table @option
+@item -block_switching @var{boolean}
+Block Switching. Enables/Disables switching from long blocks to short blocks
+based on transient detection. This allows the encoder to determine when it is
+best to use short blocks for transient signals. This option is enabled by
+default, and it is recommended that it be left as enabled except for testing
+purposes or to increase encoding speed.
+
@item -stereo_rematrixing @var{boolean}
Stereo Rematrixing. Enables/Disables use of rematrixing for stereo input. This
is an optional AC-3 feature that increases quality by selectively encoding
diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c
index f09fdf6..c65d74b 100644
--- a/libavcodec/ac3enc.c
+++ b/libavcodec/ac3enc.c
@@ -42,6 +42,7 @@
#include "ac3.h"
#include "audioconvert.h"
#include "fft.h"
+#include "iirfilter.h"
#ifndef CONFIG_AC3ENC_FLOAT
@@ -66,7 +67,9 @@ typedef int64_t CoefSumType;
typedef struct AC3MDCTContext {
const SampleType *window; ///< MDCT window function
- FFTContext fft; ///< FFT context for MDCT calculation
+ SampleType *rot_tmp; ///< temp buffer for pre-rotated samples
+ CoefType *coef_tmp; ///< temp buffer for 256-point MDCT coefs
+ FFTContext fft[2]; ///< FFT context for MDCT calculation
} AC3MDCTContext;
/**
@@ -97,6 +100,7 @@ typedef struct AC3EncOptions {
/* other encoding options */
int allow_per_frame_metadata;
+ int block_switching;
int stereo_rematrixing;
int channel_coupling;
int cpl_start;
@@ -117,6 +121,7 @@ typedef struct AC3Block {
uint16_t **qmant; ///< quantized mantissas
uint8_t **cpl_coord_exp; ///< coupling coord exponents (cplcoexp)
uint8_t **cpl_coord_mant; ///< coupling coord mantissas (cplcomant)
+ uint8_t blk_switch[AC3_MAX_CHANNELS][2]; ///< block switch flags [0]=current [1]=previous
uint8_t coeff_shift[AC3_MAX_CHANNELS]; ///< fixed-point coefficient shift values
uint8_t new_rematrixing_strategy; ///< send new rematrixing flags in this block
int num_rematrixing_bands; ///< number of rematrixing bands
@@ -180,6 +185,11 @@ typedef struct AC3EncodeContext {
int start_freq[AC3_MAX_CHANNELS]; ///< start frequency bin (strtmant)
int cpl_end_freq; ///< coupling channel end frequency bin
+ int blksw_enabled; ///< block switching enabled
+ struct FFIIRFilterCoeffs *blksw_coefs; ///< block switch filter coefficients
+ struct FFIIRFilterState *blksw_state[2][AC3_MAX_CHANNELS]; /// block switch filter states
+ struct FFIIRFilterState *temp_state; ///< block switch filter temp state
+
int cpl_on; ///< coupling turned on for this frame
int cpl_enabled; ///< coupling enabled for all frames
int num_cpl_subbands; ///< number of coupling subbands (ncplsubnd)
@@ -202,6 +212,7 @@ typedef struct AC3EncodeContext {
int exponent_bits; ///< number of bits used for exponents
SampleType **planar_samples;
+ SampleType *filtered_samples;
uint8_t *bap_buffer;
uint8_t *bap1_buffer;
CoefType *mdct_coef_buffer;
@@ -286,6 +297,7 @@ static const AVOption options[] = {
{"standard", "Standard (default)", 0, FF_OPT_TYPE_CONST, 0, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"},
{"hdcd", "HDCD", 0, FF_OPT_TYPE_CONST, 1, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"},
/* Other Encoding Options */
+{"block_switching", "Block Switching", OFFSET(block_switching), FF_OPT_TYPE_INT, 1, 0, 1, AC3ENC_PARAM},
{"stereo_rematrixing", "Stereo Rematrixing", OFFSET(stereo_rematrixing), FF_OPT_TYPE_INT, 1, 0, 1, AC3ENC_PARAM},
{"channel_coupling", "Channel Coupling", OFFSET(channel_coupling), FF_OPT_TYPE_INT, 1, 0, 1, AC3ENC_PARAM, "channel_coupling"},
{"auto", "Selected by the Encoder", 0, FF_OPT_TYPE_CONST, -1, INT_MIN, INT_MAX, AC3ENC_PARAM, "channel_coupling"},
@@ -471,6 +483,237 @@ static void deinterleave_input_samples(AC3EncodeContext *s,
/**
+ * Uninitialize block switching.
+ */
+static av_cold void block_switch_end(AC3EncodeContext *s)
+{
+/* block switching is not done for the fixed-point encoder because we do not
+ currently have a fixed-point IIR filter */
+#if CONFIG_AC3ENC_FLOAT
+ int ch;
+ ff_iir_filter_free_coeffs(s->blksw_coefs);
+ ff_iir_filter_free_state(s->temp_state);
+ for (ch = 0; ch < s->fbw_channels; ch++) {
+ ff_iir_filter_free_state(s->blksw_state[0][ch]);
+ ff_iir_filter_free_state(s->blksw_state[1][ch]);
+ }
+#endif
+}
+
+
+/**
+ * Initialize block switching.
+ */
+static av_cold int block_switch_init(AVCodecContext *avctx, AC3EncodeContext *s)
+{
+/* block switching is not done for the fixed-point encoder because we do not
+ currently have a fixed-point IIR filter */
+#if CONFIG_AC3ENC_FLOAT
+ int ch;
+
+ /* initialize high-pass filter with cutoff of 8kHz */
+ s->blksw_coefs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BIQUAD,
+ FF_FILTER_MODE_HIGHPASS, 2,
+ 2.0 * 8000.0 / s->sample_rate,
+ 0, 0);
+
+ if (!s->blksw_coefs)
+ return -1;
+
+ s->temp_state = ff_iir_filter_init_state(2);
+ if (!s->temp_state) {
+ block_switch_end(s);
+ return AVERROR(ENOMEM);
+ }
+ for (ch = 0; ch < s->fbw_channels; ch++) {
+ s->blksw_state[0][ch] = ff_iir_filter_init_state(2);
+ s->blksw_state[1][ch] = ff_iir_filter_init_state(2);
+ if (!s->blksw_state[0][ch] || !s->blksw_state[1][ch]) {
+ block_switch_end(s);
+ return AVERROR(ENOMEM);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+/**
+ * Find the maximum magnitude in an array of samples.
+ */
+static float sample_absmax(const SampleType *src, int n)
+{
+ SampleType max = 0;
+ n--;
+ while (n >= 0) {
+ SampleType v = FFABS(src[n]);
+ if (v > max)
+ max = v;
+ n--;
+ }
+ return max;
+}
+
+
+/**
+ * Build tree of peak magnitudes for each segment in 3 levels of time division.
+ * level 1 = 256 samples x 1
+ * level 2 = 128 samples x 2
+ * level 3 = 64 samples x 4
+ */
+static inline void build_peak_tree(const SampleType *src,
+ SampleType peak_tree[10])
+{
+ /* level 3 peak values */
+ peak_tree[6] = sample_absmax(src , 64);
+ peak_tree[7] = sample_absmax(src + 64, 64);
+ peak_tree[8] = sample_absmax(src + 128, 64);
+ peak_tree[9] = sample_absmax(src + 192, 64);
+ /* level 2 peak values */
+ peak_tree[4] = FFMAX(peak_tree[8], peak_tree[9]);
+ peak_tree[3] = FFMAX(peak_tree[6], peak_tree[7]);
+ /* level 1 peak value */
+ peak_tree[1] = FFMAX(peak_tree[3], peak_tree[4]);
+}
+
+
+/**
+ * Saves last segment of each level for comparison with the first segment in
+ * each level in the next block.
+ */
+static inline void save_peak_tree(SampleType peak_tree[10])
+{
+ peak_tree[5] = peak_tree[9];
+ peak_tree[2] = peak_tree[4];
+ peak_tree[0] = peak_tree[1];
+}
+
+
+#if CONFIG_AC3ENC_FLOAT
+#define SILENCE_THRESHOLD 0.0030517578125f
+#define LVL1_THRESHOLD 0.100f
+#define LVL2_THRESHOLD 0.075f
+#define LVL3_THRESHOLD 0.050f
+#else
+#define SILENCE_THRESHOLD 100
+#define LVL1_THRESHOLD 3277
+#define LVL2_THRESHOLD 2458
+#define LVL3_THRESHOLD 1638
+#endif
+
+/**
+ * Detect transients to determine block switching flags.
+ */
+static void block_switch_detection(AC3EncodeContext *s)
+{
+ int ch, blk;
+ int av_unused(i);
+ const SampleType *input_samples;
+ SampleType peak_tree[10] = {0,};
+
+ /* block switching is not done for the fixed-point encoder because we do
+ not currently have a fixed-point IIR filter */
+ av_assert0(CONFIG_AC3ENC_FLOAT);
+
+ for (ch = 0; ch < s->fbw_channels; ch++) {
+ /* filter input samples, cascaded biquad high-pass @ 8kHz */
+ input_samples = s->planar_samples[ch];
+#if CONFIG_AC3ENC_FLOAT
+ for (i = 0; i < 2; i++) {
+ SampleType *output_samples = s->filtered_samples;
+
+ ff_iir_filter_flt(s->blksw_coefs, s->blksw_state[i][ch], AC3_FRAME_SIZE,
+ input_samples, 1, output_samples, 1);
+ input_samples += AC3_FRAME_SIZE;
+ output_samples += AC3_FRAME_SIZE;
+ ff_iir_filter_copy_state(s->temp_state, s->blksw_state[i][ch], 2);
+ ff_iir_filter_flt(s->blksw_coefs, s->temp_state, AC3_BLOCK_SIZE,
+ input_samples, 1, output_samples, 1);
+
+ input_samples = s->filtered_samples;
+ }
+#endif
+
+ /* first half of first block */
+ build_peak_tree(input_samples, peak_tree);
+ save_peak_tree(peak_tree);
+ input_samples += AC3_BLOCK_SIZE;
+
+ /* second half of each block */
+ for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
+ AC3Block *block = &s->blocks[blk];
+
+ /* set current block flag */
+ build_peak_tree(input_samples, peak_tree);
+ block->blk_switch[ch][0] = 0;
+ if (peak_tree[1] > SILENCE_THRESHOLD &&
+ (((peak_tree[1] * LVL1_THRESHOLD) > peak_tree[0]) ||
+ ((peak_tree[3] * LVL2_THRESHOLD) > peak_tree[2]) ||
+ ((peak_tree[4] * LVL2_THRESHOLD) > peak_tree[3]) ||
+ ((peak_tree[6] * LVL3_THRESHOLD) > peak_tree[5]) ||
+ ((peak_tree[7] * LVL3_THRESHOLD) > peak_tree[6]) ||
+ ((peak_tree[8] * LVL3_THRESHOLD) > peak_tree[7]) ||
+ ((peak_tree[9] * LVL3_THRESHOLD) > peak_tree[8]))) {
+ block->blk_switch[ch][0] = 1;
+ }
+ save_peak_tree(peak_tree);
+
+ /* set previous block flag */
+ block->blk_switch[ch][1] = 0;
+ if (!blk)
+ block->blk_switch[ch][1] = s->blocks[5].blk_switch[ch][0];
+ else
+ block->blk_switch[ch][1] = s->blocks[blk-1].blk_switch[ch][0];
+
+ input_samples += AC3_BLOCK_SIZE;
+ }
+ }
+}
+
+
+/**
+ * Calculate two 256-point MDCTs
+ * @param out 256 output frequency coefficients
+ * @param in 512 windowed input audio samples
+ */
+static void mdct256(AC3MDCTContext *mdct, CoefType *out, const SampleType *in)
+{
+/* block switching is not done for the fixed-point encoder because we do not
+ currently have a fixed-point IIR filter */
+#if CONFIG_AC3ENC_FLOAT
+ CoefType *coef_a = mdct->coef_tmp;
+ CoefType *coef_b = mdct->coef_tmp + 128;
+ SampleType *rot = mdct->rot_tmp;
+ int i;
+
+ /* part 1 pre-rotation (-N/4) */
+ memcpy(rot, in+64, 192 * sizeof(*in));
+ for (i = 0; i < 64; i++)
+ rot[i+192] = -in[i];
+
+ /* part 1 MDCT */
+ mdct->fft[1].mdct_calcw(&mdct->fft[1], coef_a, rot);
+
+ /* part 2 pre-rotation (N/4) */
+ in += 256;
+ for (i = 0; i < 64; i++)
+ rot[i] = -in[i+192];
+ memcpy(rot+64, in, 192 * sizeof(*in));
+
+ /* part 2 MDCT */
+ mdct->fft[1].mdct_calcw(&mdct->fft[1], coef_b, rot);
+
+ /* coefficient interleaving */
+ for (i = 0; i < 128; i++) {
+ out[2*i ] = coef_a[i];
+ out[2*i+1] = coef_b[i];
+ }
+#endif
+}
+
+
+/**
* Apply the MDCT to input samples to generate frequency coefficients.
* This applies the KBD window and normalizes the input to reduce precision
* loss due to fixed-point calculations.
@@ -488,8 +731,13 @@ static void apply_mdct(AC3EncodeContext *s)
block->coeff_shift[ch+1] = normalize_samples(s);
- s->mdct.fft.mdct_calcw(&s->mdct.fft, block->mdct_coef[ch+1],
- s->windowed_samples);
+ if (block->blk_switch[ch][0]) {
+ mdct256(&s->mdct, block->mdct_coef[ch+1], s->windowed_samples);
+ } else {
+ s->mdct.fft[0].mdct_calcw(&s->mdct.fft[0],
+ block->mdct_coef[ch+1],
+ s->windowed_samples);
+ }
}
}
}
@@ -504,7 +752,8 @@ static void compute_coupling_strategy(AC3EncodeContext *s)
for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
AC3Block *block = &s->blocks[blk];
for (ch = 1; ch <= s->fbw_channels; ch++)
- block->channel_in_cpl[ch] = s->cpl_on;
+ block->channel_in_cpl[ch] = s->cpl_on &&
+ !(block->blk_switch[ch-1][0] || block->blk_switch[ch-1][1]);
}
/* enable coupling for each block if at least 2 channels have coupling
@@ -628,6 +877,11 @@ static void apply_channel_coupling(AC3EncodeContext *s)
new_coords = 1;
last_coord_blk = blk;
}
+ /* for stereo, encode coordinates more often */
+ if (s->fbw_channels == 2 && blk > 2 && last_coord_blk < (blk-2)) {
+ new_coords = 1;
+ last_coord_blk = blk;
+ }
}
s->blocks[blk].new_cpl_coords = new_coords;
}
@@ -892,6 +1146,8 @@ static void compute_exp_strategy(AC3EncodeContext *s)
exp_strategy[blk] = EXP_NEW;
else if (ch > CPL_CH && exp_diff > EXP_DIFF_THRESHOLD)
exp_strategy[blk] = EXP_NEW;
+ if (ch > CPL_CH && s->blocks[blk].blk_switch[ch-1][0] || s->blocks[blk].blk_switch[ch-1][1])
+ exp_strategy[blk] = EXP_NEW;
}
/* now select the encoding strategy type : if exponents are often
@@ -901,12 +1157,16 @@ static void compute_exp_strategy(AC3EncodeContext *s)
blk1 = blk + 1;
while (blk1 < AC3_MAX_BLOCKS && exp_strategy[blk1] == EXP_REUSE)
blk1++;
+ if (ch > CPL_CH && s->blocks[blk].blk_switch[ch-1][0] || s->blocks[blk].blk_switch[ch-1][1]) {
+ exp_strategy[blk] = EXP_D45;
+ } else {
switch (blk1 - blk) {
case 1: exp_strategy[blk] = EXP_D45; break;
case 2:
case 3: exp_strategy[blk] = EXP_D25; break;
default: exp_strategy[blk] = EXP_D15; break;
}
+ }
blk = blk1;
}
}
@@ -1752,11 +2012,14 @@ static void output_audio_block(AC3EncodeContext *s, int blk)
/* block switching */
for (ch = 0; ch < s->fbw_channels; ch++)
- put_bits(&s->pb, 1, 0);
+ put_bits(&s->pb, 1, block->blk_switch[ch][0]);
/* dither flags */
- for (ch = 0; ch < s->fbw_channels; ch++)
- put_bits(&s->pb, 1, 1);
+ for (ch = 0; ch < s->fbw_channels; ch++) {
+ /* disable zero-bit dithering for each short block and the next block */
+ int dith_flag = !(block->blk_switch[ch][0] || block->blk_switch[ch][1]);
+ put_bits(&s->pb, 1, dith_flag);
+ }
/* dynamic range codes */
put_bits(&s->pb, 1, 0);
@@ -2281,6 +2544,9 @@ static int ac3_encode_frame(AVCodecContext *avctx, unsigned char *frame,
deinterleave_input_samples(s, samples);
+ if (s->blksw_enabled)
+ block_switch_detection(s);
+
apply_mdct(s);
s->cpl_on = s->cpl_enabled;
@@ -2324,6 +2590,7 @@ static av_cold int ac3_encode_close(AVCodecContext *avctx)
for (ch = 0; ch < s->channels; ch++)
av_freep(&s->planar_samples[ch]);
av_freep(&s->planar_samples);
+ av_freep(&s->filtered_samples);
av_freep(&s->bap_buffer);
av_freep(&s->bap1_buffer);
av_freep(&s->mdct_coef_buffer);
@@ -2349,6 +2616,8 @@ static av_cold int ac3_encode_close(AVCodecContext *avctx)
mdct_end(&s->mdct);
+ block_switch_end(s);
+
av_freep(&avctx->coded_frame);
return 0;
}
@@ -2471,6 +2740,8 @@ static av_cold int validate_options(AVCodecContext *avctx, AC3EncodeContext *s)
if (ret)
return ret;
+ s->blksw_enabled = s->options.block_switching && CONFIG_AC3ENC_FLOAT;
+
s->rematrixing_enabled = s->options.stereo_rematrixing &&
(s->channel_mode == AC3_CHMODE_STEREO);
@@ -2591,6 +2862,14 @@ static av_cold int allocate_buffers(AVCodecContext *avctx)
FF_ALLOC_OR_GOTO(avctx, s->cpl_coord_mant_buffer, AC3_MAX_BLOCKS * channels *
16 * sizeof(*s->cpl_coord_mant_buffer), alloc_fail);
}
+ if (s->blksw_enabled) {
+ /* block switching is not done for the fixed-point encoder because we
+ do not currently have a fixed-point IIR filter */
+ av_assert0(CONFIG_AC3ENC_FLOAT);
+ FF_ALLOCZ_OR_GOTO(avctx, s->filtered_samples,
+ (AC3_FRAME_SIZE+AC3_BLOCK_SIZE) *
+ sizeof(*s->filtered_samples), alloc_fail);
+ }
for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
AC3Block *block = &s->blocks[blk];
FF_ALLOC_OR_GOTO(avctx, block->bap, channels * sizeof(*block->bap),
@@ -2696,6 +2975,10 @@ static av_cold int ac3_encode_init(AVCodecContext *avctx)
set_bandwidth(s);
+ ret = block_switch_init(avctx, s);
+ if (ret)
+ goto init_fail;
+
exponent_init(s);
bit_alloc_init(s);
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index ff24f8d..6a9cd7f 100644
--- a/libavcodec/ac3enc_fixed.c
+++ b/libavcodec/ac3enc_fixed.c
@@ -36,7 +36,7 @@
*/
static av_cold void mdct_end(AC3MDCTContext *mdct)
{
- ff_fft_end(&mdct->fft);
+ ff_fft_end(&mdct->fft[0]);
}
@@ -47,7 +47,7 @@ static av_cold void mdct_end(AC3MDCTContext *mdct)
static av_cold int mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct,
int nbits)
{
- int ret = ff_mdct_init(&mdct->fft, nbits, 0, 1.0);
+ int ret = ff_mdct_init(&mdct->fft[0], nbits, 0, 1.0);
mdct->window = ff_ac3_window;
return ret;
}
diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c
index 3a438c2..717750d 100644
--- a/libavcodec/ac3enc_float.c
+++ b/libavcodec/ac3enc_float.c
@@ -36,7 +36,10 @@
*/
static av_cold void mdct_end(AC3MDCTContext *mdct)
{
- ff_mdct_end(&mdct->fft);
+ av_freep(&mdct->rot_tmp);
+ av_freep(&mdct->coef_tmp);
+ ff_mdct_end(&mdct->fft[0]);
+ ff_mdct_end(&mdct->fft[1]);
av_freep(&mdct->window);
}
@@ -49,7 +52,7 @@ static av_cold int mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct,
int nbits)
{
float *window;
- int i, n, n2;
+ int i, n, n2, ret;
n = 1 << nbits;
n2 = n >> 1;
@@ -64,7 +67,22 @@ static av_cold int mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct,
window[n-1-i] = window[i];
mdct->window = window;
- return ff_mdct_init(&mdct->fft, nbits, 0, -2.0 / n);
+ FF_ALLOC_OR_GOTO(avctx, mdct->rot_tmp, n2 * sizeof(*mdct->rot_tmp),
+ mdct_alloc_fail);
+ FF_ALLOC_OR_GOTO(avctx, mdct->coef_tmp, n2 * sizeof(*mdct->coef_tmp),
+ mdct_alloc_fail);
+
+ ret = ff_mdct_init(&mdct->fft[0], nbits, 0, -2.0 / n) ||
+ ff_mdct_init(&mdct->fft[1], nbits-1, 0, -2.0 / n2);
+ if (ret) {
+ mdct_end(mdct);
+ return ret;
+ }
+
+ return 0;
+mdct_alloc_fail:
+ mdct_end(mdct);
+ return AVERROR(ENOMEM);
}
diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c
index 56d17d2..2d12551 100644
--- a/libavcodec/iirfilter.c
+++ b/libavcodec/iirfilter.c
@@ -205,6 +205,12 @@ av_cold struct FFIIRFilterState* ff_iir_filter_init_state(int order)
return s;
}
+void ff_iir_filter_copy_state(struct FFIIRFilterState *dst,
+ struct FFIIRFilterState *src, int order)
+{
+ memcpy(dst, src, sizeof(FFIIRFilterState) + sizeof(src->x[0]) * (order - 1));
+}
+
#define CONV_S16(dest, source) dest = av_clip_int16(lrintf(source));
#define CONV_FLT(dest, source) dest = source;
diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h
index bc65a96..5ead44a 100644
--- a/libavcodec/iirfilter.h
+++ b/libavcodec/iirfilter.h
@@ -77,6 +77,16 @@ struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc,
struct FFIIRFilterState* ff_iir_filter_init_state(int order);
/**
+ * Copy filter state.
+ *
+ * @param dst destination state
+ * @param src source state
+ * @param order filter order
+ */
+void ff_iir_filter_copy_state(struct FFIIRFilterState *dst,
+ struct FFIIRFilterState *src, int order);
+
+/**
* Free filter coefficients.
*
* @param coeffs pointer allocated with ff_iir_filter_init_coeffs()
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel