Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [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