diff mbox

[FFmpeg-devel] avfilter/scale.c: factorize ff_scale_eval_dimensions

Message ID 0c94949d-ef2e-5dee-0cf0-939a936014ce@gyani.pro
State Accepted
Headers show

Commit Message

Gyan Doshi Dec. 7, 2019, 6:38 a.m. UTC
On 07-12-2019 12:36 am, Michael Niedermayer wrote:
> On Wed, Dec 04, 2019 at 02:14:35PM +0530, Gyan wrote:
>> Will help reduce code duplication when adding animation support to vf_scale.
>> See Michael's last comment in https://patchwork.ffmpeg.org/patch/16272/
>>
>> Gyan
>>   doc/filters.texi             |   40 +++++++++++++++++++++++++++++
>>   libavfilter/scale.c          |   59 ++++++++++++++++++++++++++++++++++---------
>>   libavfilter/scale.h          |    4 ++
>>   libavfilter/vf_scale.c       |   28 ++------------------
>>   libavfilter/vf_scale_cuda.c  |   11 ++++++++
>>   libavfilter/vf_scale_npp.c   |   11 ++++++++
>>   libavfilter/vf_scale_vaapi.c |   11 ++++++++
>>   7 files changed, 128 insertions(+), 36 deletions(-)
>> 380bf799c14d6286cc625afe019aa553614a7d53  0001-avfilter-scale.c-factorize-ff_scale_eval_dimensions.patch
>>  From 138a8dba766674a1b017614c58fa99aeca98e9e5 Mon Sep 17 00:00:00 2001
>> From: Gyan Doshi <ffmpeg@gyani.pro>
>> Date: Mon, 2 Dec 2019 21:11:21 +0530
>> Subject: [PATCH] avfilter/scale.c: factorize ff_scale_eval_dimensions
>>
>> Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
>> Shifted code for force_original_aspect_ratio and force_divisble_by from
>> vf_scale so it is now available for scale_cuda, scale_npp and
>> scale_vaapi as well.
>> ---
>>   doc/filters.texi             | 40 ++++++++++++++++++++++++
>>   libavfilter/scale.c          | 59 +++++++++++++++++++++++++++++-------
>>   libavfilter/scale.h          |  4 +++
>>   libavfilter/vf_scale.c       | 28 ++---------------
>>   libavfilter/vf_scale_cuda.c  | 11 +++++++
>>   libavfilter/vf_scale_npp.c   | 11 +++++++
>>   libavfilter/vf_scale_vaapi.c | 11 +++++++
>>   7 files changed, 128 insertions(+), 36 deletions(-)
>>
>> diff --git a/doc/filters.texi b/doc/filters.texi
>> index 5fdec6f015..9129f7e3a5 100644
>> --- a/doc/filters.texi
>> +++ b/doc/filters.texi
>> @@ -16210,6 +16210,46 @@ Supersampling
>>   @item lanczos
>>   @end table
>>   
>> +@item force_original_aspect_ratio
>> +Enable decreasing or increasing output video width or height if necessary to
>> +keep the original aspect ratio. Possible values:
>> +
>> +@table @samp
>> +@item disable
>> +Scale the video as specified and disable this feature.
>> +
>> +@item decrease
>> +The output video dimensions will automatically be decreased if needed.
>> +
>> +@item increase
>> +The output video dimensions will automatically be increased if needed.
>> +
>> +@end table
>> +
>> +One useful instance of this option is that when you know a specific device's
>> +maximum allowed resolution, you can use this to limit the output video to
>> +that, while retaining the aspect ratio. For example, device A allows
>> +1280x720 playback, and your video is 1920x800. Using this option (set it to
>> +decrease) and specifying 1280x720 to the command line makes the output
>> +1280x533.
>> +
>> +Please note that this is a different thing than specifying -1 for @option{w}
>> +or @option{h}, you still need to specify the output resolution for this option
>> +to work.
>> +
>> +@item force_divisible_by
>> +Ensures that both the output dimensions, width and height, are divisible by the
>> +given integer when used together with @option{force_original_aspect_ratio}. This
>> +works similar to using @code{-n} in the @option{w} and @option{h} options.
>> +
>> +This option respects the value set for @option{force_original_aspect_ratio},
>> +increasing or decreasing the resolution accordingly. The video's aspect ratio
>> +may be slightly modified.
>> +
>> +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.
>> +
>>   @end table
>>   
>>   @section scale2ref
>> diff --git a/libavfilter/scale.c b/libavfilter/scale.c
>> index eaee95fac6..5e9f97230c 100644
>> --- a/libavfilter/scale.c
>> +++ b/libavfilter/scale.c
>> @@ -111,8 +111,6 @@ int ff_scale_eval_dimensions(void *log_ctx,
>>       const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
>>       const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
>>       const char *expr;
>> -    int w, h;
>> -    int factor_w, factor_h;
>>       int eval_w, eval_h;
>>       int ret;
>>       const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink;
>> @@ -172,8 +170,28 @@ int ff_scale_eval_dimensions(void *log_ctx,
>>           goto fail;
>>       eval_w = (int) res == 0 ? inlink->w : (int) res;
>>   
>> -    w = eval_w;
>> -    h = eval_h;
>> +    *ret_w = eval_w;
>> +    *ret_h = eval_h;
>> +
>> +    return 0;
>> +
>> +fail:
>> +    av_log(log_ctx, AV_LOG_ERROR,
>> +           "Error when evaluating the expression '%s'.\n"
>> +           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
>> +           expr, w_expr, h_expr);
>> +    return ret;
>> +}
>> +
>> +int ff_scale_adjust_dimensions(AVFilterLink *inlink,
>> +    int *ret_w, int *ret_h,
>> +    int force_original_aspect_ratio, int force_divisible_by)
>> +{
>> +    int w, h;
>> +    int factor_w, factor_h;
>> +
>> +    w = *ret_w;
>> +    h = *ret_h;
>>   
>>       /* Check if it is requested that the result has to be divisible by a some
>>        * factor (w or h = -n with n being the factor). */
>> @@ -199,15 +217,34 @@ int ff_scale_eval_dimensions(void *log_ctx,
>>       if (h < 0)
>>           h = av_rescale(w, inlink->h, inlink->w * 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) {
>> +        int tmp_w = av_rescale(h, inlink->w, inlink->h);
>> +        int tmp_h = av_rescale(w, inlink->h, inlink->w);
>> +
>> +        if (force_original_aspect_ratio == 1) {
>> +             w = FFMIN(tmp_w, w);
>> +             h = FFMIN(tmp_h, h);
>> +             if (force_divisible_by > 1) {
>> +                 // round down
>> +                 w = w / force_divisible_by * force_divisible_by;
>> +                 h = h / force_divisible_by * force_divisible_by;
>> +             }
>> +        } else {
>> +             w = FFMAX(tmp_w, w);
>> +             h = FFMAX(tmp_h, h);
>> +             if (force_divisible_by > 1) {
>> +                 // round up
>> +                 w = (w + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
>> +                 h = (h + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
>> +             }
>> +        }
>> +    }
>> +
>>       *ret_w = w;
>>       *ret_h = h;
>>   
>>       return 0;
>> -
>> -fail:
>> -    av_log(log_ctx, AV_LOG_ERROR,
>> -           "Error when evaluating the expression '%s'.\n"
>> -           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
>> -           expr, w_expr, h_expr);
>> -    return ret;
>>   }
>> diff --git a/libavfilter/scale.h b/libavfilter/scale.h
>> index dfe67d0be0..fa480d727a 100644
>> --- a/libavfilter/scale.h
>> +++ b/libavfilter/scale.h
>> @@ -25,4 +25,8 @@ int ff_scale_eval_dimensions(void *ctx,
>>       const char *w_expr, const char *h_expr,
>>       AVFilterLink *inlink, AVFilterLink *outlink,
>>       int *ret_w, int *ret_h);
>> +
>> +int ff_scale_adjust_dimensions(AVFilterLink *inlink,
>> +    int *ret_w, int *ret_h,
>> +    int force_original_aspect_ratio, int force_divisible_by);
>>   #endif
> This should be documented so developers know what it is, how to use it
> and what changes can be done to it without breaking code using it.
>
> That would make it easier to future contributors to work on this
> function and the code calling this function

Docs added.

Gyan
From 863c6feac1790560f7bdc29358cfcd0e5ee370f6 Mon Sep 17 00:00:00 2001
From: Gyan Doshi <ffmpeg@gyani.pro>
Date: Mon, 2 Dec 2019 21:11:21 +0530
Subject: [PATCH v2] avfilter/scale.c: factorize ff_scale_eval_dimensions

Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
Shifted code for force_original_aspect_ratio and force_divisble_by from
vf_scale so it is now available for scale_cuda, scale_npp and
scale_vaapi as well.
---
 doc/filters.texi             | 40 ++++++++++++++++++++++++
 libavfilter/scale.c          | 59 +++++++++++++++++++++++++++++-------
 libavfilter/scale.h          | 20 ++++++++++++
 libavfilter/vf_scale.c       | 28 ++---------------
 libavfilter/vf_scale_cuda.c  | 11 +++++++
 libavfilter/vf_scale_npp.c   | 11 +++++++
 libavfilter/vf_scale_vaapi.c | 11 +++++++
 7 files changed, 144 insertions(+), 36 deletions(-)

Comments

Michael Niedermayer Dec. 7, 2019, 6:17 p.m. UTC | #1
On Sat, Dec 07, 2019 at 12:08:53PM +0530, Gyan wrote:
> 
> 
> On 07-12-2019 12:36 am, Michael Niedermayer wrote:
> >On Wed, Dec 04, 2019 at 02:14:35PM +0530, Gyan wrote:
> >>Will help reduce code duplication when adding animation support to vf_scale.
> >>See Michael's last comment in https://patchwork.ffmpeg.org/patch/16272/
> >>
> >>Gyan
> >>  doc/filters.texi             |   40 +++++++++++++++++++++++++++++
> >>  libavfilter/scale.c          |   59 ++++++++++++++++++++++++++++++++++---------
> >>  libavfilter/scale.h          |    4 ++
> >>  libavfilter/vf_scale.c       |   28 ++------------------
> >>  libavfilter/vf_scale_cuda.c  |   11 ++++++++
> >>  libavfilter/vf_scale_npp.c   |   11 ++++++++
> >>  libavfilter/vf_scale_vaapi.c |   11 ++++++++
> >>  7 files changed, 128 insertions(+), 36 deletions(-)
> >>380bf799c14d6286cc625afe019aa553614a7d53  0001-avfilter-scale.c-factorize-ff_scale_eval_dimensions.patch
> >> From 138a8dba766674a1b017614c58fa99aeca98e9e5 Mon Sep 17 00:00:00 2001
> >>From: Gyan Doshi <ffmpeg@gyani.pro>
> >>Date: Mon, 2 Dec 2019 21:11:21 +0530
> >>Subject: [PATCH] avfilter/scale.c: factorize ff_scale_eval_dimensions
> >>
> >>Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
> >>Shifted code for force_original_aspect_ratio and force_divisble_by from
> >>vf_scale so it is now available for scale_cuda, scale_npp and
> >>scale_vaapi as well.
> >>---
> >>  doc/filters.texi             | 40 ++++++++++++++++++++++++
> >>  libavfilter/scale.c          | 59 +++++++++++++++++++++++++++++-------
> >>  libavfilter/scale.h          |  4 +++
> >>  libavfilter/vf_scale.c       | 28 ++---------------
> >>  libavfilter/vf_scale_cuda.c  | 11 +++++++
> >>  libavfilter/vf_scale_npp.c   | 11 +++++++
> >>  libavfilter/vf_scale_vaapi.c | 11 +++++++
> >>  7 files changed, 128 insertions(+), 36 deletions(-)
> >>
> >>diff --git a/doc/filters.texi b/doc/filters.texi
> >>index 5fdec6f015..9129f7e3a5 100644
> >>--- a/doc/filters.texi
> >>+++ b/doc/filters.texi
> >>@@ -16210,6 +16210,46 @@ Supersampling
> >>  @item lanczos
> >>  @end table
> >>+@item force_original_aspect_ratio
> >>+Enable decreasing or increasing output video width or height if necessary to
> >>+keep the original aspect ratio. Possible values:
> >>+
> >>+@table @samp
> >>+@item disable
> >>+Scale the video as specified and disable this feature.
> >>+
> >>+@item decrease
> >>+The output video dimensions will automatically be decreased if needed.
> >>+
> >>+@item increase
> >>+The output video dimensions will automatically be increased if needed.
> >>+
> >>+@end table
> >>+
> >>+One useful instance of this option is that when you know a specific device's
> >>+maximum allowed resolution, you can use this to limit the output video to
> >>+that, while retaining the aspect ratio. For example, device A allows
> >>+1280x720 playback, and your video is 1920x800. Using this option (set it to
> >>+decrease) and specifying 1280x720 to the command line makes the output
> >>+1280x533.
> >>+
> >>+Please note that this is a different thing than specifying -1 for @option{w}
> >>+or @option{h}, you still need to specify the output resolution for this option
> >>+to work.
> >>+
> >>+@item force_divisible_by
> >>+Ensures that both the output dimensions, width and height, are divisible by the
> >>+given integer when used together with @option{force_original_aspect_ratio}. This
> >>+works similar to using @code{-n} in the @option{w} and @option{h} options.
> >>+
> >>+This option respects the value set for @option{force_original_aspect_ratio},
> >>+increasing or decreasing the resolution accordingly. The video's aspect ratio
> >>+may be slightly modified.
> >>+
> >>+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.
> >>+
> >>  @end table
> >>  @section scale2ref
> >>diff --git a/libavfilter/scale.c b/libavfilter/scale.c
> >>index eaee95fac6..5e9f97230c 100644
> >>--- a/libavfilter/scale.c
> >>+++ b/libavfilter/scale.c
> >>@@ -111,8 +111,6 @@ int ff_scale_eval_dimensions(void *log_ctx,
> >>      const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
> >>      const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
> >>      const char *expr;
> >>-    int w, h;
> >>-    int factor_w, factor_h;
> >>      int eval_w, eval_h;
> >>      int ret;
> >>      const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink;
> >>@@ -172,8 +170,28 @@ int ff_scale_eval_dimensions(void *log_ctx,
> >>          goto fail;
> >>      eval_w = (int) res == 0 ? inlink->w : (int) res;
> >>-    w = eval_w;
> >>-    h = eval_h;
> >>+    *ret_w = eval_w;
> >>+    *ret_h = eval_h;
> >>+
> >>+    return 0;
> >>+
> >>+fail:
> >>+    av_log(log_ctx, AV_LOG_ERROR,
> >>+           "Error when evaluating the expression '%s'.\n"
> >>+           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
> >>+           expr, w_expr, h_expr);
> >>+    return ret;
> >>+}
> >>+
> >>+int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> >>+    int *ret_w, int *ret_h,
> >>+    int force_original_aspect_ratio, int force_divisible_by)
> >>+{
> >>+    int w, h;
> >>+    int factor_w, factor_h;
> >>+
> >>+    w = *ret_w;
> >>+    h = *ret_h;
> >>      /* Check if it is requested that the result has to be divisible by a some
> >>       * factor (w or h = -n with n being the factor). */
> >>@@ -199,15 +217,34 @@ int ff_scale_eval_dimensions(void *log_ctx,
> >>      if (h < 0)
> >>          h = av_rescale(w, inlink->h, inlink->w * 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) {
> >>+        int tmp_w = av_rescale(h, inlink->w, inlink->h);
> >>+        int tmp_h = av_rescale(w, inlink->h, inlink->w);
> >>+
> >>+        if (force_original_aspect_ratio == 1) {
> >>+             w = FFMIN(tmp_w, w);
> >>+             h = FFMIN(tmp_h, h);
> >>+             if (force_divisible_by > 1) {
> >>+                 // round down
> >>+                 w = w / force_divisible_by * force_divisible_by;
> >>+                 h = h / force_divisible_by * force_divisible_by;
> >>+             }
> >>+        } else {
> >>+             w = FFMAX(tmp_w, w);
> >>+             h = FFMAX(tmp_h, h);
> >>+             if (force_divisible_by > 1) {
> >>+                 // round up
> >>+                 w = (w + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
> >>+                 h = (h + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
> >>+             }
> >>+        }
> >>+    }
> >>+
> >>      *ret_w = w;
> >>      *ret_h = h;
> >>      return 0;
> >>-
> >>-fail:
> >>-    av_log(log_ctx, AV_LOG_ERROR,
> >>-           "Error when evaluating the expression '%s'.\n"
> >>-           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
> >>-           expr, w_expr, h_expr);
> >>-    return ret;
> >>  }
> >>diff --git a/libavfilter/scale.h b/libavfilter/scale.h
> >>index dfe67d0be0..fa480d727a 100644
> >>--- a/libavfilter/scale.h
> >>+++ b/libavfilter/scale.h
> >>@@ -25,4 +25,8 @@ int ff_scale_eval_dimensions(void *ctx,
> >>      const char *w_expr, const char *h_expr,
> >>      AVFilterLink *inlink, AVFilterLink *outlink,
> >>      int *ret_w, int *ret_h);
> >>+
> >>+int ff_scale_adjust_dimensions(AVFilterLink *inlink,
> >>+    int *ret_w, int *ret_h,
> >>+    int force_original_aspect_ratio, int force_divisible_by);
> >>  #endif
> >This should be documented so developers know what it is, how to use it
> >and what changes can be done to it without breaking code using it.
> >
> >That would make it easier to future contributors to work on this
> >function and the code calling this function
> 
> Docs added.
> 
> Gyan

>  doc/filters.texi             |   40 +++++++++++++++++++++++++++++
>  libavfilter/scale.c          |   59 ++++++++++++++++++++++++++++++++++---------
>  libavfilter/scale.h          |   20 ++++++++++++++
>  libavfilter/vf_scale.c       |   28 ++------------------
>  libavfilter/vf_scale_cuda.c  |   11 ++++++++
>  libavfilter/vf_scale_npp.c   |   11 ++++++++
>  libavfilter/vf_scale_vaapi.c |   11 ++++++++
>  7 files changed, 144 insertions(+), 36 deletions(-)
> f0a65d11857e709ee7cdf862ba108c765c4f5a2f  v2-0001-avfilter-scale.c-factorize-ff_scale_eval_dimensio.patch
> From 863c6feac1790560f7bdc29358cfcd0e5ee370f6 Mon Sep 17 00:00:00 2001
> From: Gyan Doshi <ffmpeg@gyani.pro>
> Date: Mon, 2 Dec 2019 21:11:21 +0530
> Subject: [PATCH v2] avfilter/scale.c: factorize ff_scale_eval_dimensions
> 
> Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
> Shifted code for force_original_aspect_ratio and force_divisble_by from
> vf_scale so it is now available for scale_cuda, scale_npp and
> scale_vaapi as well.
> ---
>  doc/filters.texi             | 40 ++++++++++++++++++++++++
>  libavfilter/scale.c          | 59 +++++++++++++++++++++++++++++-------
>  libavfilter/scale.h          | 20 ++++++++++++
>  libavfilter/vf_scale.c       | 28 ++---------------
>  libavfilter/vf_scale_cuda.c  | 11 +++++++
>  libavfilter/vf_scale_npp.c   | 11 +++++++
>  libavfilter/vf_scale_vaapi.c | 11 +++++++
>  7 files changed, 144 insertions(+), 36 deletions(-)

The changes should be ok i think.

Thanks

[...]
Gyan Doshi Dec. 8, 2019, 4:33 a.m. UTC | #2
On 07-12-2019 11:47 pm, Michael Niedermayer wrote:
> On Sat, Dec 07, 2019 at 12:08:53PM +0530, Gyan wrote:
>
>>   doc/filters.texi             |   40 +++++++++++++++++++++++++++++
>>   libavfilter/scale.c          |   59 ++++++++++++++++++++++++++++++++++---------
>>   libavfilter/scale.h          |   20 ++++++++++++++
>>   libavfilter/vf_scale.c       |   28 ++------------------
>>   libavfilter/vf_scale_cuda.c  |   11 ++++++++
>>   libavfilter/vf_scale_npp.c   |   11 ++++++++
>>   libavfilter/vf_scale_vaapi.c |   11 ++++++++
>>   7 files changed, 144 insertions(+), 36 deletions(-)
>> f0a65d11857e709ee7cdf862ba108c765c4f5a2f  v2-0001-avfilter-scale.c-factorize-ff_scale_eval_dimensio.patch
>>  From 863c6feac1790560f7bdc29358cfcd0e5ee370f6 Mon Sep 17 00:00:00 2001
>> From: Gyan Doshi <ffmpeg@gyani.pro>
>> Date: Mon, 2 Dec 2019 21:11:21 +0530
>> Subject: [PATCH v2] avfilter/scale.c: factorize ff_scale_eval_dimensions
>>
>> Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
>> Shifted code for force_original_aspect_ratio and force_divisble_by from
>> vf_scale so it is now available for scale_cuda, scale_npp and
>> scale_vaapi as well.
>> ---
>>   doc/filters.texi             | 40 ++++++++++++++++++++++++
>>   libavfilter/scale.c          | 59 +++++++++++++++++++++++++++++-------
>>   libavfilter/scale.h          | 20 ++++++++++++
>>   libavfilter/vf_scale.c       | 28 ++---------------
>>   libavfilter/vf_scale_cuda.c  | 11 +++++++
>>   libavfilter/vf_scale_npp.c   | 11 +++++++
>>   libavfilter/vf_scale_vaapi.c | 11 +++++++
>>   7 files changed, 144 insertions(+), 36 deletions(-)
> The changes should be ok i think.

Will push in a few hours.

Thanks,
Gyan
Gyan Doshi Dec. 8, 2019, 10:46 a.m. UTC | #3
On 08-12-2019 10:03 am, Gyan wrote:
>
>
> On 07-12-2019 11:47 pm, Michael Niedermayer wrote:
>> On Sat, Dec 07, 2019 at 12:08:53PM +0530, Gyan wrote:
>>
>>>   doc/filters.texi             |   40 +++++++++++++++++++++++++++++
>>>   libavfilter/scale.c          |   59 
>>> ++++++++++++++++++++++++++++++++++---------
>>>   libavfilter/scale.h          |   20 ++++++++++++++
>>>   libavfilter/vf_scale.c       |   28 ++------------------
>>>   libavfilter/vf_scale_cuda.c  |   11 ++++++++
>>>   libavfilter/vf_scale_npp.c   |   11 ++++++++
>>>   libavfilter/vf_scale_vaapi.c |   11 ++++++++
>>>   7 files changed, 144 insertions(+), 36 deletions(-)
>>> f0a65d11857e709ee7cdf862ba108c765c4f5a2f 
>>> v2-0001-avfilter-scale.c-factorize-ff_scale_eval_dimensio.patch
>>>  From 863c6feac1790560f7bdc29358cfcd0e5ee370f6 Mon Sep 17 00:00:00 2001
>>> From: Gyan Doshi <ffmpeg@gyani.pro>
>>> Date: Mon, 2 Dec 2019 21:11:21 +0530
>>> Subject: [PATCH v2] avfilter/scale.c: factorize 
>>> ff_scale_eval_dimensions
>>>
>>> Adjustment of evaluated values shifted to ff_adjust_scale_dimensions
>>> Shifted code for force_original_aspect_ratio and force_divisble_by from
>>> vf_scale so it is now available for scale_cuda, scale_npp and
>>> scale_vaapi as well.
>>> ---
>>>   doc/filters.texi             | 40 ++++++++++++++++++++++++
>>>   libavfilter/scale.c          | 59 
>>> +++++++++++++++++++++++++++++-------
>>>   libavfilter/scale.h          | 20 ++++++++++++
>>>   libavfilter/vf_scale.c       | 28 ++---------------
>>>   libavfilter/vf_scale_cuda.c  | 11 +++++++
>>>   libavfilter/vf_scale_npp.c   | 11 +++++++
>>>   libavfilter/vf_scale_vaapi.c | 11 +++++++
>>>   7 files changed, 144 insertions(+), 36 deletions(-)
>> The changes should be ok i think.
>
> Will push in a few hours.

Pushed with a couple of doc typos also corrected as 
1b4f473d181abaa0ff4e2d63862f61763a5a6860

Gyan
diff mbox

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index 5fdec6f015..9129f7e3a5 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -16210,6 +16210,46 @@  Supersampling
 @item lanczos
 @end table
 
+@item force_original_aspect_ratio
+Enable decreasing or increasing output video width or height if necessary to
+keep the original aspect ratio. Possible values:
+
+@table @samp
+@item disable
+Scale the video as specified and disable this feature.
+
+@item decrease
+The output video dimensions will automatically be decreased if needed.
+
+@item increase
+The output video dimensions will automatically be increased if needed.
+
+@end table
+
+One useful instance of this option is that when you know a specific device's
+maximum allowed resolution, you can use this to limit the output video to
+that, while retaining the aspect ratio. For example, device A allows
+1280x720 playback, and your video is 1920x800. Using this option (set it to
+decrease) and specifying 1280x720 to the command line makes the output
+1280x533.
+
+Please note that this is a different thing than specifying -1 for @option{w}
+or @option{h}, you still need to specify the output resolution for this option
+to work.
+
+@item force_divisible_by
+Ensures that both the output dimensions, width and height, are divisible by the
+given integer when used together with @option{force_original_aspect_ratio}. This
+works similar to using @code{-n} in the @option{w} and @option{h} options.
+
+This option respects the value set for @option{force_original_aspect_ratio},
+increasing or decreasing the resolution accordingly. The video's aspect ratio
+may be slightly modified.
+
+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.
+
 @end table
 
 @section scale2ref
diff --git a/libavfilter/scale.c b/libavfilter/scale.c
index eaee95fac6..5e9f97230c 100644
--- a/libavfilter/scale.c
+++ b/libavfilter/scale.c
@@ -111,8 +111,6 @@  int ff_scale_eval_dimensions(void *log_ctx,
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
     const char *expr;
-    int w, h;
-    int factor_w, factor_h;
     int eval_w, eval_h;
     int ret;
     const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink;
@@ -172,8 +170,28 @@  int ff_scale_eval_dimensions(void *log_ctx,
         goto fail;
     eval_w = (int) res == 0 ? inlink->w : (int) res;
 
-    w = eval_w;
-    h = eval_h;
+    *ret_w = eval_w;
+    *ret_h = eval_h;
+
+    return 0;
+
+fail:
+    av_log(log_ctx, AV_LOG_ERROR,
+           "Error when evaluating the expression '%s'.\n"
+           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
+           expr, w_expr, h_expr);
+    return ret;
+}
+
+int ff_scale_adjust_dimensions(AVFilterLink *inlink,
+    int *ret_w, int *ret_h,
+    int force_original_aspect_ratio, int force_divisible_by)
+{
+    int w, h;
+    int factor_w, factor_h;
+
+    w = *ret_w;
+    h = *ret_h;
 
     /* Check if it is requested that the result has to be divisible by a some
      * factor (w or h = -n with n being the factor). */
@@ -199,15 +217,34 @@  int ff_scale_eval_dimensions(void *log_ctx,
     if (h < 0)
         h = av_rescale(w, inlink->h, inlink->w * 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) {
+        int tmp_w = av_rescale(h, inlink->w, inlink->h);
+        int tmp_h = av_rescale(w, inlink->h, inlink->w);
+
+        if (force_original_aspect_ratio == 1) {
+             w = FFMIN(tmp_w, w);
+             h = FFMIN(tmp_h, h);
+             if (force_divisible_by > 1) {
+                 // round down
+                 w = w / force_divisible_by * force_divisible_by;
+                 h = h / force_divisible_by * force_divisible_by;
+             }
+        } else {
+             w = FFMAX(tmp_w, w);
+             h = FFMAX(tmp_h, h);
+             if (force_divisible_by > 1) {
+                 // round up
+                 w = (w + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
+                 h = (h + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
+             }
+        }
+    }
+
     *ret_w = w;
     *ret_h = h;
 
     return 0;
-
-fail:
-    av_log(log_ctx, AV_LOG_ERROR,
-           "Error when evaluating the expression '%s'.\n"
-           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
-           expr, w_expr, h_expr);
-    return ret;
 }
diff --git a/libavfilter/scale.h b/libavfilter/scale.h
index dfe67d0be0..6e1c8a1f4c 100644
--- a/libavfilter/scale.h
+++ b/libavfilter/scale.h
@@ -21,8 +21,28 @@ 
 
 #include "avfilter.h"
 
+/**
+ * Parse and evaluate string expressions for width and height. Upon success,
+ * ff_scale_adjust_dimensions must be called with evaluated width and height
+ * to obtain actual target dimensions.
+ *
+ * Returns 0 upon success, negative value if one of the expressions could
+ * not be parsed or if NaN was the result of their evaluation.
+ */
 int ff_scale_eval_dimensions(void *ctx,
     const char *w_expr, const char *h_expr,
     AVFilterLink *inlink, AVFilterLink *outlink,
     int *ret_w, int *ret_h);
+
+/**
+ * Transform evaluated width and height obtained from ff_scale_eval_dimensions
+ * into actual target width and height for scaling. Adjustment can occur if one
+ * or both of the evaluated values are of the form '-n' or if
+ * force_original_aspect_ratio is set.
+ *
+ * Returns 0.
+ */
+int ff_scale_adjust_dimensions(AVFilterLink *inlink,
+    int *ret_w, int *ret_h,
+    int force_original_aspect_ratio, int force_divisible_by);
 #endif
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 41ddec7661..b7f541be1f 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -237,31 +237,9 @@  static int config_props(AVFilterLink *outlink)
                                         &w, &h)) < 0)
         goto fail;
 
-    /* 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 (scale->force_original_aspect_ratio) {
-        int tmp_w = av_rescale(h, inlink->w, inlink->h);
-        int tmp_h = av_rescale(w, inlink->h, inlink->w);
-
-        if (scale->force_original_aspect_ratio == 1) {
-             w = FFMIN(tmp_w, w);
-             h = FFMIN(tmp_h, h);
-             if (scale->force_divisible_by > 1) {
-                 // round down
-                 w = w / scale->force_divisible_by * scale->force_divisible_by;
-                 h = h / scale->force_divisible_by * scale->force_divisible_by;
-             }
-        } else {
-             w = FFMAX(tmp_w, w);
-             h = FFMAX(tmp_h, h);
-             if (scale->force_divisible_by > 1) {
-                 // round up
-                 w = (w + scale->force_divisible_by - 1) / scale->force_divisible_by * scale->force_divisible_by;
-                 h = (h + scale->force_divisible_by - 1) / scale->force_divisible_by * scale->force_divisible_by;
-             }
-        }
-    }
+    ff_scale_adjust_dimensions(inlink, &w, &h,
+                               scale->force_original_aspect_ratio,
+                               scale->force_divisible_by);
 
     if (w > INT_MAX || h > INT_MAX ||
         (h * inlink->w) > INT_MAX  ||
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 0a73ea1422..cca68dd835 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -82,6 +82,9 @@  typedef struct CUDAScaleContext {
     char *w_expr;               ///< width  expression string
     char *h_expr;               ///< height expression string
 
+    int force_original_aspect_ratio;
+    int force_divisible_by;
+
     CUcontext   cu_ctx;
     CUmodule    cu_module;
     CUfunction  cu_func_uchar;
@@ -305,6 +308,9 @@  static av_cold int cudascale_config_props(AVFilterLink *outlink)
                                         &w, &h)) < 0)
         goto fail;
 
+    ff_scale_adjust_dimensions(inlink, &w, &h,
+                               s->force_original_aspect_ratio, s->force_divisible_by);
+
     if (((int64_t)h * inlink->w) > INT_MAX  ||
         ((int64_t)w * inlink->h) > INT_MAX)
         av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
@@ -536,6 +542,11 @@  fail:
 static const AVOption options[] = {
     { "w",      "Output video width",  OFFSET(w_expr),     AV_OPT_TYPE_STRING, { .str = "iw"   }, .flags = FLAGS },
     { "h",      "Output video height", OFFSET(h_expr),     AV_OPT_TYPE_STRING, { .str = "ih"   }, .flags = FLAGS },
+    { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
+    { "disable",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
+    { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
+    { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "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 },
     { NULL },
 };
 
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index a3e085764a..09c3d51727 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -98,6 +98,9 @@  typedef struct NPPScaleContext {
     char *h_expr;               ///< height expression string
     char *format_str;
 
+    int force_original_aspect_ratio;
+    int force_divisible_by;
+
     int interp_algo;
 } NPPScaleContext;
 
@@ -347,6 +350,9 @@  static int nppscale_config_props(AVFilterLink *outlink)
                                         &w, &h)) < 0)
         goto fail;
 
+    ff_scale_adjust_dimensions(inlink, &w, &h,
+                               s->force_original_aspect_ratio, s->force_divisible_by);
+
     if (((int64_t)h * inlink->w) > INT_MAX  ||
         ((int64_t)w * inlink->h) > INT_MAX)
         av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
@@ -552,6 +558,11 @@  static const AVOption options[] = {
         { "cubic2p_b05c03",     "2-parameter cubic (B=1/2, C=3/10)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_B05C03     }, 0, 0, FLAGS, "interp_algo" },
         { "super",              "supersampling",                     0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER              }, 0, 0, FLAGS, "interp_algo" },
         { "lanczos",            "Lanczos",                           0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LANCZOS            }, 0, 0, FLAGS, "interp_algo" },
+    { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
+    { "disable",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
+    { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
+    { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "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 },
     { NULL },
 };
 
diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
index c32395ac09..88642cbe73 100644
--- a/libavfilter/vf_scale_vaapi.c
+++ b/libavfilter/vf_scale_vaapi.c
@@ -40,6 +40,9 @@  typedef struct ScaleVAAPIContext {
     char *w_expr;      // width expression string
     char *h_expr;      // height expression string
 
+    int force_original_aspect_ratio;
+    int force_divisible_by;
+
     char *colour_primaries_string;
     char *colour_transfer_string;
     char *colour_matrix_string;
@@ -81,6 +84,9 @@  static int scale_vaapi_config_output(AVFilterLink *outlink)
                                         &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
         return err;
 
+    ff_scale_adjust_dimensions(inlink, &vpp_ctx->output_width, &vpp_ctx->output_height,
+                               ctx->force_original_aspect_ratio, ctx->force_divisible_by);
+
     err = ff_vaapi_vpp_config_output(outlink);
     if (err < 0)
         return err;
@@ -247,6 +253,11 @@  static const AVOption scale_vaapi_options[] = {
     { "out_chroma_location", "Output chroma sample location",
       OFFSET(chroma_location_string),  AV_OPT_TYPE_STRING,
       { .str = NULL }, .flags = FLAGS },
+    { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
+    { "disable",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
+    { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
+    { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "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 },
 
     { NULL },
 };