Go to the documentation of this file.
40 #define MAX_BANDS MAX_SPLITS + 1
84 #define OFFSET(x) offsetof(AudioCrossoverContext, x)
85 #define AF AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
98 {
"18th",
"18th order (108 dB/8ve)",0,
AV_OPT_TYPE_CONST, {.i64=8}, 0, 0,
AF, .unit =
"m" },
99 {
"20th",
"20th order (120 dB/8ve)",0,
AV_OPT_TYPE_CONST, {.i64=9}, 0, 0,
AF, .unit =
"m" },
102 {
"precision",
"set processing precision",
OFFSET(precision),
AV_OPT_TYPE_INT, {.i64=0}, 0, 2,
AF, .unit =
"precision" },
103 {
"auto",
"set auto processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=0}, 0, 0,
AF, .unit =
"precision" },
104 {
"float",
"set single-floating point processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=1}, 0, 0,
AF, .unit =
"precision" },
105 {
"double",
"set double-floating point processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=2}, 0, 0,
AF, .unit =
"precision" },
128 switch (
s->precision) {
130 sample_fmts_list = auto_sample_fmts;
151 char *p, *
arg, *saveptr =
NULL;
171 if (
c[0] ==
'd' &&
c[1] ==
'B')
186 char *p, *
arg, *saveptr =
NULL;
211 if (
i > 0 && freq <= s->splits[
i-1]) {
225 for (
i = 0;
i <=
s->nb_splits;
i++) {
244 double omega = 2. *
M_PI *
fc / sr;
245 double cosine = cos(omega);
246 double alpha = sin(omega) / (2. * q);
248 double b0 = (1. - cosine) / 2.;
249 double b1 = 1. - cosine;
250 double b2 = (1. - cosine) / 2.;
252 double a1 = -2. * cosine;
270 double omega = 2. *
M_PI *
fc / sr;
271 double cosine = cos(omega);
272 double alpha = sin(omega) / (2. * q);
274 double b0 = (1. + cosine) / 2.;
275 double b1 = -1. - cosine;
276 double b2 = (1. + cosine) / 2.;
278 double a1 = -2. * cosine;
296 double omega = 2. *
M_PI *
fc / sr;
297 double cosine = cos(omega);
298 double alpha = sin(omega) / (2. * q);
301 double a1 = -2. * cosine;
322 double omega = 2. *
M_PI *
fc / sr;
339 double n = order / 2.;
341 for (
int i = 0;
i < n / 2;
i++)
342 q[
i] = 1. / (-2. * cos(
M_PI * (2. * (
i + 1) + n - 1.) / (2. * n)));
345 #define BIQUAD_PROCESS(name, type) \
346 static void biquad_process_## name(const type *const c, \
348 type *dst, const type *src, \
351 const type b0 = c[B0]; \
352 const type b1 = c[B1]; \
353 const type b2 = c[B2]; \
354 const type a1 = c[A1]; \
355 const type a2 = c[A2]; \
359 for (int n = 0; n + 1 < nb_samples; n++) { \
363 out = in * b0 + z1; \
364 z1 = b1 * in + z2 + a1 * out; \
365 z2 = b2 * in + a2 * out; \
370 out = in * b0 + z1; \
371 z1 = b1 * in + z2 + a1 * out; \
372 z2 = b2 * in + a2 * out; \
376 if (nb_samples & 1) { \
377 const int n = nb_samples - 1; \
378 const type in = src[n]; \
381 out = in * b0 + z1; \
382 z1 = b1 * in + z2 + a1 * out; \
383 z2 = b2 * in + a2 * out; \
394 #define XOVER_PROCESS(name, type, one, ff) \
395 static int filter_channels_## name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
397 AudioCrossoverContext *s = ctx->priv; \
399 AVFrame **frames = s->frames; \
400 const int start = (in->ch_layout.nb_channels * jobnr) / nb_jobs; \
401 const int end = (in->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; \
402 const int nb_samples = in->nb_samples; \
403 const int nb_outs = ctx->nb_outputs; \
404 const int first_order = s->first_order; \
406 for (int ch = start; ch < end; ch++) { \
407 const type *src = (const type *)in->extended_data[ch]; \
408 type *xover = (type *)s->xover->extended_data[ch]; \
410 s->fdsp->vector_## ff ##mul_scalar((type *)frames[0]->extended_data[ch], src, \
411 s->level_in, FFALIGN(nb_samples, sizeof(type))); \
413 for (int band = 0; band < nb_outs; band++) { \
414 for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) { \
415 const type *prv = (const type *)frames[band]->extended_data[ch]; \
416 type *dst = (type *)frames[band + 1]->extended_data[ch]; \
417 const type *hsrc = f == 0 ? prv : dst; \
418 type *hp = xover + nb_outs * 20 + band * 20 + f * 2; \
419 const type *const hpc = (type *)&s->hp[band][f].c ## ff; \
421 biquad_process_## name(hpc, hp, dst, hsrc, nb_samples); \
424 for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) { \
425 type *dst = (type *)frames[band]->extended_data[ch]; \
426 const type *lsrc = dst; \
427 type *lp = xover + band * 20 + f * 2; \
428 const type *const lpc = (type *)&s->lp[band][f].c ## ff; \
430 biquad_process_## name(lpc, lp, dst, lsrc, nb_samples); \
433 for (int aband = band + 1; aband + 1 < nb_outs; aband++) { \
435 const type *asrc = (const type *)frames[band]->extended_data[ch]; \
436 type *dst = (type *)frames[band]->extended_data[ch]; \
437 type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20; \
438 const type *const apc = (type *)&s->ap[aband][0].c ## ff; \
440 biquad_process_## name(apc, ap, dst, asrc, nb_samples); \
443 for (int f = first_order; f < s->ap_filter_count; f++) { \
444 const type *asrc = (const type *)frames[band]->extended_data[ch]; \
445 type *dst = (type *)frames[band]->extended_data[ch]; \
446 type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20 + f * 2;\
447 const type *const apc = (type *)&s->ap[aband][f].c ## ff; \
449 biquad_process_## name(apc, ap, dst, asrc, nb_samples); \
454 for (int band = 0; band < nb_outs; band++) { \
455 const type gain = s->gains[band] * ((band & 1 && first_order) ? -one : one); \
456 type *dst = (type *)frames[band]->extended_data[ch]; \
458 s->fdsp->vector_## ff ##mul_scalar(dst, dst, gain, \
459 FFALIGN(nb_samples, sizeof(type))); \
473 int sample_rate =
inlink->sample_rate;
476 s->order = (
s->order_opt + 1) * 2;
477 s->filter_count =
s->order / 2;
478 s->first_order =
s->filter_count & 1;
479 s->ap_filter_count =
s->filter_count / 2 +
s->first_order;
482 for (
int band = 0; band <=
s->nb_splits; band++) {
483 if (
s->first_order) {
484 set_lp(&
s->lp[band][0],
s->splits[band], 0.5, sample_rate);
485 set_hp(&
s->hp[band][0],
s->splits[band], 0.5, sample_rate);
488 for (
int n =
s->first_order; n < s->filter_count; n++) {
489 const int idx =
s->filter_count / 2 - ((n +
s->first_order) / 2 -
s->first_order) - 1;
491 set_lp(&
s->lp[band][n],
s->splits[band], q[idx], sample_rate);
492 set_hp(&
s->hp[band][n],
s->splits[band], q[idx], sample_rate);
496 set_ap1(&
s->ap[band][0],
s->splits[band], sample_rate);
498 for (
int n =
s->first_order; n < s->ap_filter_count; n++) {
499 const int idx = (
s->filter_count / 2 - ((n * 2 +
s->first_order) / 2 -
s->first_order) - 1);
501 set_ap(&
s->ap[band][n],
s->splits[band], q[idx], sample_rate);
512 ctx->nb_outputs *
ctx->nb_outputs * 10));
526 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
542 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
555 for (
int i = 0;
i <
ctx->nb_outputs;
i++)
568 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
583 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
591 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
621 .
name =
"acrossover",
624 .priv_class = &acrossover_class,
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
@ AV_SAMPLE_FMT_FLTP
float, planar
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
BiquadCoeffs lp[MAX_BANDS][20]
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
static enum AVSampleFormat sample_fmts[]
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
char * av_asprintf(const char *fmt,...)
BiquadCoeffs hp[MAX_BANDS][20]
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
#define FILTER_INPUTS(array)
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
AVFILTER_DEFINE_CLASS(acrossover)
#define fc(width, name, range_min, range_max)
#define BIQUAD_PROCESS(name, type)
const char * name
Filter name.
AVFrame * frames[MAX_BANDS]
A link between two filters.
int(* filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
static double b1(void *priv, double x, double y)
static const AVOption acrossover_options[]
if it could not because there are no more frames
static int parse_gains(AVFilterContext *ctx)
static double a2(void *priv, double x, double y)
static void set_hp(BiquadCoeffs *b, double fc, double q, double sr)
A filter pad used for either input or output.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
const AVFilter ff_af_acrossover
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
Describe the class of an AVClass context structure.
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
BiquadCoeffs ap[MAX_BANDS][20]
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS
The number of the filter outputs is not determined just by AVFilter.outputs.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static av_cold void uninit(AVFilterContext *ctx)
static double b2(void *priv, double x, double y)
static double a0(void *priv, double x, double y)
static void calc_q_factors(int order, double *q)
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
int nb_samples
number of audio samples (per channel) described by this frame
#define i(width, name, range_min, range_max)
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
AVSampleFormat
Audio sample formats.
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
#define FILTER_QUERY_FUNC2(func)
const char * name
Pad name.
static void set_lp(BiquadCoeffs *b, double fc, double q, double sr)
static const AVFilterPad inputs[]
static void set_ap(BiquadCoeffs *b, double fc, double q, double sr)
enum AVMediaType type
AVFilterPad type.
static void set_ap1(BiquadCoeffs *b, double fc, double sr)
static av_cold int init(AVFilterContext *ctx)
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_SAMPLE_FMT_DBLP
double, planar
static int activate(AVFilterContext *ctx)
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
static int config_input(AVFilterLink *inlink)
static const int16_t alpha[]
int ff_append_outpad_free_name(AVFilterContext *f, AVFilterPad *p)
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
#define XOVER_PROCESS(name, type, one, ff)
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
static double b0(void *priv, double x, double y)
static double a1(void *priv, double x, double y)
the definition of that something depends on the semantic of the filter The callback must examine the status of the filter s links and proceed accordingly The status of output links is stored in the status_in and status_out fields and tested by the ff_outlink_frame_wanted() function. If this function returns true
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.