From 369b7f2654aa200edfac4a4f8a9b4f5d0bfa9517 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 4 Nov 2022 17:59:28 +0100 Subject: [PATCH] avfilter/af_dynaudnorm: add slice threading support --- libavfilter/af_dynaudnorm.c | 86 +++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c index 5aecefff5e..88d1b382f3 100644 --- a/libavfilter/af_dynaudnorm.c +++ b/libavfilter/af_dynaudnorm.c @@ -93,6 +93,11 @@ typedef struct DynamicAudioNormalizerContext { AVFrame *window; } DynamicAudioNormalizerContext; +typedef struct ThreadData { + AVFrame *in, *out; + int enabled; +} ThreadData; + #define OFFSET(x) offsetof(DynamicAudioNormalizerContext, x) #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM @@ -521,6 +526,20 @@ static void update_gain_history(DynamicAudioNormalizerContext *s, int channel, } } +static int update_gain_histories(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + DynamicAudioNormalizerContext *s = ctx->priv; + AVFrame *analyze_frame = arg; + const int channels = s->channels; + const int start = (channels * jobnr) / nb_jobs; + const int end = (channels * (jobnr+1)) / nb_jobs; + + for (int c = start; c < end; c++) + update_gain_history(s, c, get_max_local_gain(s, analyze_frame, c)); + + return 0; +} + static inline double update_value(double new, double old, double aggressiveness) { av_assert0((aggressiveness >= 0.0) && (aggressiveness <= 1.0)); @@ -655,8 +674,9 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame } } -static int analyze_frame(DynamicAudioNormalizerContext *s, AVFilterLink *outlink, AVFrame **frame) +static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **frame) { + DynamicAudioNormalizerContext *s = ctx->priv; AVFrame *analyze_frame; if (s->dc_correction || s->compress_factor > DBL_EPSILON) { @@ -716,34 +736,49 @@ static int analyze_frame(DynamicAudioNormalizerContext *s, AVFilterLink *outlink for (int c = 0; c < s->channels; c++) update_gain_history(s, c, gain); } else { - for (int c = 0; c < s->channels; c++) - update_gain_history(s, c, get_max_local_gain(s, analyze_frame, c)); + ff_filter_execute(ctx, update_gain_histories, analyze_frame, NULL, + FFMIN(s->channels, ff_filter_get_nb_threads(ctx))); } return 0; } -static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *in, - AVFrame *frame, int enabled) +static void amplify_channel(DynamicAudioNormalizerContext *s, AVFrame *in, + AVFrame *frame, int enabled, int c) { - for (int c = 0; c < s->channels; c++) { - const int bypass = bypass_channel(s, frame, c); - const double *src_ptr = (const double *)in->extended_data[c]; - double *dst_ptr = (double *)frame->extended_data[c]; - double current_amplification_factor; + const int bypass = bypass_channel(s, frame, c); + const double *src_ptr = (const double *)in->extended_data[c]; + double *dst_ptr = (double *)frame->extended_data[c]; + double current_amplification_factor; - cqueue_dequeue(s->gain_history_smoothed[c], ¤t_amplification_factor); + cqueue_dequeue(s->gain_history_smoothed[c], ¤t_amplification_factor); - for (int i = 0; i < frame->nb_samples && enabled && !bypass; i++) { - const double amplification_factor = fade(s->prev_amplification_factor[c], - current_amplification_factor, i, - frame->nb_samples); + for (int i = 0; i < frame->nb_samples && enabled && !bypass; i++) { + const double amplification_factor = fade(s->prev_amplification_factor[c], + current_amplification_factor, i, + frame->nb_samples); - dst_ptr[i] = src_ptr[i] * amplification_factor; - } - - s->prev_amplification_factor[c] = current_amplification_factor; + dst_ptr[i] = src_ptr[i] * amplification_factor; } + + s->prev_amplification_factor[c] = current_amplification_factor; +} + +static int amplify_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + DynamicAudioNormalizerContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *out = td->out; + AVFrame *in = td->in; + const int enabled = td->enabled; + const int channels = s->channels; + const int start = (channels * jobnr) / nb_jobs; + const int end = (channels * (jobnr+1)) / nb_jobs; + + for (int ch = start; ch < end; ch++) + amplify_channel(s, in, out, enabled, ch); + + return 0; } static int filter_frame(AVFilterLink *inlink, AVFrame *in) @@ -751,6 +786,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; DynamicAudioNormalizerContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + ThreadData td; int ret; while (((s->queue.available >= s->filter_size) || @@ -773,7 +809,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - amplify_frame(s, in, out, is_enabled > 0.); + td.in = in; + td.out = out; + td.enabled = is_enabled > 0.; + ff_filter_execute(ctx, amplify_channels, &td, NULL, + FFMIN(s->channels, ff_filter_get_nb_threads(ctx))); + s->pts = out->pts + av_rescale_q(out->nb_samples, av_make_q(1, outlink->sample_rate), outlink->time_base); if (out != in) @@ -783,7 +824,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ret; } - ret = analyze_frame(s, outlink, &in); + ret = analyze_frame(ctx, outlink, &in); if (ret < 0) return ret; if (!s->eof) { @@ -940,6 +981,7 @@ const AVFilter ff_af_dynaudnorm = { FILTER_OUTPUTS(avfilter_af_dynaudnorm_outputs), FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP), .priv_class = &dynaudnorm_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, .process_command = process_command, };