1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-09-16 08:36:51 +02:00

avfilter/vf_premultiply: add dynamic variant of this filter

We need a filter that can premultiply and unpremultiply the alpha channel
dynamically, on demand, in response to the negotiated alpha mode, analogous
to how vf_scale operates. Introduce a new filter "vf_premultiply_dynamic"
that accomplishes this.
This commit is contained in:
Niklas Haas
2025-08-17 19:26:04 +02:00
parent 6bac13d20a
commit c39a67e64f
3 changed files with 67 additions and 10 deletions

View File

@@ -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;

View File

@@ -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 */