diff options
author | Paul B Mahol <onemda@gmail.com> | 2023-01-19 10:04:15 +0100 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2023-02-11 10:36:56 +0100 |
commit | 725328672a28d9591d2cf7564401742b12478a7e (patch) | |
tree | e3509f7e8b948d47f5cf55644bdb0c843dd697c9 | |
parent | acd87d41f29bce3283798c10dccf6b00090b0d2d (diff) | |
download | ffmpeg-725328672a28d9591d2cf7564401742b12478a7e.tar.gz |
avfilter/vf_vibrance: reduce copy operations
-rw-r--r-- | libavfilter/vf_vibrance.c | 117 |
1 files changed, 96 insertions, 21 deletions
diff --git a/libavfilter/vf_vibrance.c b/libavfilter/vf_vibrance.c index 81ae63902c..329b37bdc6 100644 --- a/libavfilter/vf_vibrance.c +++ b/libavfilter/vf_vibrance.c @@ -29,6 +29,7 @@ #define R 0 #define G 1 #define B 2 +#define A 3 typedef struct VibranceContext { const AVClass *class; @@ -51,10 +52,16 @@ static inline float lerpf(float v0, float v1, float f) return v0 + (v1 - v0) * f; } +typedef struct ThreadData { + AVFrame *out, *in; +} ThreadData; + static int vibrance_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) { VibranceContext *s = avctx->priv; - AVFrame *frame = arg; + ThreadData *td = arg; + AVFrame *frame = td->out; + AVFrame *in = td->in; const int width = frame->width; const int height = frame->height; const float scale = 1.f / 255.f; @@ -74,15 +81,25 @@ static int vibrance_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_ const int glinesize = frame->linesize[0]; const int blinesize = frame->linesize[1]; const int rlinesize = frame->linesize[2]; + const int alinesize = frame->linesize[3]; + const int gslinesize = in->linesize[0]; + const int bslinesize = in->linesize[1]; + const int rslinesize = in->linesize[2]; + const int aslinesize = in->linesize[3]; + const uint8_t *gsrc = in->data[0] + slice_start * glinesize; + const uint8_t *bsrc = in->data[1] + slice_start * blinesize; + const uint8_t *rsrc = in->data[2] + slice_start * rlinesize; uint8_t *gptr = frame->data[0] + slice_start * glinesize; uint8_t *bptr = frame->data[1] + slice_start * blinesize; uint8_t *rptr = frame->data[2] + slice_start * rlinesize; + const uint8_t *asrc = in->data[3]; + uint8_t *aptr = frame->data[3]; for (int y = slice_start; y < slice_end; y++) { for (int x = 0; x < width; x++) { - float g = gptr[x] * scale; - float b = bptr[x] * scale; - float r = rptr[x] * scale; + float g = gsrc[x] * scale; + float b = bsrc[x] * scale; + float r = rsrc[x] * scale; float max_color = FFMAX3(r, g, b); float min_color = FFMIN3(r, g, b); float color_saturation = max_color - min_color; @@ -100,6 +117,12 @@ static int vibrance_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_ rptr[x] = av_clip_uint8(r * 255.f); } + if (aptr && alinesize && frame != in) + memcpy(aptr + alinesize * y, asrc + aslinesize * y, width); + + gsrc += gslinesize; + bsrc += bslinesize; + rsrc += rslinesize; gptr += glinesize; bptr += blinesize; rptr += rlinesize; @@ -111,7 +134,9 @@ static int vibrance_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_ static int vibrance_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) { VibranceContext *s = avctx->priv; - AVFrame *frame = arg; + ThreadData *td = arg; + AVFrame *frame = td->out; + AVFrame *in = td->in; const int depth = s->depth; const float max = (1 << depth) - 1; const float scale = 1.f / max; @@ -130,18 +155,28 @@ static int vibrance_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb const float srintensity = alternate * FFSIGN(rintensity); const int slice_start = (height * jobnr) / nb_jobs; const int slice_end = (height * (jobnr + 1)) / nb_jobs; + const int gslinesize = in->linesize[0] / 2; + const int bslinesize = in->linesize[1] / 2; + const int rslinesize = in->linesize[2] / 2; + const int aslinesize = in->linesize[3] / 2; const int glinesize = frame->linesize[0] / 2; const int blinesize = frame->linesize[1] / 2; const int rlinesize = frame->linesize[2] / 2; + const int alinesize = frame->linesize[3] / 2; + const uint16_t *gsrc = (const uint16_t *)in->data[0] + slice_start * gslinesize; + const uint16_t *bsrc = (const uint16_t *)in->data[1] + slice_start * bslinesize; + const uint16_t *rsrc = (const uint16_t *)in->data[2] + slice_start * rslinesize; uint16_t *gptr = (uint16_t *)frame->data[0] + slice_start * glinesize; uint16_t *bptr = (uint16_t *)frame->data[1] + slice_start * blinesize; uint16_t *rptr = (uint16_t *)frame->data[2] + slice_start * rlinesize; + const uint16_t *asrc = (const uint16_t *)in->data[3]; + uint16_t *aptr = (uint16_t *)frame->data[3]; for (int y = slice_start; y < slice_end; y++) { for (int x = 0; x < width; x++) { - float g = gptr[x] * scale; - float b = bptr[x] * scale; - float r = rptr[x] * scale; + float g = gsrc[x] * scale; + float b = bsrc[x] * scale; + float r = rsrc[x] * scale; float max_color = FFMAX3(r, g, b); float min_color = FFMIN3(r, g, b); float color_saturation = max_color - min_color; @@ -159,6 +194,12 @@ static int vibrance_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb rptr[x] = av_clip_uintp2_c(r * max, depth); } + if (aptr && alinesize && frame != in) + memcpy(aptr + alinesize * y, asrc + aslinesize * y, width * 2); + + gsrc += gslinesize; + bsrc += bslinesize; + rsrc += rslinesize; gptr += glinesize; bptr += blinesize; rptr += rlinesize; @@ -170,7 +211,9 @@ static int vibrance_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb static int vibrance_slice8p(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) { VibranceContext *s = avctx->priv; - AVFrame *frame = arg; + ThreadData *td = arg; + AVFrame *frame = td->out; + AVFrame *in = td->in; const int step = s->step; const int width = frame->width; const int height = frame->height; @@ -181,6 +224,7 @@ static int vibrance_slice8p(AVFilterContext *avctx, void *arg, int jobnr, int nb const uint8_t roffset = s->rgba_map[R]; const uint8_t goffset = s->rgba_map[G]; const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; const float intensity = s->intensity; const float alternate = s->alternate ? 1.f : -1.f; const float gintensity = intensity * s->balance[0]; @@ -192,13 +236,15 @@ static int vibrance_slice8p(AVFilterContext *avctx, void *arg, int jobnr, int nb const int slice_start = (height * jobnr) / nb_jobs; const int slice_end = (height * (jobnr + 1)) / nb_jobs; const int linesize = frame->linesize[0]; + const int slinesize = in->linesize[0]; + const uint8_t *src = in->data[0] + slice_start * slinesize; uint8_t *ptr = frame->data[0] + slice_start * linesize; for (int y = slice_start; y < slice_end; y++) { for (int x = 0; x < width; x++) { - float g = ptr[x * step + goffset] * scale; - float b = ptr[x * step + boffset] * scale; - float r = ptr[x * step + roffset] * scale; + float g = src[x * step + goffset] * scale; + float b = src[x * step + boffset] * scale; + float r = src[x * step + roffset] * scale; float max_color = FFMAX3(r, g, b); float min_color = FFMIN3(r, g, b); float color_saturation = max_color - min_color; @@ -214,9 +260,13 @@ static int vibrance_slice8p(AVFilterContext *avctx, void *arg, int jobnr, int nb ptr[x * step + goffset] = av_clip_uint8(g * 255.f); ptr[x * step + boffset] = av_clip_uint8(b * 255.f); ptr[x * step + roffset] = av_clip_uint8(r * 255.f); + + if (frame != in) + ptr[x * step + aoffset] = src[x * step + aoffset]; } ptr += linesize; + src += slinesize; } return 0; @@ -225,7 +275,9 @@ static int vibrance_slice8p(AVFilterContext *avctx, void *arg, int jobnr, int nb static int vibrance_slice16p(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) { VibranceContext *s = avctx->priv; - AVFrame *frame = arg; + ThreadData *td = arg; + AVFrame *frame = td->out; + AVFrame *in = td->in; const int step = s->step; const int depth = s->depth; const float max = (1 << depth) - 1; @@ -236,6 +288,7 @@ static int vibrance_slice16p(AVFilterContext *avctx, void *arg, int jobnr, int n const uint8_t roffset = s->rgba_map[R]; const uint8_t goffset = s->rgba_map[G]; const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; const int width = frame->width; const int height = frame->height; const float intensity = s->intensity; @@ -249,13 +302,15 @@ static int vibrance_slice16p(AVFilterContext *avctx, void *arg, int jobnr, int n const int slice_start = (height * jobnr) / nb_jobs; const int slice_end = (height * (jobnr + 1)) / nb_jobs; const int linesize = frame->linesize[0] / 2; + const int slinesize = in->linesize[0] / 2; + const uint16_t *src = (const uint16_t *)in->data[0] + slice_start * slinesize; uint16_t *ptr = (uint16_t *)frame->data[0] + slice_start * linesize; for (int y = slice_start; y < slice_end; y++) { for (int x = 0; x < width; x++) { - float g = ptr[x * step + goffset] * scale; - float b = ptr[x * step + boffset] * scale; - float r = ptr[x * step + roffset] * scale; + float g = src[x * step + goffset] * scale; + float b = src[x * step + boffset] * scale; + float r = src[x * step + roffset] * scale; float max_color = FFMAX3(r, g, b); float min_color = FFMIN3(r, g, b); float color_saturation = max_color - min_color; @@ -271,25 +326,46 @@ static int vibrance_slice16p(AVFilterContext *avctx, void *arg, int jobnr, int n ptr[x * step + goffset] = av_clip_uintp2_c(g * max, depth); ptr[x * step + boffset] = av_clip_uintp2_c(b * max, depth); ptr[x * step + roffset] = av_clip_uintp2_c(r * max, depth); + if (frame != in) + ptr[x * step + aoffset] = src[x * step + aoffset]; } ptr += linesize; + src += slinesize; } return 0; } -static int filter_frame(AVFilterLink *link, AVFrame *frame) +static int filter_frame(AVFilterLink *link, AVFrame *in) { AVFilterContext *avctx = link->dst; + AVFilterLink *outlink = avctx->outputs[0]; VibranceContext *s = avctx->priv; + ThreadData td; + AVFrame *out; int res; - if (res = ff_filter_execute(avctx, s->do_slice, frame, NULL, - FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) + 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); + } + + td.out = out; + td.in = in; + if (res = ff_filter_execute(avctx, s->do_slice, &td, NULL, + FFMIN(out->height, ff_filter_get_nb_threads(avctx)))) return res; - return ff_filter_frame(avctx->outputs[0], frame); + if (out != in) + av_frame_free(&in); + return ff_filter_frame(outlink, out); } static const enum AVPixelFormat pixel_fmts[] = { @@ -335,7 +411,6 @@ static const AVFilterPad vibrance_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .flags = AVFILTERPAD_FLAG_NEEDS_WRITABLE, .filter_frame = filter_frame, .config_props = config_input, }, |