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){ diff --git a/filters/f_lavfi.h b/filters/f_lavfi.h index c6cf86f500..ec6990f68a 100644 --- a/filters/f_lavfi.h +++ b/filters/f_lavfi.h @@ -18,6 +18,7 @@ struct mp_lavfi { // graph: a libavfilter graph specification 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); // Unlike mp_lavfi_create_graph(), this creates a single filter, using explicit @@ -26,6 +27,7 @@ struct mp_lavfi *mp_lavfi_create_graph(struct mp_filter *parent, // (which are applied with mp_set_avopts()). 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); diff --git a/filters/filter.c b/filters/filter.c index 2522209b49..eb757f5753 100644 --- a/filters/filter.c +++ b/filters/filter.c @@ -685,7 +685,7 @@ struct mp_stream_info *mp_filter_find_stream_info(struct mp_filter *f) return NULL; } -struct AVBufferRef *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt) +struct mp_hwdec_ctx *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt) { struct mp_stream_info *info = mp_filter_find_stream_info(f); if (!info || !info->hwdec_devs) @@ -697,7 +697,7 @@ struct AVBufferRef *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt) }; hwdec_devices_request_for_img_fmt(info->hwdec_devs, ¶ms); - return hwdec_devices_get_imgfmt(info->hwdec_devs, imgfmt); + return hwdec_devices_get_by_imgfmt(info->hwdec_devs, imgfmt); } static void filter_wakeup(struct mp_filter *f, bool mark_only) diff --git a/filters/filter.h b/filters/filter.h index 52797eb433..4df54b6112 100644 --- a/filters/filter.h +++ b/filters/filter.h @@ -408,8 +408,7 @@ struct mp_stream_info { // Search for a parent filter (including f) that has this set, and return it. struct mp_stream_info *mp_filter_find_stream_info(struct mp_filter *f); -struct AVBufferRef; -struct AVBufferRef *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt); +struct mp_hwdec_ctx *mp_filter_load_hwdec_device(struct mp_filter *f, int imgfmt); // Perform filtering. This runs until the filter graph is blocked (due to // missing external input or unread output). It returns whether any outside diff --git a/filters/user_filters.c b/filters/user_filters.c index 34382ba052..cf1764e9c9 100644 --- a/filters/user_filters.c +++ b/filters/user_filters.c @@ -155,7 +155,7 @@ struct mp_filter *mp_create_user_filter(struct mp_filter *parent, if (strncmp(name, "lavfi-", 6) == 0) name += 6; struct mp_lavfi *l = - mp_lavfi_create_filter(parent, frame_type, true, NULL, name, args); + mp_lavfi_create_filter(parent, frame_type, true, NULL, NULL, name, args); if (l) f = l->f; goto done; diff --git a/player/loadfile.c b/player/loadfile.c index a4ef62f2aa..da0d8b3a28 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1257,7 +1257,7 @@ static int reinit_complex_filters(struct MPContext *mpctx, bool force_uninit) } struct mp_lavfi *l = - mp_lavfi_create_graph(mpctx->filter_root, 0, false, NULL, graph); + mp_lavfi_create_graph(mpctx->filter_root, 0, false, NULL, NULL, graph); if (!l) goto done; mpctx->lavfi = l->f; diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c index d84c393e29..8d58fb173b 100644 --- a/video/filter/vf_vavpp.c +++ b/video/filter/vf_vavpp.c @@ -448,7 +448,11 @@ static struct mp_filter *vf_vavpp_create(struct mp_filter *parent, void *options p->queue = mp_refqueue_alloc(f); - p->av_device_ref = mp_filter_load_hwdec_device(f, IMGFMT_VAAPI); + struct mp_hwdec_ctx *hwdec_ctx = + mp_filter_load_hwdec_device(f, IMGFMT_VAAPI); + if (!hwdec_ctx || !hwdec_ctx->av_device_ref) + goto error; + p->av_device_ref = av_buffer_ref(hwdec_ctx->av_device_ref); if (!p->av_device_ref) goto error; diff --git a/video/filter/vf_vdpaupp.c b/video/filter/vf_vdpaupp.c index 6de8671e39..de5caa3534 100644 --- a/video/filter/vf_vdpaupp.c +++ b/video/filter/vf_vdpaupp.c @@ -136,11 +136,11 @@ static struct mp_filter *vf_vdpaupp_create(struct mp_filter *parent, void *optio p->queue = mp_refqueue_alloc(f); - AVBufferRef *ref = mp_filter_load_hwdec_device(f, IMGFMT_VDPAU); - if (!ref) + struct mp_hwdec_ctx *hwdec_ctx = + mp_filter_load_hwdec_device(f, IMGFMT_VDPAU); + if (!hwdec_ctx || !hwdec_ctx->av_device_ref) goto error; - p->ctx = mp_vdpau_get_ctx_from_av(ref); - av_buffer_unref(&ref); + p->ctx = mp_vdpau_get_ctx_from_av(hwdec_ctx->av_device_ref); if (!p->ctx) goto error; diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c index 9b994bc0a1..01147be832 100644 --- a/video/out/gpu/hwdec.c +++ b/video/out/gpu/hwdec.c @@ -26,17 +26,14 @@ #include "hwdec.h" extern const struct ra_hwdec_driver ra_hwdec_vaegl; -extern const struct ra_hwdec_driver ra_hwdec_vaglx; extern const struct ra_hwdec_driver ra_hwdec_videotoolbox; extern const struct ra_hwdec_driver ra_hwdec_vdpau; extern const struct ra_hwdec_driver ra_hwdec_dxva2egl; extern const struct ra_hwdec_driver ra_hwdec_d3d11egl; extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx; -extern const struct ra_hwdec_driver ra_hwdec_dxva2; extern const struct ra_hwdec_driver ra_hwdec_d3d11va; extern const struct ra_hwdec_driver ra_hwdec_dxva2dxgi; extern const struct ra_hwdec_driver ra_hwdec_cuda; -extern const struct ra_hwdec_driver ra_hwdec_cuda_nvdec; extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay; extern const struct ra_hwdec_driver ra_hwdec_drmprime; extern const struct ra_hwdec_driver ra_hwdec_drmprime_drm; @@ -174,8 +171,9 @@ int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img) return 0; } -int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, - struct bstr name, const char **value) +static int ra_hwdec_validate_opt_full(struct mp_log *log, bool include_modes, + const m_option_t *opt, + struct bstr name, const char **value) { struct bstr param = bstr0(*value); bool help = bstr_equals0(param, "help"); @@ -190,20 +188,36 @@ int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, } } if (help) { - mp_info(log, " auto (behavior depends on context)\n" - " all (load all hwdecs)\n" - " no (do not load any and block loading on demand)\n"); + if (include_modes) { + mp_info(log, " auto (behavior depends on context)\n" + " all (load all hwdecs)\n" + " no (do not load any and block loading on demand)\n"); + } return M_OPT_EXIT; } if (!param.len) return 1; // "" is treated specially - if (bstr_equals0(param, "all") || bstr_equals0(param, "auto") || - bstr_equals0(param, "no")) + if (include_modes && + (bstr_equals0(param, "all") || bstr_equals0(param, "auto") || + bstr_equals0(param, "no"))) return 1; mp_fatal(log, "No hwdec backend named '%.*s' found!\n", BSTR_P(param)); return M_OPT_INVALID; } +int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, + struct bstr name, const char **value) +{ + return ra_hwdec_validate_opt_full(log, true, opt, name, value); +} + +int ra_hwdec_validate_drivers_only_opt(struct mp_log *log, + const m_option_t *opt, + struct bstr name, const char **value) +{ + return ra_hwdec_validate_opt_full(log, false, opt, name, value); +} + static void load_add_hwdec(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs, const struct ra_hwdec_driver *drv, bool is_auto) { @@ -323,3 +337,13 @@ struct ra_hwdec *ra_hwdec_get(struct ra_hwdec_ctx *ctx, int imgfmt) return NULL; } + +int ra_hwdec_driver_get_imgfmt_for_name(const char *name) +{ + for (int i = 0; ra_hwdec_drivers[i]; i++) { + if (!strcmp(ra_hwdec_drivers[i]->name, name)) { + return ra_hwdec_drivers[i]->imgfmts[0]; + } + } + return IMGFMT_NONE; +} diff --git a/video/out/gpu/hwdec.h b/video/out/gpu/hwdec.h index 34f8bc7856..0dd2e14588 100644 --- a/video/out/gpu/hwdec.h +++ b/video/out/gpu/hwdec.h @@ -20,6 +20,10 @@ struct ra_hwdec_ctx { int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, struct bstr name, const char **value); +int ra_hwdec_validate_drivers_only_opt(struct mp_log *log, + const m_option_t *opt, + struct bstr name, const char **value); + void ra_hwdec_ctx_init(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs, const char *opt, bool load_all_by_default); void ra_hwdec_ctx_uninit(struct ra_hwdec_ctx *ctx); @@ -143,4 +147,8 @@ void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper); void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper); int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img); +// Get the primary image format for the given driver name. +// Returns IMGFMT_NONE if the name doesn't get matched. +int ra_hwdec_driver_get_imgfmt_for_name(const char *name); + #endif