diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index 50609f978a..4f9268256c 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -335,6 +335,10 @@ Available mpv-only filters are: but values such as ``[16:9]`` can be passed too (``[...]`` for quoting to prevent the option parser from interpreting the ``:`` character). + ```` + Force a specific scaler backend, if applicable. This is a debug option + and could go away any time. + ``lavfi=graph[:sws-flags[:o=opts]]`` Filter video using FFmpeg's libavfilter. diff --git a/filters/f_autoconvert.c b/filters/f_autoconvert.c index 5e0caaf321..7452a13ae8 100644 --- a/filters/f_autoconvert.c +++ b/filters/f_autoconvert.c @@ -244,6 +244,8 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log, goto fail; } + sws->force_scaler = c->force_scaler; + int out = mp_sws_find_best_out_format(sws, src_fmt, fmts, num_fmts); if (!out) { mp_err(log, "can't find video conversion for %s\n", diff --git a/filters/f_autoconvert.h b/filters/f_autoconvert.h index 7cb144aa59..6d6660c46a 100644 --- a/filters/f_autoconvert.h +++ b/filters/f_autoconvert.h @@ -1,6 +1,7 @@ #pragma once #include "filter.h" +#include "video/sws_utils.h" struct mp_image; struct mp_image_params; @@ -12,6 +13,8 @@ struct mp_autoconvert { // f->pins[0] is input, f->pins[1] is output struct mp_filter *f; + enum mp_sws_scaler force_scaler; + // If this is set, the callback is invoked (from the process function), and // further data flow is blocked until mp_autoconvert_format_change_continue() // is called. The idea is that you can reselect the output parameters on diff --git a/filters/f_swscale.c b/filters/f_swscale.c index f9af4d18fb..614de1466c 100644 --- a/filters/f_swscale.c +++ b/filters/f_swscale.c @@ -43,6 +43,8 @@ int mp_sws_find_best_out_format(struct mp_sws_filter *sws, int in_format, int *out_formats, int num_out_formats) { + sws->sws->force_scaler = sws->force_scaler; + int best = 0; for (int n = 0; n < num_out_formats; n++) { int out_format = out_formats[n]; @@ -73,6 +75,8 @@ static void process(struct mp_filter *f) if (!mp_pin_can_transfer_data(f->ppins[1], f->ppins[0])) return; + s->sws->force_scaler = s->force_scaler; + struct mp_frame frame = mp_pin_out_read(f->ppins[0]); if (mp_frame_is_signaling(frame)) { mp_pin_in_write(f->ppins[1], frame); diff --git a/filters/f_swscale.h b/filters/f_swscale.h index 861ad029dd..3ee7455ecd 100644 --- a/filters/f_swscale.h +++ b/filters/f_swscale.h @@ -3,6 +3,7 @@ #include #include "video/mp_image.h" +#include "video/sws_utils.h" struct mp_sws_filter { struct mp_filter *f; @@ -11,6 +12,8 @@ struct mp_sws_filter { // If set, force all image params; ignores out_format. bool use_out_params; struct mp_image_params out_params; + // Other options. + enum mp_sws_scaler force_scaler; // private state struct mp_sws_context *sws; struct mp_image_pool *pool; diff --git a/video/filter/vf_format.c b/video/filter/vf_format.c index a2adcca54a..793e37bc4a 100644 --- a/video/filter/vf_format.c +++ b/video/filter/vf_format.c @@ -54,6 +54,7 @@ struct vf_format_opts { int dw, dh; double dar; int convert; + int force_scaler; }; static void set_params(struct vf_format_opts *p, struct mp_image_params *out, @@ -175,6 +176,8 @@ static struct mp_filter *vf_format_create(struct mp_filter *parent, void *option return NULL; } + priv->conv->force_scaler = priv->opts->force_scaler; + if (priv->opts->fmt) mp_autoconvert_add_imgfmt(priv->conv, priv->opts->fmt, 0); @@ -199,6 +202,10 @@ static const m_option_t vf_opts_fields[] = { {"dh", OPT_INT(dh)}, {"dar", OPT_DOUBLE(dar)}, {"convert", OPT_FLAG(convert)}, + {"force-scaler", OPT_CHOICE(force_scaler, + {"auto", MP_SWS_AUTO}, + {"sws", MP_SWS_SWS}, + {"zimg", MP_SWS_ZIMG})}, {"outputlevels", OPT_REMOVED("use the --video-output-levels global option")}, {"peak", OPT_REMOVED("use sig-peak instead (changed value scale!)")}, {0} diff --git a/video/sws_utils.c b/video/sws_utils.c index ee37fc4f91..1a29d87308 100644 --- a/video/sws_utils.c +++ b/video/sws_utils.c @@ -124,18 +124,30 @@ bool mp_sws_supported_format(int imgfmt) && sws_isSupportedOutput(av_format); } +static bool allow_zimg(struct mp_sws_context *ctx) +{ + return ctx->force_scaler == MP_SWS_ZIMG || + (ctx->force_scaler == MP_SWS_AUTO && ctx->allow_zimg); +} + +static bool allow_sws(struct mp_sws_context *ctx) +{ + return ctx->force_scaler == MP_SWS_SWS || ctx->force_scaler == MP_SWS_AUTO; +} + bool mp_sws_supports_formats(struct mp_sws_context *ctx, int imgfmt_out, int imgfmt_in) { #if HAVE_ZIMG - if (ctx->allow_zimg) { + if (allow_zimg(ctx)) { if (mp_zimg_supports_in_format(imgfmt_in) && mp_zimg_supports_out_format(imgfmt_out)) return true; } #endif - return sws_isSupportedInput(imgfmt2pixfmt(imgfmt_in)) && + return allow_sws(ctx) && + sws_isSupportedInput(imgfmt2pixfmt(imgfmt_in)) && sws_isSupportedOutput(imgfmt2pixfmt(imgfmt_out)); } @@ -158,6 +170,7 @@ static bool cache_valid(struct mp_sws_context *ctx) ctx->contrast == old->contrast && ctx->saturation == old->saturation && ctx->allow_zimg == old->allow_zimg && + ctx->force_scaler == old->force_scaler && (!ctx->opts_cache || !m_config_cache_update(ctx->opts_cache)); } @@ -232,7 +245,7 @@ int mp_sws_reinit(struct mp_sws_context *ctx) ctx->zimg_ok = false; #if HAVE_ZIMG - if (ctx->allow_zimg) { + if (allow_zimg(ctx)) { ctx->zimg->log = ctx->log; ctx->zimg->src = *src; ctx->zimg->dst = *dst; @@ -245,6 +258,11 @@ int mp_sws_reinit(struct mp_sws_context *ctx) } #endif + if (!allow_sws(ctx)) { + MP_ERR(ctx, "No scaler.\n"); + return -1; + } + ctx->sws = sws_alloc_context(); if (!ctx->sws) return -1; diff --git a/video/sws_utils.h b/video/sws_utils.h index ddf628cf23..24846f544e 100644 --- a/video/sws_utils.h +++ b/video/sws_utils.h @@ -23,6 +23,12 @@ int mp_image_swscale(struct mp_image *dst, struct mp_image *src, int mp_image_sw_blur_scale(struct mp_image *dst, struct mp_image *src, float gblur); +enum mp_sws_scaler { + MP_SWS_AUTO = 0, // use command line + MP_SWS_SWS, + MP_SWS_ZIMG, +}; + struct mp_sws_context { // Can be set for verbose error printing. struct mp_log *log; @@ -36,6 +42,9 @@ struct mp_sws_context { // Setting them before that call makes sense when using mp_sws_reinit(). struct mp_image_params src, dst; + // This is unfortunately a hack: bypass command line choice + enum mp_sws_scaler force_scaler; + // Changing these requires setting force_reload=true. // By default, they are NULL. // Freeing the mp_sws_context will deallocate these if set.