summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2022-03-12 11:24:51 -0800
committerPhilip Langdale <github.philipl@overt.org>2022-09-21 09:39:34 -0700
commit989d873d6ec57171a55f432d6f87a9e5a61a706c (patch)
tree0077fcefc7be591eea5d6ad2e4e2373c8d59b49d
parent5629ed81eed90f95a04bb3d8ff64f135bd186651 (diff)
downloadmpv-989d873d6ec57171a55f432d6f87a9e5a61a706c.tar.bz2
mpv-989d873d6ec57171a55f432d6f87a9e5a61a706c.tar.xz
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 ```
-rw-r--r--filters/f_lavfi.c49
-rw-r--r--filters/f_lavfi.h2
-rw-r--r--filters/filter.c4
-rw-r--r--filters/filter.h3
-rw-r--r--filters/user_filters.c2
-rw-r--r--player/loadfile.c2
-rw-r--r--video/filter/vf_vavpp.c6
-rw-r--r--video/filter/vf_vdpaupp.c8
-rw-r--r--video/out/gpu/hwdec.c44
-rw-r--r--video/out/gpu/hwdec.h8
10 files changed, 100 insertions, 28 deletions
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, &params);
- 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