+static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ AudioCrossoverContext *s = ctx->priv;
+ AVFrame *in = s->input_frame;
+ AVFrame **frames = s->frames;
+ const int start = (in->channels * jobnr) / nb_jobs;
+ const int end = (in->channels * (jobnr+1)) / nb_jobs;
+ int f, band;
+
+ for (int ch = start; ch < end; ch++) {
+ const double *src = (const double *)in->extended_data[ch];
+ CrossoverChannel *xover = &s->xover[ch];
+
+ for (int i = 0; i < in->nb_samples; i++) {
+ double sample = src[i], lo, hi;
+
+ for (band = 0; band < ctx->nb_outputs; band++) {
+ double *dst = (double *)frames[band]->extended_data[ch];
+
+ lo = sample;
+ hi = sample;
+ for (f = 0; band + 1 < ctx->nb_outputs && f < s->filter_count; f++) {
+ BiquadContext *lp = &xover->lp[band][f];
+ lo = biquad_process(lp, lo);
+ }
+
+ for (f = 0; band + 1 < ctx->nb_outputs && f < s->filter_count; f++) {
+ BiquadContext *hp = &xover->hp[band][f];
+ hi = biquad_process(hp, hi);
+ }
+
+ dst[i] = lo;
+
+ sample = hi;
+ }
+ }
+ }
+
+ return 0;
+}
+