* [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar
@ 2025-01-31 13:00 Gyan Doshi
2025-02-07 4:00 ` Gyan Doshi
2025-02-07 14:54 ` Leo Izen
0 siblings, 2 replies; 3+ messages in thread
From: Gyan Doshi @ 2025-01-31 13:00 UTC (permalink / raw)
To: ffmpeg-devel
For anamorphic videos, enabling this option leads to adjustment of
output dimensions to obtain square pixels when the user requests
proportional scaling through either of the w/h expressions or
force_original_aspect_ratio.
Output SAR is always reset to 1.
Option added to scale, scale_cuda, scale_npp & scale_vaapi.
libplacebo already has a similar option with different semantics,
scale_vt and scale_vulkan don't implement force_oar, so for these
three filters, I've made minimal changes needed to not break building
or change output.
---
doc/filters.texi | 21 +++++++++++++++++++++
libavfilter/scale_eval.c | 13 +++++++------
libavfilter/scale_eval.h | 5 ++++-
libavfilter/vf_libplacebo.c | 2 +-
libavfilter/vf_scale.c | 13 +++++++++++--
libavfilter/vf_scale_cuda.c | 25 +++++++++++++++++++------
libavfilter/vf_scale_npp.c | 13 +++++++++++--
libavfilter/vf_scale_vaapi.c | 13 +++++++++++--
libavfilter/vf_scale_vt.c | 2 +-
libavfilter/vf_scale_vulkan.c | 2 +-
10 files changed, 87 insertions(+), 22 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index a14c7e7e77..71de1ab2dc 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -21285,6 +21285,13 @@ This option can be handy if you need to have a video fit within or exceed
a defined resolution using @option{force_original_aspect_ratio} but also have
encoder restrictions on width or height divisibility.
+@item reset_sar
+For anamorphic videos, enabling this option leads to adjustment of output dimensions
+to obtain square pixels when the user requests proportional scaling through either of
+the width or height expressions or through force_original_aspect_ratio.
+Output SAR is always reset to 1.
+Default is false.
+
@end table
The values of the @option{w} and @option{h} options are expressions
@@ -21538,6 +21545,13 @@ Affects the curves of the bicubic algorithm.
@item force_divisible_by
Work the same as the identical @ref{scale} filter options.
+@item reset_sar
+For anamorphic videos, enabling this option leads to adjustment of output dimensions
+to obtain square pixels when the user requests proportional scaling through either of
+the width or height expressions or through force_original_aspect_ratio.
+Output SAR is always reset to 1.
+Default is false.
+
@end table
@subsection Examples
@@ -21641,6 +21655,13 @@ This option can be handy if you need to have a video fit within or exceed
a defined resolution using @option{force_original_aspect_ratio} but also have
encoder restrictions on width or height divisibility.
+@item reset_sar
+For anamorphic videos, enabling this option leads to adjustment of output dimensions
+to obtain square pixels when the user requests proportional scaling through either of
+the width or height expressions or through force_original_aspect_ratio.
+Output SAR is always reset to 1.
+Default is false.
+
@item eval
Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values:
diff --git a/libavfilter/scale_eval.c b/libavfilter/scale_eval.c
index dc8d522b1e..53f5e22b0e 100644
--- a/libavfilter/scale_eval.c
+++ b/libavfilter/scale_eval.c
@@ -112,7 +112,8 @@ fail:
int ff_scale_adjust_dimensions(AVFilterLink *inlink,
int *ret_w, int *ret_h,
- int force_original_aspect_ratio, int force_divisible_by)
+ int force_original_aspect_ratio, int force_divisible_by,
+ double w_adj)
{
int64_t w, h;
int factor_w, factor_h;
@@ -132,7 +133,7 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
}
if (w < 0 && h < 0) {
- w = inlink->w;
+ w = inlink->w * w_adj;
h = inlink->h;
}
@@ -140,18 +141,18 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
* earlier. If no factor was set, nothing will happen as the default
* factor is 1 */
if (w < 0)
- w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
+ w = av_rescale(h, inlink->w * w_adj, inlink->h * factor_w) * factor_w;
if (h < 0)
- h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h;
+ h = av_rescale(w, inlink->h, inlink->w * w_adj * factor_h) * factor_h;
/* Note that force_original_aspect_ratio may overwrite the previous set
* dimensions so that it is not divisible by the set factors anymore
* unless force_divisible_by is defined as well */
if (force_original_aspect_ratio) {
// Including force_divisible_by here rounds to the nearest multiple of it.
- int64_t tmp_w = av_rescale(h, inlink->w, inlink->h * (int64_t)force_divisible_by)
+ int64_t tmp_w = av_rescale(h, inlink->w * w_adj, inlink->h * (int64_t)force_divisible_by)
* force_divisible_by;
- int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * (int64_t)force_divisible_by)
+ int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * w_adj * (int64_t)force_divisible_by)
* force_divisible_by;
if (force_original_aspect_ratio == 1) {
diff --git a/libavfilter/scale_eval.h b/libavfilter/scale_eval.h
index b489528404..6cab623e1c 100644
--- a/libavfilter/scale_eval.h
+++ b/libavfilter/scale_eval.h
@@ -40,10 +40,13 @@ int ff_scale_eval_dimensions(void *ctx,
* or both of the evaluated values are of the form '-n' or if
* force_original_aspect_ratio is set. force_divisible_by is used only when
* force_original_aspect_ratio is set and must be at least 1.
+ * w_adj is the input SAR when the output dimensions are intended to be square
+ * pixels, else should be 1.
*
* Returns negative error code on error or non negative on success
*/
int ff_scale_adjust_dimensions(AVFilterLink *inlink,
int *ret_w, int *ret_h,
- int force_original_aspect_ratio, int force_divisible_by);
+ int force_original_aspect_ratio, int force_divisible_by,
+ double w_adj);
#endif
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index c884c621c8..e1c6629f6d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -1201,7 +1201,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
s->force_original_aspect_ratio,
- s->force_divisible_by);
+ s->force_divisible_by, 1.f);
if (s->normalize_sar || s->nb_inputs > 1) {
/* SAR is normalized, or we have multiple inputs, set out to 1:1 */
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 14ce1fbbd8..2eae981b57 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -176,6 +176,7 @@ typedef struct ScaleContext {
int force_original_aspect_ratio;
int force_divisible_by;
+ int reset_sar;
int eval_mode; ///< expression evaluation mode
@@ -645,6 +646,7 @@ static int config_props(AVFilterLink *outlink)
outlink->src->inputs[0];
ScaleContext *scale = ctx->priv;
uint8_t *flags_val = NULL;
+ double w_adj = 1;
int ret;
if ((ret = scale_eval_dimensions(ctx)) < 0)
@@ -653,9 +655,13 @@ static int config_props(AVFilterLink *outlink)
outlink->w = scale->w;
outlink->h = scale->h;
+ if (scale->reset_sar)
+ w_adj = IS_SCALE2REF(ctx) ? scale->var_values[VAR_S2R_MAIN_SAR] :
+ scale->var_values[VAR_SAR];
+
ret = ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
scale->force_original_aspect_ratio,
- scale->force_divisible_by);
+ scale->force_divisible_by, w_adj);
if (ret < 0)
goto fail;
@@ -668,7 +674,9 @@ static int config_props(AVFilterLink *outlink)
/* TODO: make algorithm configurable */
- if (inlink0->sample_aspect_ratio.num){
+ if (scale->reset_sar)
+ outlink->sample_aspect_ratio = (AVRational){1, 1};
+ else if (inlink0->sample_aspect_ratio.num){
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink0->w, outlink->w * inlink0->h}, inlink0->sample_aspect_ratio);
} else
outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
@@ -1175,6 +1183,7 @@ static const AVOption scale_options[] = {
{ "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
+ { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
{ "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
{ "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 5f9fd59118..de1883a1df 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -96,6 +96,7 @@ typedef struct CUDAScaleContext {
int force_original_aspect_ratio;
int force_divisible_by;
+ int reset_sar;
CUcontext cu_ctx;
CUmodule cu_module;
@@ -355,6 +356,7 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
AVHWFramesContext *frames_ctx;
AVCUDADeviceContext *device_hwctx;
int w, h;
+ double w_adj = 1.0;
int ret;
if ((ret = ff_scale_eval_dimensions(s,
@@ -363,8 +365,12 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
&w, &h)) < 0)
goto fail;
+ if (s->reset_sar)
+ w_adj = inlink->sample_aspect_ratio.num ?
+ (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
+
ff_scale_adjust_dimensions(inlink, &w, &h,
- s->force_original_aspect_ratio, s->force_divisible_by);
+ s->force_original_aspect_ratio, s->force_divisible_by, w_adj);
if (((int64_t)h * inlink->w) > INT_MAX ||
((int64_t)w * inlink->h) > INT_MAX)
@@ -383,7 +389,9 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
s->hwctx = device_hwctx;
s->cu_stream = s->hwctx->stream;
- if (inlink->sample_aspect_ratio.num) {
+ if (s->reset_sar)
+ outlink->sample_aspect_ratio = (AVRational){1, 1};
+ else if (inlink->sample_aspect_ratio.num) {
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
outlink->w*inlink->h},
inlink->sample_aspect_ratio);
@@ -574,10 +582,14 @@ static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in)
if (ret < 0)
goto fail;
- av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
- (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
- (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
- INT_MAX);
+ if (s->reset_sar) {
+ out->sample_aspect_ratio = (AVRational){1, 1};
+ } else {
+ av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
+ (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
+ (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
+ INT_MAX);
+ }
av_frame_free(&in);
return ff_filter_frame(outlink, out);
@@ -614,6 +626,7 @@ static const AVOption options[] = {
{ "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
+ { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ NULL },
};
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index ec3267801b..5274158f1b 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -160,6 +160,7 @@ typedef struct NPPScaleContext {
int force_original_aspect_ratio;
int force_divisible_by;
+ int reset_sar;
int interp_algo;
@@ -650,14 +651,19 @@ static int config_props(AVFilterLink *outlink)
outlink->src->inputs[1] :
outlink->src->inputs[0];
NPPScaleContext *s = ctx->priv;
+ double w_adj = 1.0;
int ret;
if ((ret = nppscale_eval_dimensions(ctx)) < 0)
goto fail;
+ if (s->reset_sar)
+ w_adj = IS_SCALE2REF(ctx) ? s->var_values[VAR_S2R_MAIN_SAR] :
+ s->var_values[VAR_SAR];
+
ff_scale_adjust_dimensions(inlink, &s->w, &s->h,
s->force_original_aspect_ratio,
- s->force_divisible_by);
+ s->force_divisible_by, w_adj);
if (s->w > INT_MAX || s->h > INT_MAX ||
(s->h * inlink->w) > INT_MAX ||
@@ -674,7 +680,9 @@ static int config_props(AVFilterLink *outlink)
av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d\n",
inlink->w, inlink->h, outlink->w, outlink->h);
- if (inlink->sample_aspect_ratio.num)
+ if (s->reset_sar)
+ outlink->sample_aspect_ratio = (AVRational){1, 1};
+ else if (inlink->sample_aspect_ratio.num)
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
outlink->w*inlink->h},
inlink->sample_aspect_ratio);
@@ -1019,6 +1027,7 @@ static const AVOption options[] = {
{ "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
+ { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, { .i64 = EVAL_MODE_INIT }, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
{ "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_INIT }, 0, 0, FLAGS, .unit = "eval" },
{ "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_FRAME }, 0, 0, FLAGS, .unit = "eval" },
diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
index 0f2d617996..ab95d41e0e 100644
--- a/libavfilter/vf_scale_vaapi.c
+++ b/libavfilter/vf_scale_vaapi.c
@@ -39,6 +39,7 @@ typedef struct ScaleVAAPIContext {
int force_original_aspect_ratio;
int force_divisible_by;
+ int reset_sar;
char *colour_primaries_string;
char *colour_transfer_string;
@@ -73,6 +74,7 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
AVFilterContext *avctx = outlink->src;
VAAPIVPPContext *vpp_ctx = avctx->priv;
ScaleVAAPIContext *ctx = avctx->priv;
+ double w_adj = 1.0;
int err;
if ((err = ff_scale_eval_dimensions(ctx,
@@ -81,8 +83,12 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
&vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
return err;
+ if (ctx->reset_sar)
+ w_adj = inlink->sample_aspect_ratio.num ?
+ (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
+
ff_scale_adjust_dimensions(inlink, &vpp_ctx->output_width, &vpp_ctx->output_height,
- ctx->force_original_aspect_ratio, ctx->force_divisible_by);
+ ctx->force_original_aspect_ratio, ctx->force_divisible_by, w_adj);
if (inlink->w == vpp_ctx->output_width && inlink->h == vpp_ctx->output_height &&
(vpp_ctx->input_frames->sw_format == vpp_ctx->output_format ||
@@ -98,7 +104,9 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
if (err < 0)
return err;
- if (inlink->sample_aspect_ratio.num)
+ if (ctx->reset_sar)
+ outlink->sample_aspect_ratio = (AVRational){1, 1};
+ else if (inlink->sample_aspect_ratio.num)
outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
else
outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
@@ -274,6 +282,7 @@ static const AVOption scale_vaapi_options[] = {
{ "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
{ "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
+ { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
{ NULL },
};
diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c
index 162ea8fcec..c024717bc2 100644
--- a/libavfilter/vf_scale_vt.c
+++ b/libavfilter/vf_scale_vt.c
@@ -248,7 +248,7 @@ static int scale_vt_config_output(AVFilterLink *outlink)
if (err < 0)
return err;
- ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1);
+ ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1, 1.f);
outlink->w = s->output_width;
outlink->h = s->output_height;
diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
index 6f99769d81..1d6492e213 100644
--- a/libavfilter/vf_scale_vulkan.c
+++ b/libavfilter/vf_scale_vulkan.c
@@ -336,7 +336,7 @@ static int scale_vulkan_config_output(AVFilterLink *outlink)
if (err < 0)
return err;
- ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1);
+ ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1, 1.f);
outlink->w = vkctx->output_width;
outlink->h = vkctx->output_height;
--
2.46.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar
2025-01-31 13:00 [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar Gyan Doshi
@ 2025-02-07 4:00 ` Gyan Doshi
2025-02-07 14:54 ` Leo Izen
1 sibling, 0 replies; 3+ messages in thread
From: Gyan Doshi @ 2025-02-07 4:00 UTC (permalink / raw)
To: ffmpeg-devel
On 2025-01-31 06:30 pm, Gyan Doshi wrote:
> For anamorphic videos, enabling this option leads to adjustment of
> output dimensions to obtain square pixels when the user requests
> proportional scaling through either of the w/h expressions or
> force_original_aspect_ratio.
>
> Output SAR is always reset to 1.
>
> Option added to scale, scale_cuda, scale_npp & scale_vaapi.
>
> libplacebo already has a similar option with different semantics,
> scale_vt and scale_vulkan don't implement force_oar, so for these
> three filters, I've made minimal changes needed to not break building
> or change output.
Plan to push on Monday.
Regards,
Gyan
> ---
> doc/filters.texi | 21 +++++++++++++++++++++
> libavfilter/scale_eval.c | 13 +++++++------
> libavfilter/scale_eval.h | 5 ++++-
> libavfilter/vf_libplacebo.c | 2 +-
> libavfilter/vf_scale.c | 13 +++++++++++--
> libavfilter/vf_scale_cuda.c | 25 +++++++++++++++++++------
> libavfilter/vf_scale_npp.c | 13 +++++++++++--
> libavfilter/vf_scale_vaapi.c | 13 +++++++++++--
> libavfilter/vf_scale_vt.c | 2 +-
> libavfilter/vf_scale_vulkan.c | 2 +-
> 10 files changed, 87 insertions(+), 22 deletions(-)
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index a14c7e7e77..71de1ab2dc 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -21285,6 +21285,13 @@ This option can be handy if you need to have a video fit within or exceed
> a defined resolution using @option{force_original_aspect_ratio} but also have
> encoder restrictions on width or height divisibility.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @end table
>
> The values of the @option{w} and @option{h} options are expressions
> @@ -21538,6 +21545,13 @@ Affects the curves of the bicubic algorithm.
> @item force_divisible_by
> Work the same as the identical @ref{scale} filter options.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @end table
>
> @subsection Examples
> @@ -21641,6 +21655,13 @@ This option can be handy if you need to have a video fit within or exceed
> a defined resolution using @option{force_original_aspect_ratio} but also have
> encoder restrictions on width or height divisibility.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @item eval
> Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values:
>
> diff --git a/libavfilter/scale_eval.c b/libavfilter/scale_eval.c
> index dc8d522b1e..53f5e22b0e 100644
> --- a/libavfilter/scale_eval.c
> +++ b/libavfilter/scale_eval.c
> @@ -112,7 +112,8 @@ fail:
>
> int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> int *ret_w, int *ret_h,
> - int force_original_aspect_ratio, int force_divisible_by)
> + int force_original_aspect_ratio, int force_divisible_by,
> + double w_adj)
> {
> int64_t w, h;
> int factor_w, factor_h;
> @@ -132,7 +133,7 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> }
>
> if (w < 0 && h < 0) {
> - w = inlink->w;
> + w = inlink->w * w_adj;
> h = inlink->h;
> }
>
> @@ -140,18 +141,18 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> * earlier. If no factor was set, nothing will happen as the default
> * factor is 1 */
> if (w < 0)
> - w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
> + w = av_rescale(h, inlink->w * w_adj, inlink->h * factor_w) * factor_w;
> if (h < 0)
> - h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h;
> + h = av_rescale(w, inlink->h, inlink->w * w_adj * factor_h) * factor_h;
>
> /* Note that force_original_aspect_ratio may overwrite the previous set
> * dimensions so that it is not divisible by the set factors anymore
> * unless force_divisible_by is defined as well */
> if (force_original_aspect_ratio) {
> // Including force_divisible_by here rounds to the nearest multiple of it.
> - int64_t tmp_w = av_rescale(h, inlink->w, inlink->h * (int64_t)force_divisible_by)
> + int64_t tmp_w = av_rescale(h, inlink->w * w_adj, inlink->h * (int64_t)force_divisible_by)
> * force_divisible_by;
> - int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * (int64_t)force_divisible_by)
> + int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * w_adj * (int64_t)force_divisible_by)
> * force_divisible_by;
>
> if (force_original_aspect_ratio == 1) {
> diff --git a/libavfilter/scale_eval.h b/libavfilter/scale_eval.h
> index b489528404..6cab623e1c 100644
> --- a/libavfilter/scale_eval.h
> +++ b/libavfilter/scale_eval.h
> @@ -40,10 +40,13 @@ int ff_scale_eval_dimensions(void *ctx,
> * or both of the evaluated values are of the form '-n' or if
> * force_original_aspect_ratio is set. force_divisible_by is used only when
> * force_original_aspect_ratio is set and must be at least 1.
> + * w_adj is the input SAR when the output dimensions are intended to be square
> + * pixels, else should be 1.
> *
> * Returns negative error code on error or non negative on success
> */
> int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> int *ret_w, int *ret_h,
> - int force_original_aspect_ratio, int force_divisible_by);
> + int force_original_aspect_ratio, int force_divisible_by,
> + double w_adj);
> #endif
> diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
> index c884c621c8..e1c6629f6d 100644
> --- a/libavfilter/vf_libplacebo.c
> +++ b/libavfilter/vf_libplacebo.c
> @@ -1201,7 +1201,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
>
> ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
> s->force_original_aspect_ratio,
> - s->force_divisible_by);
> + s->force_divisible_by, 1.f);
>
> if (s->normalize_sar || s->nb_inputs > 1) {
> /* SAR is normalized, or we have multiple inputs, set out to 1:1 */
> diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
> index 14ce1fbbd8..2eae981b57 100644
> --- a/libavfilter/vf_scale.c
> +++ b/libavfilter/vf_scale.c
> @@ -176,6 +176,7 @@ typedef struct ScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> int eval_mode; ///< expression evaluation mode
>
> @@ -645,6 +646,7 @@ static int config_props(AVFilterLink *outlink)
> outlink->src->inputs[0];
> ScaleContext *scale = ctx->priv;
> uint8_t *flags_val = NULL;
> + double w_adj = 1;
> int ret;
>
> if ((ret = scale_eval_dimensions(ctx)) < 0)
> @@ -653,9 +655,13 @@ static int config_props(AVFilterLink *outlink)
> outlink->w = scale->w;
> outlink->h = scale->h;
>
> + if (scale->reset_sar)
> + w_adj = IS_SCALE2REF(ctx) ? scale->var_values[VAR_S2R_MAIN_SAR] :
> + scale->var_values[VAR_SAR];
> +
> ret = ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
> scale->force_original_aspect_ratio,
> - scale->force_divisible_by);
> + scale->force_divisible_by, w_adj);
>
> if (ret < 0)
> goto fail;
> @@ -668,7 +674,9 @@ static int config_props(AVFilterLink *outlink)
>
> /* TODO: make algorithm configurable */
>
> - if (inlink0->sample_aspect_ratio.num){
> + if (scale->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink0->sample_aspect_ratio.num){
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink0->w, outlink->w * inlink0->h}, inlink0->sample_aspect_ratio);
> } else
> outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
> @@ -1175,6 +1183,7 @@ static const AVOption scale_options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
> { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
> { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
> diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
> index 5f9fd59118..de1883a1df 100644
> --- a/libavfilter/vf_scale_cuda.c
> +++ b/libavfilter/vf_scale_cuda.c
> @@ -96,6 +96,7 @@ typedef struct CUDAScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> CUcontext cu_ctx;
> CUmodule cu_module;
> @@ -355,6 +356,7 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> AVHWFramesContext *frames_ctx;
> AVCUDADeviceContext *device_hwctx;
> int w, h;
> + double w_adj = 1.0;
> int ret;
>
> if ((ret = ff_scale_eval_dimensions(s,
> @@ -363,8 +365,12 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> &w, &h)) < 0)
> goto fail;
>
> + if (s->reset_sar)
> + w_adj = inlink->sample_aspect_ratio.num ?
> + (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
> +
> ff_scale_adjust_dimensions(inlink, &w, &h,
> - s->force_original_aspect_ratio, s->force_divisible_by);
> + s->force_original_aspect_ratio, s->force_divisible_by, w_adj);
>
> if (((int64_t)h * inlink->w) > INT_MAX ||
> ((int64_t)w * inlink->h) > INT_MAX)
> @@ -383,7 +389,9 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> s->hwctx = device_hwctx;
> s->cu_stream = s->hwctx->stream;
>
> - if (inlink->sample_aspect_ratio.num) {
> + if (s->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink->sample_aspect_ratio.num) {
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
> outlink->w*inlink->h},
> inlink->sample_aspect_ratio);
> @@ -574,10 +582,14 @@ static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in)
> if (ret < 0)
> goto fail;
>
> - av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
> - (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
> - (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
> - INT_MAX);
> + if (s->reset_sar) {
> + out->sample_aspect_ratio = (AVRational){1, 1};
> + } else {
> + av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
> + (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
> + (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
> + INT_MAX);
> + }
>
> av_frame_free(&in);
> return ff_filter_frame(outlink, out);
> @@ -614,6 +626,7 @@ static const AVOption options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { NULL },
> };
>
> diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
> index ec3267801b..5274158f1b 100644
> --- a/libavfilter/vf_scale_npp.c
> +++ b/libavfilter/vf_scale_npp.c
> @@ -160,6 +160,7 @@ typedef struct NPPScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> int interp_algo;
>
> @@ -650,14 +651,19 @@ static int config_props(AVFilterLink *outlink)
> outlink->src->inputs[1] :
> outlink->src->inputs[0];
> NPPScaleContext *s = ctx->priv;
> + double w_adj = 1.0;
> int ret;
>
> if ((ret = nppscale_eval_dimensions(ctx)) < 0)
> goto fail;
>
> + if (s->reset_sar)
> + w_adj = IS_SCALE2REF(ctx) ? s->var_values[VAR_S2R_MAIN_SAR] :
> + s->var_values[VAR_SAR];
> +
> ff_scale_adjust_dimensions(inlink, &s->w, &s->h,
> s->force_original_aspect_ratio,
> - s->force_divisible_by);
> + s->force_divisible_by, w_adj);
>
> if (s->w > INT_MAX || s->h > INT_MAX ||
> (s->h * inlink->w) > INT_MAX ||
> @@ -674,7 +680,9 @@ static int config_props(AVFilterLink *outlink)
> av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d\n",
> inlink->w, inlink->h, outlink->w, outlink->h);
>
> - if (inlink->sample_aspect_ratio.num)
> + if (s->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink->sample_aspect_ratio.num)
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
> outlink->w*inlink->h},
> inlink->sample_aspect_ratio);
> @@ -1019,6 +1027,7 @@ static const AVOption options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, { .i64 = EVAL_MODE_INIT }, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
> { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_INIT }, 0, 0, FLAGS, .unit = "eval" },
> { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_FRAME }, 0, 0, FLAGS, .unit = "eval" },
> diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
> index 0f2d617996..ab95d41e0e 100644
> --- a/libavfilter/vf_scale_vaapi.c
> +++ b/libavfilter/vf_scale_vaapi.c
> @@ -39,6 +39,7 @@ typedef struct ScaleVAAPIContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> char *colour_primaries_string;
> char *colour_transfer_string;
> @@ -73,6 +74,7 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> AVFilterContext *avctx = outlink->src;
> VAAPIVPPContext *vpp_ctx = avctx->priv;
> ScaleVAAPIContext *ctx = avctx->priv;
> + double w_adj = 1.0;
> int err;
>
> if ((err = ff_scale_eval_dimensions(ctx,
> @@ -81,8 +83,12 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
> return err;
>
> + if (ctx->reset_sar)
> + w_adj = inlink->sample_aspect_ratio.num ?
> + (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
> +
> ff_scale_adjust_dimensions(inlink, &vpp_ctx->output_width, &vpp_ctx->output_height,
> - ctx->force_original_aspect_ratio, ctx->force_divisible_by);
> + ctx->force_original_aspect_ratio, ctx->force_divisible_by, w_adj);
>
> if (inlink->w == vpp_ctx->output_width && inlink->h == vpp_ctx->output_height &&
> (vpp_ctx->input_frames->sw_format == vpp_ctx->output_format ||
> @@ -98,7 +104,9 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - if (inlink->sample_aspect_ratio.num)
> + if (ctx->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink->sample_aspect_ratio.num)
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
> else
> outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
> @@ -274,6 +282,7 @@ static const AVOption scale_vaapi_options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
>
> { NULL },
> };
> diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c
> index 162ea8fcec..c024717bc2 100644
> --- a/libavfilter/vf_scale_vt.c
> +++ b/libavfilter/vf_scale_vt.c
> @@ -248,7 +248,7 @@ static int scale_vt_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1);
> + ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1, 1.f);
>
> outlink->w = s->output_width;
> outlink->h = s->output_height;
> diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
> index 6f99769d81..1d6492e213 100644
> --- a/libavfilter/vf_scale_vulkan.c
> +++ b/libavfilter/vf_scale_vulkan.c
> @@ -336,7 +336,7 @@ static int scale_vulkan_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1);
> + ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1, 1.f);
>
> outlink->w = vkctx->output_width;
> outlink->h = vkctx->output_height;
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar
2025-01-31 13:00 [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar Gyan Doshi
2025-02-07 4:00 ` Gyan Doshi
@ 2025-02-07 14:54 ` Leo Izen
1 sibling, 0 replies; 3+ messages in thread
From: Leo Izen @ 2025-02-07 14:54 UTC (permalink / raw)
To: ffmpeg-devel
On 1/31/25 8:00 AM, Gyan Doshi wrote:
> For anamorphic videos, enabling this option leads to adjustment of
> output dimensions to obtain square pixels when the user requests
> proportional scaling through either of the w/h expressions or
> force_original_aspect_ratio.
>
> Output SAR is always reset to 1.
>
> Option added to scale, scale_cuda, scale_npp & scale_vaapi.
>
> libplacebo already has a similar option with different semantics,
> scale_vt and scale_vulkan don't implement force_oar, so for these
> three filters, I've made minimal changes needed to not break building
> or change output.
> ---
> doc/filters.texi | 21 +++++++++++++++++++++
> libavfilter/scale_eval.c | 13 +++++++------
> libavfilter/scale_eval.h | 5 ++++-
> libavfilter/vf_libplacebo.c | 2 +-
> libavfilter/vf_scale.c | 13 +++++++++++--
> libavfilter/vf_scale_cuda.c | 25 +++++++++++++++++++------
> libavfilter/vf_scale_npp.c | 13 +++++++++++--
> libavfilter/vf_scale_vaapi.c | 13 +++++++++++--
> libavfilter/vf_scale_vt.c | 2 +-
> libavfilter/vf_scale_vulkan.c | 2 +-
> 10 files changed, 87 insertions(+), 22 deletions(-)
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index a14c7e7e77..71de1ab2dc 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -21285,6 +21285,13 @@ This option can be handy if you need to have a video fit within or exceed
> a defined resolution using @option{force_original_aspect_ratio} but also have
> encoder restrictions on width or height divisibility.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @end table
Documentation should probably state that if force_original_aspect_ratio
is set, but width and height expressions are unset, that the width of
the input is modified, but not the height. This way a user with, say, a
16:9 rip of a DVD will know that the height will be preserved.
>
> The values of the @option{w} and @option{h} options are expressions
> @@ -21538,6 +21545,13 @@ Affects the curves of the bicubic algorithm.
> @item force_divisible_by
> Work the same as the identical @ref{scale} filter options.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @end table
>
> @subsection Examples
> @@ -21641,6 +21655,13 @@ This option can be handy if you need to have a video fit within or exceed
> a defined resolution using @option{force_original_aspect_ratio} but also have
> encoder restrictions on width or height divisibility.
>
> +@item reset_sar
> +For anamorphic videos, enabling this option leads to adjustment of output dimensions
> +to obtain square pixels when the user requests proportional scaling through either of
> +the width or height expressions or through force_original_aspect_ratio.
> +Output SAR is always reset to 1.
> +Default is false.
> +
> @item eval
> Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values:
>
> diff --git a/libavfilter/scale_eval.c b/libavfilter/scale_eval.c
> index dc8d522b1e..53f5e22b0e 100644
> --- a/libavfilter/scale_eval.c
> +++ b/libavfilter/scale_eval.c
> @@ -112,7 +112,8 @@ fail:
>
> int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> int *ret_w, int *ret_h,
> - int force_original_aspect_ratio, int force_divisible_by)
> + int force_original_aspect_ratio, int force_divisible_by,
> + double w_adj)
> {
> int64_t w, h;
> int factor_w, factor_h;
> @@ -132,7 +133,7 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> }
>
> if (w < 0 && h < 0) {
> - w = inlink->w;
> + w = inlink->w * w_adj;
> h = inlink->h;
> }
>
> @@ -140,18 +141,18 @@ int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> * earlier. If no factor was set, nothing will happen as the default
> * factor is 1 */
> if (w < 0)
> - w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
> + w = av_rescale(h, inlink->w * w_adj, inlink->h * factor_w) * factor_w;
> if (h < 0)
> - h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h;
> + h = av_rescale(w, inlink->h, inlink->w * w_adj * factor_h) * factor_h;
>
> /* Note that force_original_aspect_ratio may overwrite the previous set
> * dimensions so that it is not divisible by the set factors anymore
> * unless force_divisible_by is defined as well */
> if (force_original_aspect_ratio) {
> // Including force_divisible_by here rounds to the nearest multiple of it.
> - int64_t tmp_w = av_rescale(h, inlink->w, inlink->h * (int64_t)force_divisible_by)
> + int64_t tmp_w = av_rescale(h, inlink->w * w_adj, inlink->h * (int64_t)force_divisible_by)
> * force_divisible_by;
> - int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * (int64_t)force_divisible_by)
> + int64_t tmp_h = av_rescale(w, inlink->h, inlink->w * w_adj * (int64_t)force_divisible_by)
> * force_divisible_by;
>
> if (force_original_aspect_ratio == 1) {
> diff --git a/libavfilter/scale_eval.h b/libavfilter/scale_eval.h
> index b489528404..6cab623e1c 100644
> --- a/libavfilter/scale_eval.h
> +++ b/libavfilter/scale_eval.h
> @@ -40,10 +40,13 @@ int ff_scale_eval_dimensions(void *ctx,
> * or both of the evaluated values are of the form '-n' or if
> * force_original_aspect_ratio is set. force_divisible_by is used only when
> * force_original_aspect_ratio is set and must be at least 1.
> + * w_adj is the input SAR when the output dimensions are intended to be square
> + * pixels, else should be 1.
> *
> * Returns negative error code on error or non negative on success
> */
> int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> int *ret_w, int *ret_h,
> - int force_original_aspect_ratio, int force_divisible_by);
> + int force_original_aspect_ratio, int force_divisible_by,
> + double w_adj);
> #endif
> diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
> index c884c621c8..e1c6629f6d 100644
> --- a/libavfilter/vf_libplacebo.c
> +++ b/libavfilter/vf_libplacebo.c
> @@ -1201,7 +1201,7 @@ static int libplacebo_config_output(AVFilterLink *outlink)
>
> ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
> s->force_original_aspect_ratio,
> - s->force_divisible_by);
> + s->force_divisible_by, 1.f);
>
> if (s->normalize_sar || s->nb_inputs > 1) {
> /* SAR is normalized, or we have multiple inputs, set out to 1:1 */
> diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
> index 14ce1fbbd8..2eae981b57 100644
> --- a/libavfilter/vf_scale.c
> +++ b/libavfilter/vf_scale.c
> @@ -176,6 +176,7 @@ typedef struct ScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> int eval_mode; ///< expression evaluation mode
>
> @@ -645,6 +646,7 @@ static int config_props(AVFilterLink *outlink)
> outlink->src->inputs[0];
> ScaleContext *scale = ctx->priv;
> uint8_t *flags_val = NULL;
> + double w_adj = 1;
Nit: you've initialized it as 1.0 everywhere else.
> int ret;
>
> if ((ret = scale_eval_dimensions(ctx)) < 0)
> @@ -653,9 +655,13 @@ static int config_props(AVFilterLink *outlink)
> outlink->w = scale->w;
> outlink->h = scale->h;
>
> + if (scale->reset_sar)
> + w_adj = IS_SCALE2REF(ctx) ? scale->var_values[VAR_S2R_MAIN_SAR] :
> + scale->var_values[VAR_SAR];
> +
> ret = ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
> scale->force_original_aspect_ratio,
> - scale->force_divisible_by);
> + scale->force_divisible_by, w_adj);
>
> if (ret < 0)
> goto fail;
> @@ -668,7 +674,9 @@ static int config_props(AVFilterLink *outlink)
>
> /* TODO: make algorithm configurable */
>
> - if (inlink0->sample_aspect_ratio.num){
> + if (scale->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};\
This doesn't compile on MSVC (for some reason). use av_make_q(1, 1);
(MSVC doesn't support compound initializers pre 2013, and MSVCPP has
never supported them and likely will never. I don't know why.)
> + else if (inlink0->sample_aspect_ratio.num){
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink0->w, outlink->w * inlink0->h}, inlink0->sample_aspect_ratio);
> } else
> outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
> @@ -1175,6 +1183,7 @@ static const AVOption scale_options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
> { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
> { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
> diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
> index 5f9fd59118..de1883a1df 100644
> --- a/libavfilter/vf_scale_cuda.c
> +++ b/libavfilter/vf_scale_cuda.c
> @@ -96,6 +96,7 @@ typedef struct CUDAScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> CUcontext cu_ctx;
> CUmodule cu_module;
> @@ -355,6 +356,7 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> AVHWFramesContext *frames_ctx;
> AVCUDADeviceContext *device_hwctx;
> int w, h;
> + double w_adj = 1.0;
> int ret;
>
> if ((ret = ff_scale_eval_dimensions(s,
> @@ -363,8 +365,12 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> &w, &h)) < 0)
> goto fail;
>
> + if (s->reset_sar)
> + w_adj = inlink->sample_aspect_ratio.num ?
> + (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
I believe you want to check if the denominator is nonzero here, not the
numerator. Otherwise this gives infinity.
> +
> ff_scale_adjust_dimensions(inlink, &w, &h,
> - s->force_original_aspect_ratio, s->force_divisible_by);
> + s->force_original_aspect_ratio, s->force_divisible_by, w_adj);
>
> if (((int64_t)h * inlink->w) > INT_MAX ||
> ((int64_t)w * inlink->h) > INT_MAX)
> @@ -383,7 +389,9 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
> s->hwctx = device_hwctx;
> s->cu_stream = s->hwctx->stream;
>
> - if (inlink->sample_aspect_ratio.num) {
> + if (s->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink->sample_aspect_ratio.num) {
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
> outlink->w*inlink->h},
> inlink->sample_aspect_ratio);
> @@ -574,10 +582,14 @@ static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in)
> if (ret < 0)
> goto fail;
>
> - av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
> - (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
> - (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
> - INT_MAX);
> + if (s->reset_sar) {
> + out->sample_aspect_ratio = (AVRational){1, 1};
Same comment about compound literals.
> + } else {
> + av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
> + (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
> + (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
> + INT_MAX);
> + }
>
> av_frame_free(&in);
> return ff_filter_frame(outlink, out);
> @@ -614,6 +626,7 @@ static const AVOption options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { NULL },
> };
>
> diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
> index ec3267801b..5274158f1b 100644
> --- a/libavfilter/vf_scale_npp.c
> +++ b/libavfilter/vf_scale_npp.c
> @@ -160,6 +160,7 @@ typedef struct NPPScaleContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> int interp_algo;
>
> @@ -650,14 +651,19 @@ static int config_props(AVFilterLink *outlink)
> outlink->src->inputs[1] :
> outlink->src->inputs[0];
> NPPScaleContext *s = ctx->priv;
> + double w_adj = 1.0;
> int ret;
>
> if ((ret = nppscale_eval_dimensions(ctx)) < 0)
> goto fail;
>
> + if (s->reset_sar)
> + w_adj = IS_SCALE2REF(ctx) ? s->var_values[VAR_S2R_MAIN_SAR] :
> + s->var_values[VAR_SAR];
> +
> ff_scale_adjust_dimensions(inlink, &s->w, &s->h,
> s->force_original_aspect_ratio,
> - s->force_divisible_by);
> + s->force_divisible_by, w_adj);
>
> if (s->w > INT_MAX || s->h > INT_MAX ||
> (s->h * inlink->w) > INT_MAX ||
> @@ -674,7 +680,9 @@ static int config_props(AVFilterLink *outlink)
> av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d\n",
> inlink->w, inlink->h, outlink->w, outlink->h);
>
> - if (inlink->sample_aspect_ratio.num)
> + if (s->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
Same here.
> + else if (inlink->sample_aspect_ratio.num)
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
> outlink->w*inlink->h},
> inlink->sample_aspect_ratio);
> @@ -1019,6 +1027,7 @@ static const AVOption options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
> { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, { .i64 = EVAL_MODE_INIT }, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
> { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_INIT }, 0, 0, FLAGS, .unit = "eval" },
> { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_FRAME }, 0, 0, FLAGS, .unit = "eval" },
> diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
> index 0f2d617996..ab95d41e0e 100644
> --- a/libavfilter/vf_scale_vaapi.c
> +++ b/libavfilter/vf_scale_vaapi.c
> @@ -39,6 +39,7 @@ typedef struct ScaleVAAPIContext {
>
> int force_original_aspect_ratio;
> int force_divisible_by;
> + int reset_sar;
>
> char *colour_primaries_string;
> char *colour_transfer_string;
> @@ -73,6 +74,7 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> AVFilterContext *avctx = outlink->src;
> VAAPIVPPContext *vpp_ctx = avctx->priv;
> ScaleVAAPIContext *ctx = avctx->priv;
> + double w_adj = 1.0;
> int err;
>
> if ((err = ff_scale_eval_dimensions(ctx,
> @@ -81,8 +83,12 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
> return err;
>
> + if (ctx->reset_sar)
> + w_adj = inlink->sample_aspect_ratio.num ?
> + (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
> +
Same comment.
> ff_scale_adjust_dimensions(inlink, &vpp_ctx->output_width, &vpp_ctx->output_height,
> - ctx->force_original_aspect_ratio, ctx->force_divisible_by);
> + ctx->force_original_aspect_ratio, ctx->force_divisible_by, w_adj);
>
> if (inlink->w == vpp_ctx->output_width && inlink->h == vpp_ctx->output_height &&
> (vpp_ctx->input_frames->sw_format == vpp_ctx->output_format ||
> @@ -98,7 +104,9 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - if (inlink->sample_aspect_ratio.num)
> + if (ctx->reset_sar)
> + outlink->sample_aspect_ratio = (AVRational){1, 1};
> + else if (inlink->sample_aspect_ratio.num)
> outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
> else
> outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
> @@ -274,6 +282,7 @@ static const AVOption scale_vaapi_options[] = {
> { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
> { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
> + { "reset_sar", "scale output frame to have square pixels", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
>
> { NULL },
> };
> diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c
> index 162ea8fcec..c024717bc2 100644
> --- a/libavfilter/vf_scale_vt.c
> +++ b/libavfilter/vf_scale_vt.c
> @@ -248,7 +248,7 @@ static int scale_vt_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1);
> + ff_scale_adjust_dimensions(inlink, &s->output_width, &s->output_height, 0, 1, 1.f);
>
> outlink->w = s->output_width;
> outlink->h = s->output_height;
> diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
> index 6f99769d81..1d6492e213 100644
> --- a/libavfilter/vf_scale_vulkan.c
> +++ b/libavfilter/vf_scale_vulkan.c
> @@ -336,7 +336,7 @@ static int scale_vulkan_config_output(AVFilterLink *outlink)
> if (err < 0)
> return err;
>
> - ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1);
> + ff_scale_adjust_dimensions(inlink, &vkctx->output_width, &vkctx->output_height, 0, 1, 1.f);
>
> outlink->w = vkctx->output_width;
> outlink->h = vkctx->output_height;
Overall looks fine. However, here's one possible issue I forsee happening:
A user has an NTSC DVD which is 720x480 and 16:9 DAR, or 32:27 SAR. That
user does something simple like:
ffmpeg -i dvdrip.mpg -vf scale=reset_sar=1 -c:v libx264 ...
Then, it will scale the video to 853x480, which will then fail to encode
in libx264 because it requires an even width with yuv420p. Then, the
user will change it to scale=reset_sar=1:force_divisible_by=2 and it
still won't work because force_original_aspect_ratio is unset.
I don't know if this is possibly a user issue cause the solution here is
to use reset_sar=1:force_original_aspect_ratio=1:force_divisible_by=2
In either case, it may be a good idea to automatically enable
force_original_aspect_ratio if the width and height expressions are
unset, but reset_sar is set.
- Leo Izen (Traneptora)
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-02-07 14:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-31 13:00 [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar Gyan Doshi
2025-02-07 4:00 ` Gyan Doshi
2025-02-07 14:54 ` Leo Izen
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git