From 989d873d6ec57171a55f432d6f87a9e5a61a706c Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 12 Mar 2022 11:24:51 -0800 Subject: filters: lavfi: allow hwdec_interop selection for filters Today, lavfi filters are provided a hw_device from the first hwdec_interop that was loaded, regardless of whether it's the right one or not. In most situations where a hardware based filter is used, we need more control over the device. In this change, a `hwdec_interop` option is added to the lavfi wrapper filter configuration and this is used to pick the correct hw_device to inject into the filter or graph (in the case of a graph, all filters get the same device). Note that this requires the use of the explicit lavfi syntax to allow for the extra configuration. eg: ``` mpv --vf=hwupload ``` becomes ``` mpv --vf=lavfi=[hwupload]:hwdec_interop=cuda-nvdec ``` or ``` mpv --vf=lavfi-bridge=[hwupload]:hwdec_interop=cuda-nvdec ``` --- filters/f_lavfi.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) (limited to 'filters/f_lavfi.c') diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c index ec6fb9f095..cbb3066430 100644 --- a/filters/f_lavfi.c +++ b/filters/f_lavfi.c @@ -47,6 +47,7 @@ #include "audio/fmt-conversion.h" #include "video/fmt-conversion.h" #include "video/hwdec.h" +#include "video/out/gpu/hwdec.h" #include "f_lavfi.h" #include "filter.h" @@ -98,6 +99,9 @@ struct lavfi { double delay; // seconds of audio apparently buffered by filter struct mp_lavfi public; + + // Identify a specific hwdec_interop to use + char *hwdec_interop; }; struct lavfi_pad { @@ -548,11 +552,22 @@ static void init_graph(struct lavfi *c) if (init_pads(c)) { struct mp_stream_info *info = mp_filter_find_stream_info(c->f); if (info && info->hwdec_devs) { - struct mp_hwdec_ctx *hwdec = hwdec_devices_get_first(info->hwdec_devs); - for (int n = 0; n < c->graph->nb_filters; n++) { - AVFilterContext *filter = c->graph->filters[n]; - if (hwdec && hwdec->av_device_ref) - filter->hw_device_ctx = av_buffer_ref(hwdec->av_device_ref); + struct mp_hwdec_ctx *hwdec_ctx = NULL; + if (c->hwdec_interop) { + int imgfmt = + ra_hwdec_driver_get_imgfmt_for_name(c->hwdec_interop); + hwdec_ctx = mp_filter_load_hwdec_device(c->f, imgfmt); + } else { + hwdec_ctx = hwdec_devices_get_first(info->hwdec_devs); + } + if (hwdec_ctx && hwdec_ctx->av_device_ref) { + MP_VERBOSE(c, "Configuring hwdec_interop=%s for filters\n", + hwdec_ctx->driver_name); + for (int n = 0; n < c->graph->nb_filters; n++) { + AVFilterContext *filter = c->graph->filters[n]; + filter->hw_device_ctx = + av_buffer_ref(hwdec_ctx->av_device_ref); + } } } @@ -886,6 +901,7 @@ error: struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent, enum mp_frame_type type, bool bidir, + char *hwdec_interop, char **graph_opts, const char *graph) { struct lavfi *c = lavfi_alloc(parent); @@ -896,12 +912,14 @@ struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent, c->force_bidir = bidir; c->graph_opts = mp_dup_str_array(c, graph_opts); c->graph_string = talloc_strdup(c, graph); + c->hwdec_interop = talloc_strdup(c, hwdec_interop); return do_init(c); } struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent, enum mp_frame_type type, bool bidir, + char *hwdec_interop, char **graph_opts, const char *filter, char **filter_opts) { @@ -911,6 +929,7 @@ struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent, c->force_type = type; c->force_bidir = bidir; + c->hwdec_interop = talloc_strdup(c, hwdec_interop); c->graph_opts = mp_dup_str_array(c, graph_opts); c->graph_string = talloc_strdup(c, filter); c->direct_filter_opts = mp_dup_str_array(c, filter_opts); @@ -930,6 +949,8 @@ struct lavfi_user_opts { char **filter_opts; int fix_pts; + + char *hwdec_interop; }; static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options) @@ -937,10 +958,11 @@ static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options) struct lavfi_user_opts *opts = options; struct mp_lavfi *l; if (opts->is_bridge) { - l = mp_lavfi_create_filter(parent, opts->type, true, opts->avopts, + l = mp_lavfi_create_filter(parent, opts->type, true, + opts->hwdec_interop, opts->avopts, opts->filter_name, opts->filter_opts); } else { - l = mp_lavfi_create_graph(parent, opts->type, true, + l = mp_lavfi_create_graph(parent, opts->type, true, opts->hwdec_interop, opts->avopts, opts->graph); } if (l) { @@ -1101,6 +1123,9 @@ const struct mp_user_filter_entry af_lavfi = { {"graph", OPT_STRING(graph)}, {"fix-pts", OPT_FLAG(fix_pts)}, {"o", OPT_KEYVALUELIST(avopts)}, + {"hwdec_interop", + OPT_STRING_VALIDATE(hwdec_interop, + ra_hwdec_validate_drivers_only_opt)}, {0} }, .priv_defaults = &(const OPT_BASE_STRUCT){ @@ -1120,6 +1145,9 @@ const struct mp_user_filter_entry af_lavfi_bridge = { {"name", OPT_STRING(filter_name)}, {"opts", OPT_KEYVALUELIST(filter_opts)}, {"o", OPT_KEYVALUELIST(avopts)}, + {"hwdec_interop", + OPT_STRING_VALIDATE(hwdec_interop, + ra_hwdec_validate_drivers_only_opt)}, {0} }, .priv_defaults = &(const OPT_BASE_STRUCT){ @@ -1139,6 +1167,9 @@ const struct mp_user_filter_entry vf_lavfi = { .options = (const m_option_t[]){ {"graph", OPT_STRING(graph)}, {"o", OPT_KEYVALUELIST(avopts)}, + {"hwdec_interop", + OPT_STRING_VALIDATE(hwdec_interop, + ra_hwdec_validate_drivers_only_opt)}, {0} }, .priv_defaults = &(const OPT_BASE_STRUCT){ @@ -1158,6 +1189,10 @@ const struct mp_user_filter_entry vf_lavfi_bridge = { {"name", OPT_STRING(filter_name)}, {"opts", OPT_KEYVALUELIST(filter_opts)}, {"o", OPT_KEYVALUELIST(avopts)}, + {"hwdec_interop", + OPT_STRING_VALIDATE(hwdec_interop, + ra_hwdec_validate_drivers_only_opt)}, + {0} }, .priv_defaults = &(const OPT_BASE_STRUCT){ -- cgit v1.2.3