From acd87d41f29bce3283798c10dccf6b00090b0d2d Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Thu, 19 Jan 2023 00:25:36 +0100 Subject: [PATCH] avfilter/vf_exposure: reduce copy operations --- libavfilter/vf_exposure.c | 60 +++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/libavfilter/vf_exposure.c b/libavfilter/vf_exposure.c index bbe951967b..ff2f156534 100644 --- a/libavfilter/vf_exposure.c +++ b/libavfilter/vf_exposure.c @@ -38,43 +38,80 @@ typedef struct ExposureContext { int jobnr, int nb_jobs); } ExposureContext; +typedef struct ThreadData { + AVFrame *out, *in; +} ThreadData; + static int exposure_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ExposureContext *s = ctx->priv; - AVFrame *frame = arg; - const int width = frame->width; - const int height = frame->height; + ThreadData *td = arg; + const int width = td->out->width; + const int height = td->out->height; const int slice_start = (height * jobnr) / nb_jobs; const int slice_end = (height * (jobnr + 1)) / nb_jobs; const float black = s->black; const float scale = s->scale; for (int p = 0; p < 3; p++) { - const int linesize = frame->linesize[p] / 4; - float *ptr = (float *)frame->data[p] + slice_start * linesize; + const int slinesize = td->in->linesize[p] / 4; + const int dlinesize = td->out->linesize[p] / 4; + const float *src = (const float *)td->in->data[p] + slice_start * slinesize; + float *ptr = (float *)td->out->data[p] + slice_start * dlinesize; for (int y = slice_start; y < slice_end; y++) { for (int x = 0; x < width; x++) - ptr[x] = (ptr[x] - black) * scale; + ptr[x] = (src[x] - black) * scale; - ptr += linesize; + ptr += dlinesize; + src += slinesize; + } + } + + if (td->in->data[3] && td->in->linesize[3] && td->in != td->out) { + const int slinesize = td->in->linesize[3] / 4; + const int dlinesize = td->out->linesize[3] / 4; + const float *src = (const float *)td->in->data[3] + slice_start * slinesize; + float *ptr = (float *)td->out->data[3] + slice_start * dlinesize; + for (int y = slice_start; y < slice_end; y++) { + memcpy(ptr, src, width * sizeof(*ptr)); + ptr += dlinesize; + src += slinesize; } } return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; ExposureContext *s = ctx->priv; float diff = fabsf(exp2f(-s->exposure) - s->black); + ThreadData td; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } diff = diff > 0.f ? diff : 1.f / 1024.f; s->scale = 1.f / diff; - ff_filter_execute(ctx, s->do_slice, frame, NULL, - FFMIN(frame->height, ff_filter_get_nb_threads(ctx))); + td.out = out; + td.in = in; + ff_filter_execute(ctx, s->do_slice, &td, NULL, + FFMIN(out->height, ff_filter_get_nb_threads(ctx))); - return ff_filter_frame(ctx->outputs[0], frame); + if (out != in) + av_frame_free(&in); + return ff_filter_frame(outlink, out); } static av_cold int config_input(AVFilterLink *inlink) @@ -91,7 +128,6 @@ static const AVFilterPad exposure_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .flags = AVFILTERPAD_FLAG_NEEDS_WRITABLE, .filter_frame = filter_frame, .config_props = config_input, },