Commit 1b4f473d authored by Gyan Doshi's avatar Gyan Doshi

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.
parent ff2b75d9
...@@ -16210,6 +16210,46 @@ Supersampling ...@@ -16210,6 +16210,46 @@ Supersampling
@item lanczos @item lanczos
@end table @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 @end table
@section scale2ref @section scale2ref
......
...@@ -111,8 +111,6 @@ int ff_scale_eval_dimensions(void *log_ctx, ...@@ -111,8 +111,6 @@ int ff_scale_eval_dimensions(void *log_ctx,
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format); const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
const char *expr; const char *expr;
int w, h;
int factor_w, factor_h;
int eval_w, eval_h; int eval_w, eval_h;
int ret; int ret;
const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink; const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink;
...@@ -172,10 +170,30 @@ int ff_scale_eval_dimensions(void *log_ctx, ...@@ -172,10 +170,30 @@ int ff_scale_eval_dimensions(void *log_ctx,
goto fail; goto fail;
eval_w = (int) res == 0 ? inlink->w : (int) res; eval_w = (int) res == 0 ? inlink->w : (int) res;
w = eval_w; *ret_w = eval_w;
h = eval_h; *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 /* Check if it is requested that the result has to be divisible by some
* factor (w or h = -n with n being the factor). */ * factor (w or h = -n with n being the factor). */
factor_w = 1; factor_w = 1;
factor_h = 1; factor_h = 1;
...@@ -192,22 +210,41 @@ int ff_scale_eval_dimensions(void *log_ctx, ...@@ -192,22 +210,41 @@ int ff_scale_eval_dimensions(void *log_ctx,
} }
/* Make sure that the result is divisible by the factor we determined /* Make sure that the result is divisible by the factor we determined
* earlier. If no factor was set, it is nothing will happen as the default * earlier. If no factor was set, nothing will happen as the default
* factor is 1 */ * factor is 1 */
if (w < 0) if (w < 0)
w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w; w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
if (h < 0) if (h < 0)
h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h; 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_w = w;
*ret_h = h; *ret_h = h;
return 0; 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;
} }
...@@ -21,8 +21,28 @@ ...@@ -21,8 +21,28 @@
#include "avfilter.h" #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, int ff_scale_eval_dimensions(void *ctx,
const char *w_expr, const char *h_expr, const char *w_expr, const char *h_expr,
AVFilterLink *inlink, AVFilterLink *outlink, AVFilterLink *inlink, AVFilterLink *outlink,
int *ret_w, int *ret_h); 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 #endif
...@@ -237,31 +237,9 @@ static int config_props(AVFilterLink *outlink) ...@@ -237,31 +237,9 @@ static int config_props(AVFilterLink *outlink)
&w, &h)) < 0) &w, &h)) < 0)
goto fail; goto fail;
/* Note that force_original_aspect_ratio may overwrite the previous set ff_scale_adjust_dimensions(inlink, &w, &h,
* dimensions so that it is not divisible by the set factors anymore scale->force_original_aspect_ratio,
* unless force_divisible_by is defined as well */ scale->force_divisible_by);
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;
}
}
}
if (w > INT_MAX || h > INT_MAX || if (w > INT_MAX || h > INT_MAX ||
(h * inlink->w) > INT_MAX || (h * inlink->w) > INT_MAX ||
......
...@@ -82,6 +82,9 @@ typedef struct CUDAScaleContext { ...@@ -82,6 +82,9 @@ typedef struct CUDAScaleContext {
char *w_expr; ///< width expression string char *w_expr; ///< width expression string
char *h_expr; ///< height expression string char *h_expr; ///< height expression string
int force_original_aspect_ratio;
int force_divisible_by;
CUcontext cu_ctx; CUcontext cu_ctx;
CUmodule cu_module; CUmodule cu_module;
CUfunction cu_func_uchar; CUfunction cu_func_uchar;
...@@ -305,6 +308,9 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink) ...@@ -305,6 +308,9 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink)
&w, &h)) < 0) &w, &h)) < 0)
goto fail; 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 || if (((int64_t)h * inlink->w) > INT_MAX ||
((int64_t)w * inlink->h) > 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"); av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
...@@ -536,6 +542,11 @@ fail: ...@@ -536,6 +542,11 @@ fail:
static const AVOption options[] = { static const AVOption options[] = {
{ "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS }, { "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 }, { "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 }, { NULL },
}; };
......
...@@ -98,6 +98,9 @@ typedef struct NPPScaleContext { ...@@ -98,6 +98,9 @@ typedef struct NPPScaleContext {
char *h_expr; ///< height expression string char *h_expr; ///< height expression string
char *format_str; char *format_str;
int force_original_aspect_ratio;
int force_divisible_by;
int interp_algo; int interp_algo;
} NPPScaleContext; } NPPScaleContext;
...@@ -347,6 +350,9 @@ static int nppscale_config_props(AVFilterLink *outlink) ...@@ -347,6 +350,9 @@ static int nppscale_config_props(AVFilterLink *outlink)
&w, &h)) < 0) &w, &h)) < 0)
goto fail; 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 || if (((int64_t)h * inlink->w) > INT_MAX ||
((int64_t)w * inlink->h) > 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"); av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
...@@ -552,6 +558,11 @@ static const AVOption options[] = { ...@@ -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" }, { "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" }, { "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" }, { "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 }, { NULL },
}; };
......
...@@ -40,6 +40,9 @@ typedef struct ScaleVAAPIContext { ...@@ -40,6 +40,9 @@ typedef struct ScaleVAAPIContext {
char *w_expr; // width expression string char *w_expr; // width expression string
char *h_expr; // height expression string char *h_expr; // height expression string
int force_original_aspect_ratio;
int force_divisible_by;
char *colour_primaries_string; char *colour_primaries_string;
char *colour_transfer_string; char *colour_transfer_string;
char *colour_matrix_string; char *colour_matrix_string;
...@@ -81,6 +84,9 @@ static int scale_vaapi_config_output(AVFilterLink *outlink) ...@@ -81,6 +84,9 @@ static int scale_vaapi_config_output(AVFilterLink *outlink)
&vpp_ctx->output_width, &vpp_ctx->output_height)) < 0) &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
return err; 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); err = ff_vaapi_vpp_config_output(outlink);
if (err < 0) if (err < 0)
return err; return err;
...@@ -247,6 +253,11 @@ static const AVOption scale_vaapi_options[] = { ...@@ -247,6 +253,11 @@ static const AVOption scale_vaapi_options[] = {
{ "out_chroma_location", "Output chroma sample location", { "out_chroma_location", "Output chroma sample location",
OFFSET(chroma_location_string), AV_OPT_TYPE_STRING, OFFSET(chroma_location_string), AV_OPT_TYPE_STRING,
{ .str = NULL }, .flags = FLAGS }, { .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 }, { NULL },
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment