1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-10-06 05:47:18 +02:00

avfilter/vf_libplacebo: introduce fit_sense option

This allows choosing whether the `fit_mode` merely controls the placement
of the image within the output resolution, or whether the output resolution
is also adjusted according to the given `fit_mode`.
This commit is contained in:
Niklas Haas
2025-09-23 20:49:07 +02:00
committed by Niklas Haas
parent 12d696cff4
commit b80f28fcbc
2 changed files with 43 additions and 3 deletions

View File

@@ -16449,7 +16449,8 @@ will be performed.
@item force_original_aspect_ratio @item force_original_aspect_ratio
@item force_divisible_by @item force_divisible_by
Work the same as the identical @ref{scale} filter options. Work the same as the identical @ref{scale} filter options. Note that
@option{force_divisible_by} also works with @code{fit_sense=constraint}.
@item reset_sar @item reset_sar
If enabled, output frames will always have a pixel aspect ratio of 1:1. If If enabled, output frames will always have a pixel aspect ratio of 1:1. If
@@ -16503,6 +16504,22 @@ to either @code{contain} or @code{none}, depending on whether the input is
larger than the output or not. larger than the output or not.
@end table @end table
@item fit_sense
When @option{fit_mode} is in use, this option controls how the fit strategy
is applied against the specified output resolution. Mutually exclusive with
@option{force_original_aspect_ratio}. Valid values are:
@table @samp
@item target
The computed output resolution is taken as the exact size of the output frame.
This is the default behavior.
@item constraint
The computed output resolution is a size reference against which the fit mode
is applied, enlarging or decreasing the true frame size as needed to fit the
content.
@end table
@item fillcolor @item fillcolor
Set the color used to fill the output area not covered by the output image, for Set the color used to fill the output area not covered by the output image, for
example as a result of @option{normalize_sar}. For the general syntax of this example as a result of @option{normalize_sar}. For the general syntax of this

View File

@@ -161,6 +161,12 @@ enum fit_mode {
FIT_MODE_NB, FIT_MODE_NB,
}; };
enum fit_sense {
FIT_TARGET,
FIT_CONSTRAINT,
FIT_SENSE_NB,
};
typedef struct LibplaceboContext { typedef struct LibplaceboContext {
/* lavfi vulkan*/ /* lavfi vulkan*/
FFVulkanContext vkctx; FFVulkanContext vkctx;
@@ -206,6 +212,7 @@ typedef struct LibplaceboContext {
int reset_sar; int reset_sar;
int normalize_sar; int normalize_sar;
int fit_mode; int fit_mode;
int fit_sense;
int apply_filmgrain; int apply_filmgrain;
int apply_dovi; int apply_dovi;
int colorspace; int colorspace;
@@ -1452,11 +1459,24 @@ static int libplacebo_config_output(AVFilterLink *outlink)
double sar_in = inlink->sample_aspect_ratio.num ? double sar_in = inlink->sample_aspect_ratio.num ?
av_q2d(inlink->sample_aspect_ratio) : 1.0; av_q2d(inlink->sample_aspect_ratio) : 1.0;
int force_oar = s->force_original_aspect_ratio;
if (!force_oar && s->fit_sense == FIT_CONSTRAINT) {
if (s->fit_mode == FIT_CONTAIN || s->fit_mode == FIT_SCALE_DOWN) {
force_oar = SCALE_FORCE_OAR_DECREASE;
} else if (s->fit_mode == FIT_COVER) {
force_oar = SCALE_FORCE_OAR_INCREASE;
}
}
ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h, ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
s->force_original_aspect_ratio, force_oar, s->force_divisible_by,
s->force_divisible_by,
s->reset_sar ? sar_in : 1.0); s->reset_sar ? sar_in : 1.0);
if (s->fit_mode == FIT_SCALE_DOWN && s->fit_sense == FIT_CONSTRAINT) {
int w_adj = s->reset_sar ? sar_in * inlink->w : inlink->w;
outlink->w = FFMIN(outlink->w, w_adj);
outlink->h = FFMIN(outlink->h, inlink->h);
}
if (s->nb_inputs > 1 && !s->disable_fbos) { if (s->nb_inputs > 1 && !s->disable_fbos) {
/* Create a separate renderer and composition texture */ /* Create a separate renderer and composition texture */
@@ -1586,6 +1606,9 @@ static const AVOption libplacebo_options[] = {
{ "none", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" }, { "none", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
{ "place", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" }, { "place", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
{ "scale_down", "Downscale only if larger, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_SCALE_DOWN }, 0, 0, STATIC, .unit = "fit_mode" }, { "scale_down", "Downscale only if larger, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_SCALE_DOWN }, 0, 0, STATIC, .unit = "fit_mode" },
{ "fit_sense", "Output size strategy (for the base layer only)", OFFSET(fit_sense), AV_OPT_TYPE_INT, {.i64 = FIT_TARGET }, 0, FIT_SENSE_NB - 1, STATIC, .unit = "fit_sense" },
{ "target", "Computed resolution is the exact output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_TARGET }, 0, 0, STATIC, .unit = "fit_sense" },
{ "constraint", "Computed resolution constrains the output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_CONSTRAINT }, 0, 0, STATIC, .unit = "fit_sense" },
{ "fillcolor", "Background fill color", OFFSET(fillcolor), AV_OPT_TYPE_COLOR, {.str = "black@0"}, .flags = DYNAMIC }, { "fillcolor", "Background fill color", OFFSET(fillcolor), AV_OPT_TYPE_COLOR, {.str = "black@0"}, .flags = DYNAMIC },
{ "corner_rounding", "Corner rounding radius", OFFSET(corner_rounding), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, .flags = DYNAMIC }, { "corner_rounding", "Corner rounding radius", OFFSET(corner_rounding), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, .flags = DYNAMIC },
{ "lut", "Path to custom LUT file to apply", OFFSET(lut_filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = STATIC }, { "lut", "Path to custom LUT file to apply", OFFSET(lut_filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = STATIC },