mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-21 10:55:51 +02:00
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.
This commit is contained in:
parent
ff2b75d94c
commit
1b4f473d18
@ -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
|
||||
|
@ -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,10 +170,30 @@ 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;
|
||||
|
||||
/* Check if it is requested that the result has to be divisible by a some
|
||||
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 some
|
||||
* factor (w or h = -n with n being the factor). */
|
||||
factor_w = 1;
|
||||
factor_h = 1;
|
||||
@ -192,22 +210,41 @@ int ff_scale_eval_dimensions(void *log_ctx,
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (w < 0)
|
||||
w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ||
|
||||
|
@ -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 },
|
||||
};
|
||||
|
||||
|
@ -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 },
|
||||
};
|
||||
|
||||
|
@ -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 },
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user