diff --git a/doc/filters.texi b/doc/filters.texi index 4c774162e3..66b6c85979 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -19628,6 +19628,20 @@ By default value 0xf, all planes will be processed. Do not require 2nd input for processing, instead use alpha plane from input stream. @end table +@section premultiply_dynamic +Dynamically premultiply or unpremultiply the input video stream as needed, +to match the requirements of the downstream filter graph. This is roughly +equivalent to either @code{premultiply:inplace=yes} or +@code{unpremultiply:inplace=yes}, or otherwise a noop. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes will be processed, unprocessed planes will be copied. +By default value 0xf, all planes will be processed. +@end table + @section prewitt Apply prewitt operator to input video stream. diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index cca4ce0288..3ac1502254 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -410,6 +410,7 @@ extern const FFFilter ff_vf_pixelize; extern const FFFilter ff_vf_pixscope; extern const FFFilter ff_vf_pp7; extern const FFFilter ff_vf_premultiply; +extern const FFFilter ff_vf_premultiply_dynamic; extern const FFFilter ff_vf_prewitt; extern const FFFilter ff_vf_prewitt_opencl; extern const FFFilter ff_vf_procamp_vaapi; diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c index 39a084bfc5..9b4fc39ccb 100644 --- a/libavfilter/vf_premultiply.c +++ b/libavfilter/vf_premultiply.c @@ -41,6 +41,7 @@ typedef struct PreMultiplyContext { int planes; int inverse; int inplace; + int dynamic; int half, depth, offset, max; FFFrameSync fs; @@ -95,18 +96,25 @@ static int query_formats(const AVFilterContext *ctx, if (ret < 0) return ret; - /* Configure alpha mode corresponding to the chosen direction */ - if (s->inplace) { - formats = ff_make_formats_list_singleton(s->inverse ? AVALPHA_MODE_PREMULTIPLIED - : AVALPHA_MODE_STRAIGHT); - ret = ff_formats_ref(formats, &cfg_in[0]->alpha_modes); + if (s->dynamic) { + ret = ff_formats_ref(ff_all_alpha_modes(), &cfg_in[0]->alpha_modes); if (ret < 0) return ret; - } + return ff_formats_ref(ff_all_alpha_modes(), &cfg_out[0]->alpha_modes); + } else { + /* Configure alpha mode corresponding to the chosen direction */ + if (s->inplace) { + formats = ff_make_formats_list_singleton(s->inverse ? AVALPHA_MODE_PREMULTIPLIED + : AVALPHA_MODE_STRAIGHT); + ret = ff_formats_ref(formats, &cfg_in[0]->alpha_modes); + if (ret < 0) + return ret; + } - formats = ff_make_formats_list_singleton(s->inverse ? AVALPHA_MODE_STRAIGHT - : AVALPHA_MODE_PREMULTIPLIED); - return ff_formats_ref(formats, &cfg_out[0]->alpha_modes); + formats = ff_make_formats_list_singleton(s->inverse ? AVALPHA_MODE_STRAIGHT + : AVALPHA_MODE_PREMULTIPLIED); + return ff_formats_ref(formats, &cfg_out[0]->alpha_modes); + } } static void premultiply8(const uint8_t *msrc, const uint8_t *asrc, @@ -530,7 +538,7 @@ static int filter_frame(AVFilterContext *ctx, PreMultiplyContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - if (ctx->is_disabled) { + if (ctx->is_disabled || outlink->alpha_mode == base->alpha_mode) { *out = av_frame_clone(base); if (!*out) return AVERROR(ENOMEM); @@ -741,6 +749,9 @@ static int config_output(AVFilterLink *outlink) outlink->sample_aspect_ratio = base->sample_aspect_ratio; ol->frame_rate = il->frame_rate; + if (s->dynamic) + s->inverse = base->alpha_mode == AVALPHA_MODE_PREMULTIPLIED; + if (s->inplace) return 0; @@ -802,6 +813,11 @@ static av_cold int init(AVFilterContext *ctx) AVFilterPad pad = { 0 }; int ret; + if (!strcmp(ctx->filter->name, "premultiply_dynamic")) { + s->dynamic = s->inplace = 1; + return 0; + } + if (!strcmp(ctx->filter->name, "unpremultiply")) s->inverse = 1; @@ -877,3 +893,29 @@ const FFFilter ff_vf_unpremultiply = { }; #endif /* CONFIG_UNPREMULTIPLY_FILTER */ + +#if CONFIG_PREMULTIPLY_DYNAMIC_FILTER + +static const AVFilterPad premultiply_input[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + }, +}; + +const FFFilter ff_vf_premultiply_dynamic = { + .p.name = "premultiply_dynamic", + .p.description = NULL_IF_CONFIG_SMALL("Premultiply or unpremultiply an image in-place, as needed."), + .p.priv_class = &premultiply_class, + .p.flags = AVFILTER_FLAG_SLICE_THREADS, + .priv_size = sizeof(PreMultiplyContext), + .init = init, + .uninit = uninit, + .activate = activate, + FILTER_INPUTS(premultiply_input), + FILTER_OUTPUTS(premultiply_outputs), + FILTER_QUERY_FUNC2(query_formats), +}; + +#endif /* CONFIG_UNPREMULTIPLY_DYNAMIC_FILTER */