From: Gyan Doshi <ffmpeg@gyani.pro> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH] avfilter/scale*: add option reset_sar Date: Fri, 31 Jan 2025 18:30:15 +0530 Message-ID: <20250131130015.7150-1-ffmpeg@gyani.pro> (raw) 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".
reply other threads:[~2025-01-31 13:00 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20250131130015.7150-1-ffmpeg@gyani.pro \ --to=ffmpeg@gyani.pro \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
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