* [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar
@ 2025-01-31 13:00 Gyan Doshi
0 siblings, 0 replies; only message 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] only message in thread
only message in thread, other threads:[~2025-01-31 13:00 UTC | newest]
Thread overview: (only message) (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
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