+ if (s->oversample <= 1)
+ return 0;
+
+ s->up_ctx = swr_alloc();
+ s->down_ctx = swr_alloc();
+ if (!s->up_ctx || !s->down_ctx)
+ return AVERROR(ENOMEM);
+
+ av_opt_set_int(s->up_ctx, "in_channel_layout", inlink->channel_layout, 0);
+ av_opt_set_int(s->up_ctx, "in_sample_rate", inlink->sample_rate, 0);
+ av_opt_set_sample_fmt(s->up_ctx, "in_sample_fmt", inlink->format, 0);
+
+ av_opt_set_int(s->up_ctx, "out_channel_layout", inlink->channel_layout, 0);
+ av_opt_set_int(s->up_ctx, "out_sample_rate", inlink->sample_rate * s->oversample, 0);
+ av_opt_set_sample_fmt(s->up_ctx, "out_sample_fmt", inlink->format, 0);
+
+ av_opt_set_int(s->down_ctx, "in_channel_layout", inlink->channel_layout, 0);
+ av_opt_set_int(s->down_ctx, "in_sample_rate", inlink->sample_rate * s->oversample, 0);
+ av_opt_set_sample_fmt(s->down_ctx, "in_sample_fmt", inlink->format, 0);
+
+ av_opt_set_int(s->down_ctx, "out_channel_layout", inlink->channel_layout, 0);
+ av_opt_set_int(s->down_ctx, "out_sample_rate", inlink->sample_rate, 0);
+ av_opt_set_sample_fmt(s->down_ctx, "out_sample_fmt", inlink->format, 0);
+
+ ret = swr_init(s->up_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = swr_init(s->down_ctx);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+ int nb_samples;
+ int channels;
+} ThreadData;
+
+static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ASoftClipContext *s = ctx->priv;
+ ThreadData *td = arg;
+ AVFrame *out = td->out;
+ AVFrame *in = td->in;
+ const int channels = td->channels;
+ const int nb_samples = td->nb_samples;
+ const int start = (channels * jobnr) / nb_jobs;
+ const int end = (channels * (jobnr+1)) / nb_jobs;
+
+ s->filter(s, (void **)out->extended_data, (const void **)in->extended_data,
+ nb_samples, channels, start, end);
+