summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/d3d.h15
-rw-r--r--video/decode/d3d11va.c12
-rw-r--r--video/decode/dec_video.h2
-rw-r--r--video/decode/dxva2.c16
-rw-r--r--video/decode/lavc.h4
-rw-r--r--video/decode/vaapi.c33
-rw-r--r--video/decode/vd_lavc.c16
-rw-r--r--video/decode/vdpau.c9
-rw-r--r--video/decode/videotoolbox.c9
-rw-r--r--video/filter/vf.c2
-rw-r--r--video/filter/vf.h4
-rw-r--r--video/filter/vf_vavpp.c12
-rw-r--r--video/filter/vf_vdpaupp.c5
-rw-r--r--video/filter/vf_vdpaurb.c9
-rw-r--r--video/hwdec.c90
-rw-r--r--video/hwdec.h77
-rw-r--r--video/out/opengl/hwdec.c29
-rw-r--r--video/out/opengl/hwdec.h12
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c18
-rw-r--r--video/out/opengl/hwdec_dxva2.c27
-rw-r--r--video/out/opengl/hwdec_dxva2egl.c20
-rw-r--r--video/out/opengl/hwdec_dxva2gldx.c20
-rw-r--r--video/out/opengl/hwdec_osx.c26
-rw-r--r--video/out/opengl/hwdec_vaegl.c7
-rw-r--r--video/out/opengl/hwdec_vaglx.c7
-rw-r--r--video/out/opengl/hwdec_vdpau.c7
-rw-r--r--video/out/vo.c1
-rw-r--r--video/out/vo.h6
-rw-r--r--video/out/vo_opengl.c36
-rw-r--r--video/out/vo_opengl_cb.c21
-rw-r--r--video/out/vo_vaapi.c17
-rw-r--r--video/out/vo_vdpau.c12
-rw-r--r--video/vaapi.c3
-rw-r--r--video/vdpau.c8
34 files changed, 334 insertions, 258 deletions
diff --git a/video/d3d.h b/video/d3d.h
deleted file mode 100644
index b5cf365f7f..0000000000
--- a/video/d3d.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef MP_D3D_H_
-#define MP_D3D_H_
-
-#include <d3d9.h>
-#include <d3d11.h>
-
-#include "hwdec.h"
-
-struct mp_d3d_ctx {
- struct mp_hwdec_ctx hwctx;
- IDirect3DDevice9 *d3d9_device;
- ID3D11Device *d3d11_device;
-};
-
-#endif
diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c
index 246a35ec9a..1626626767 100644
--- a/video/decode/d3d11va.c
+++ b/video/decode/d3d11va.c
@@ -26,7 +26,6 @@
#include "video/mp_image_pool.h"
#include "video/hwdec.h"
-#include "video/d3d.h"
#include "d3d.h"
#define ADDITIONAL_SURFACES (4 + HWDEC_DELAY_QUEUE_COUNT)
@@ -492,9 +491,7 @@ static int d3d11va_init(struct lavc_ctx *s)
p->sw_pool = talloc_steal(p, mp_image_pool_new(17));
}
- if (s->hwdec_info && s->hwdec_info->hwctx && s->hwdec_info->hwctx->d3d_ctx)
- p->device = s->hwdec_info->hwctx->d3d_ctx->d3d11_device;
-
+ p->device = hwdec_devices_load(s->hwdec_devs, s->hwdec->type);
if (p->device) {
ID3D11Device_AddRef(p->device);
ID3D11Device_GetImmediateContext(p->device, &p->device_ctx);
@@ -539,15 +536,12 @@ fail:
return -1;
}
-static int d3d11va_probe(struct vd_lavc_hwdec *hwdec,
- struct mp_hwdec_info *info,
+static int d3d11va_probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
- hwdec_request_api(info, "d3d11va");
// d3d11va-copy can do without external context; dxva2 requires it.
if (hwdec->type != HWDEC_D3D11VA_COPY) {
- if (!info || !info->hwctx || !info->hwctx->d3d_ctx ||
- !info->hwctx->d3d_ctx->d3d11_device)
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_D3D11VA))
return HWDEC_ERR_NO_CTX;
}
return d3d_probe_codec(codec);
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index f4646a97d0..1030973e1c 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -32,7 +32,7 @@ struct dec_video {
struct mpv_global *global;
struct MPOpts *opts;
const struct vd_functions *vd_driver;
- struct mp_hwdec_info *hwdec_info; // video output hwdec handles
+ struct mp_hwdec_devices *hwdec_devs; // video output hwdec handles
struct sh_stream *header;
struct mp_codec_params *codec;
diff --git a/video/decode/dxva2.c b/video/decode/dxva2.c
index 70623c8fb4..5d3afda86c 100644
--- a/video/decode/dxva2.c
+++ b/video/decode/dxva2.c
@@ -32,7 +32,6 @@
#include "video/mp_image_pool.h"
#include "video/hwdec.h"
-#include "video/d3d.h"
#include "video/dxva2.h"
#include "d3d.h"
@@ -406,9 +405,7 @@ static int dxva2_init(struct lavc_ctx *s)
p->sw_pool = talloc_steal(p, mp_image_pool_new(17));
}
- if (s->hwdec_info && s->hwdec_info->hwctx && s->hwdec_info->hwctx->d3d_ctx)
- p->device = s->hwdec_info->hwctx->d3d_ctx->d3d9_device;
-
+ p->device = hwdec_devices_load(s->hwdec_devs, s->hwdec->type);
if (p->device) {
IDirect3D9_AddRef(p->device);
MP_VERBOSE(p, "Using VO-supplied device %p.\n", p->device);
@@ -477,16 +474,15 @@ fail:
return -1;
}
-static int dxva2_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int dxva2_probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
- hwdec_request_api(info, "dxva2");
// dxva2-copy can do without external context; dxva2 requires it.
- if (hwdec->type != HWDEC_DXVA2_COPY) {
- if (!info || !info->hwctx || !info->hwctx->d3d_ctx ||
- info->hwctx->type == HWDEC_DXVA2_COPY ||
- !info->hwctx->d3d_ctx->d3d9_device)
+ if (hwdec->type == HWDEC_DXVA2) {
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_DXVA2))
return HWDEC_ERR_NO_CTX;
+ } else {
+ hwdec_devices_load(ctx->hwdec_devs, HWDEC_DXVA2_COPY);
}
return d3d_probe_codec(codec);
}
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 73243e16c4..dbefe79ad9 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -30,7 +30,7 @@ typedef struct lavc_ctx {
int max_delay_queue;
// From VO
- struct mp_hwdec_info *hwdec_info;
+ struct mp_hwdec_devices *hwdec_devs;
// For free use by hwdec implementation
void *hwdec_priv;
@@ -54,7 +54,7 @@ struct vd_lavc_hwdec {
// efficiency by not blocking on the hardware pipeline by reading back
// immediately after decoding.
int delay_queue;
- int (*probe)(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+ int (*probe)(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec);
int (*init)(struct lavc_ctx *ctx);
int (*init_decoder)(struct lavc_ctx *ctx, int w, int h);
diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c
index 169564d6c4..4b098a8804 100644
--- a/video/decode/vaapi.c
+++ b/video/decode/vaapi.c
@@ -357,7 +357,7 @@ static void destroy_va_dummy_ctx(struct priv *p)
// Creates a "private" VADisplay, disconnected from the VO. We just create a
// new X connection, because that's simpler. (We could also pass the X
-// connection along with struct mp_hwdec_info, if we wanted.)
+// connection along with struct mp_hwdec_devices, if we wanted.)
static bool create_va_dummy_ctx(struct priv *p)
{
for (int n = 0; native_displays[n]; n++) {
@@ -399,21 +399,23 @@ static void uninit(struct lavc_ctx *ctx)
ctx->hwdec_priv = NULL;
}
-static int init_with_vactx(struct lavc_ctx *ctx, struct mp_vaapi_ctx *vactx)
+static int init(struct lavc_ctx *ctx, bool direct)
{
struct priv *p = talloc_ptrtype(NULL, p);
*p = (struct priv) {
.log = mp_log_new(p, ctx->log, "vaapi"),
- .ctx = vactx,
.va_context = &p->va_context_storage,
.rt_format = VA_RT_FORMAT_YUV420
};
- if (!p->ctx)
+ if (direct) {
+ p->ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VAAPI)->ctx;
+ } else {
create_va_dummy_ctx(p);
- if (!p->ctx) {
- talloc_free(p);
- return -1;
+ if (!p->ctx) {
+ talloc_free(p);
+ return -1;
+ }
}
p->display = p->ctx->display;
@@ -431,25 +433,22 @@ static int init_with_vactx(struct lavc_ctx *ctx, struct mp_vaapi_ctx *vactx)
return 0;
}
-static int init(struct lavc_ctx *ctx)
+static int init_direct(struct lavc_ctx *ctx)
{
- return init_with_vactx(ctx, ctx->hwdec_info->hwctx->vaapi_ctx);
+ return init(ctx, true);
}
-static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
- hwdec_request_api(info, "vaapi");
- if (!info || !info->hwctx || !info->hwctx->vaapi_ctx)
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VAAPI))
return HWDEC_ERR_NO_CTX;
if (!hwdec_check_codec_support(codec, profiles))
return HWDEC_ERR_NO_CODEC;
- if (va_guess_if_emulated(info->hwctx->vaapi_ctx))
- return HWDEC_ERR_EMULATED;
return 0;
}
-static int probe_copy(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
struct priv dummy = {mp_null_log};
@@ -466,7 +465,7 @@ static int probe_copy(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
static int init_copy(struct lavc_ctx *ctx)
{
- return init_with_vactx(ctx, NULL);
+ return init(ctx, false);
}
static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *img)
@@ -497,7 +496,7 @@ const struct vd_lavc_hwdec mp_vd_lavc_vaapi = {
.type = HWDEC_VAAPI,
.image_format = IMGFMT_VAAPI,
.probe = probe,
- .init = init,
+ .init = init_direct,
.uninit = uninit,
.init_decoder = init_decoder,
.allocate_image = allocate_image,
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index ff97e3446c..bc70b7d348 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -280,18 +280,13 @@ static bool hwdec_is_wrapper(struct vd_lavc_hwdec *hwdec, const char *decoder)
return bstr_endswith0(bstr0(decoder), hwdec->lavc_suffix);
}
-void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name)
-{
- if (info && info->load_api)
- info->load_api(info, api_name);
-}
-
-static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int hwdec_probe(struct dec_video *vd, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
+ vd_ffmpeg_ctx *ctx = vd->priv;
int r = 0;
if (hwdec->probe)
- r = hwdec->probe(hwdec, info, codec);
+ r = hwdec->probe(ctx, hwdec, codec);
if (r >= 0) {
if (hwdec->lavc_suffix && !hwdec_find_decoder(codec, hwdec->lavc_suffix))
return HWDEC_ERR_NO_CODEC;
@@ -309,7 +304,7 @@ static struct vd_lavc_hwdec *probe_hwdec(struct dec_video *vd, bool autoprobe,
MP_VERBOSE(vd, "Requested hardware decoder not compiled.\n");
return NULL;
}
- int r = hwdec_probe(hwdec, vd->hwdec_info, codec);
+ int r = hwdec_probe(vd, hwdec, codec);
if (r == HWDEC_ERR_EMULATED) {
if (autoprobe)
return NULL;
@@ -412,6 +407,7 @@ static int init(struct dec_video *vd, const char *decoder)
ctx->log = vd->log;
ctx->opts = vd->opts;
ctx->decoder = talloc_strdup(ctx, decoder);
+ ctx->hwdec_devs = vd->hwdec_devs;
reinit(vd);
@@ -441,8 +437,6 @@ static void init_avctx(struct dec_video *vd, const char *decoder,
if (!lavc_codec)
return;
- ctx->hwdec_info = vd->hwdec_info;
-
ctx->codec_timebase = (AVRational){0};
if (strstr(decoder, "_mmal") || strstr(decoder, "_mediacodec"))
ctx->codec_timebase = (AVRational){1, 1000000};
diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c
index 313fabff76..2aba10c13b 100644
--- a/video/decode/vdpau.c
+++ b/video/decode/vdpau.c
@@ -75,7 +75,7 @@ static int init(struct lavc_ctx *ctx)
struct priv *p = talloc_ptrtype(NULL, p);
*p = (struct priv) {
.log = mp_log_new(p, ctx->log, "vdpau"),
- .mpvdp = ctx->hwdec_info->hwctx->vdpau_ctx,
+ .mpvdp = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VDPAU)->ctx,
};
ctx->hwdec_priv = p;
@@ -83,14 +83,11 @@ static int init(struct lavc_ctx *ctx)
return 0;
}
-static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
- hwdec_request_api(info, "vdpau");
- if (!info || !info->hwctx || !info->hwctx->vdpau_ctx)
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VDPAU))
return HWDEC_ERR_NO_CTX;
- if (mp_vdpau_guess_if_emulated(info->hwctx->vdpau_ctx))
- return HWDEC_ERR_EMULATED;
return 0;
}
diff --git a/video/decode/videotoolbox.c b/video/decode/videotoolbox.c
index 2d2f5f735c..c69d5e89e6 100644
--- a/video/decode/videotoolbox.c
+++ b/video/decode/videotoolbox.c
@@ -27,11 +27,10 @@
#include "config.h"
-static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
- hwdec_request_api(info, "videotoolbox");
- if (!info || !info->hwctx || !info->hwctx->get_vt_fmt)
+ if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX))
return HWDEC_ERR_NO_CTX;
switch (mp_codec_to_av_codec_id(codec)) {
case AV_CODEC_ID_H264:
@@ -89,8 +88,8 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h)
AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
- struct mp_hwdec_ctx *hwctx = ctx->hwdec_info->hwctx;
- vtctx->cv_pix_fmt_type = hwctx->get_vt_fmt(hwctx);
+ struct mp_vt_ctx *vt = hwdec_devices_load(ctx->hwdec_devs, HWDEC_VIDEOTOOLBOX);
+ vtctx->cv_pix_fmt_type = vt->get_vt_fmt(vt);
int err = av_videotoolbox_default_init2(ctx->avctx, vtctx);
if (err < 0) {
diff --git a/video/filter/vf.c b/video/filter/vf.c
index d8e7f6b4c8..7ca1b08f34 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -244,7 +244,7 @@ static struct vf_instance *vf_open(struct vf_chain *c, const char *name,
*vf = (vf_instance_t) {
.info = desc.p,
.log = mp_log_new(vf, c->log, name),
- .hwdec = c->hwdec,
+ .hwdec_devs = c->hwdec_devs,
.query_format = vf_default_query_format,
.out_pool = talloc_steal(vf, mp_image_pool_new(16)),
.chain = c,
diff --git a/video/filter/vf.h b/video/filter/vf.h
index c982b612e1..02f6f2c8fd 100644
--- a/video/filter/vf.h
+++ b/video/filter/vf.h
@@ -92,7 +92,7 @@ typedef struct vf_instance {
struct mp_image_pool *out_pool;
struct vf_priv_s *priv;
struct mp_log *log;
- struct mp_hwdec_info *hwdec;
+ struct mp_hwdec_devices *hwdec_devs;
struct mp_image **out_queued;
int num_out_queued;
@@ -120,7 +120,7 @@ struct vf_chain {
struct mp_log *log;
struct MPOpts *opts;
struct mpv_global *global;
- struct mp_hwdec_info *hwdec;
+ struct mp_hwdec_devices *hwdec_devs;
// Call when the filter chain wants new processing (for filters with
// asynchronous behavior) - must be immutable once filters are created,
diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c
index 9dab15e2b9..554ddc1a05 100644
--- a/video/filter/vf_vavpp.c
+++ b/video/filter/vf_vavpp.c
@@ -481,19 +481,17 @@ static bool initialize(struct vf_instance *vf)
static int vf_open(vf_instance_t *vf)
{
+ struct vf_priv_s *p = vf->priv;
+
vf->reconfig = reconfig;
vf->filter_ext = filter_ext;
vf->query_format = query_format;
vf->uninit = uninit;
vf->control = control;
- struct vf_priv_s *p = vf->priv;
- if (!vf->hwdec)
- return false;
- hwdec_request_api(vf->hwdec, "vaapi");
- p->va = vf->hwdec->hwctx ? vf->hwdec->hwctx->vaapi_ctx : NULL;
- if (!p->va || !p->va->display)
- return false;
+ p->va = hwdec_devices_load(vf->hwdec_devs, HWDEC_VAAPI);
+ if (!p->va)
+ return 0;
p->display = p->va->display;
if (initialize(vf))
return true;
diff --git a/video/filter/vf_vdpaupp.c b/video/filter/vf_vdpaupp.c
index 882b80d9e2..23afeafe6a 100644
--- a/video/filter/vf_vdpaupp.c
+++ b/video/filter/vf_vdpaupp.c
@@ -223,10 +223,7 @@ static int vf_open(vf_instance_t *vf)
vf->control = control;
vf->uninit = uninit;
- if (!vf->hwdec)
- return 0;
- hwdec_request_api(vf->hwdec, "vdpau");
- p->ctx = vf->hwdec->hwctx ? vf->hwdec->hwctx->vdpau_ctx : NULL;
+ p->ctx = hwdec_devices_load(vf->hwdec_devs, HWDEC_VDPAU);
if (!p->ctx)
return 0;
diff --git a/video/filter/vf_vdpaurb.c b/video/filter/vf_vdpaurb.c
index 62f7f34af1..92dfa52486 100644
--- a/video/filter/vf_vdpaurb.c
+++ b/video/filter/vf_vdpaurb.c
@@ -101,14 +101,9 @@ static int vf_open(vf_instance_t *vf)
vf->reconfig = reconfig;
vf->query_format = query_format;
- if (!vf->hwdec) {
+ p->ctx = hwdec_devices_load(vf->hwdec_devs, HWDEC_VDPAU);
+ if (!p->ctx)
return 0;
- }
- hwdec_request_api(vf->hwdec, "vdpau");
- p->ctx = vf->hwdec->hwctx ? vf->hwdec->hwctx->vdpau_ctx : NULL;
- if (!p->ctx) {
- return 0;
- }
return 1;
}
diff --git a/video/hwdec.c b/video/hwdec.c
new file mode 100644
index 0000000000..6db8d57869
--- /dev/null
+++ b/video/hwdec.c
@@ -0,0 +1,90 @@
+#include <pthread.h>
+#include <assert.h>
+
+#include "hwdec.h"
+
+struct mp_hwdec_devices {
+ pthread_mutex_t lock;
+
+ struct mp_hwdec_ctx *hwctx;
+
+ void (*load_api)(void *ctx, enum hwdec_type type);
+ void *load_api_ctx;
+};
+
+struct mp_hwdec_devices *hwdec_devices_create(void)
+{
+ struct mp_hwdec_devices *devs = talloc_zero(NULL, struct mp_hwdec_devices);
+ pthread_mutex_init(&devs->lock, NULL);
+ return devs;
+}
+
+void hwdec_devices_destroy(struct mp_hwdec_devices *devs)
+{
+ if (!devs)
+ return;
+ assert(!devs->hwctx); // must have been hwdec_devices_remove()ed
+ assert(!devs->load_api); // must have been unset
+ pthread_mutex_destroy(&devs->lock);
+ talloc_free(devs);
+}
+
+struct mp_hwdec_ctx *hwdec_devices_get(struct mp_hwdec_devices *devs,
+ enum hwdec_type type)
+{
+ struct mp_hwdec_ctx *res = NULL;
+ pthread_mutex_lock(&devs->lock);
+ if (devs->hwctx && devs->hwctx->type == type)
+ res = devs->hwctx;
+ pthread_mutex_unlock(&devs->lock);
+ return res;
+}
+
+struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
+{
+ pthread_mutex_lock(&devs->lock);
+ struct mp_hwdec_ctx *res = devs->hwctx;
+ pthread_mutex_unlock(&devs->lock);
+ return res;
+}
+
+void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
+{
+ pthread_mutex_lock(&devs->lock);
+ // We support only 1 device; ignore the rest.
+ if (!devs->hwctx)
+ devs->hwctx = ctx;
+ pthread_mutex_unlock(&devs->lock);
+}
+
+void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
+{
+ pthread_mutex_lock(&devs->lock);
+ if (devs->hwctx == ctx)
+ devs->hwctx = NULL;
+ pthread_mutex_unlock(&devs->lock);
+}
+
+void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
+ void (*load_api)(void *ctx, enum hwdec_type type), void *load_api_ctx)
+{
+ devs->load_api = load_api;
+ devs->load_api_ctx = load_api_ctx;
+}
+
+// Cause VO to lazily load the requested device, and will block until this is
+// done (even if not available).
+void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type)
+{
+ if (devs->load_api && !hwdec_devices_get_first(devs))
+ devs->load_api(devs->load_api_ctx, type);
+}
+
+void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type)
+{
+ if (!devs)
+ return NULL;
+ hwdec_devices_request(devs, type);
+ struct mp_hwdec_ctx *hwctx = hwdec_devices_get(devs, type);
+ return hwctx ? hwctx->ctx : NULL;
+}
diff --git a/video/hwdec.h b/video/hwdec.h
index 94667774e7..48ec6a2a21 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -25,16 +25,17 @@ enum hwdec_type {
extern const struct m_opt_choice_alternatives mp_hwdec_names[];
struct mp_hwdec_ctx {
- enum hwdec_type type;
+ enum hwdec_type type; // (never HWDEC_NONE or HWDEC_AUTO)
const char *driver_name; // NULL if unknown/not loaded
- void *priv; // for free use by hwdec implementation
-
- // API-specific, not needed by all backends.
- struct mp_vdpau_ctx *vdpau_ctx;
- struct mp_vaapi_ctx *vaapi_ctx;
- struct mp_d3d_ctx *d3d_ctx;
- uint32_t (*get_vt_fmt)(struct mp_hwdec_ctx *ctx);
+ // This is never NULL. Its meaning depends on the .type field:
+ // HWDEC_VDPAU: struct mp_vaapi_ctx*
+ // HWDEC_VIDEOTOOLBOX: struct mp_vt_ctx*
+ // HWDEC_VAAPI: struct mp_vaapi_ctx*
+ // HWDEC_D3D11VA: ID3D11Device*
+ // HWDEC_DXVA2: IDirect3DDevice9*
+ // HWDEC_DXVA2_COPY: IDirect3DDevice9*
+ void *ctx;
// Optional.
// Allocates a software image from the pool, downloads the hw image from
@@ -46,24 +47,50 @@ struct mp_hwdec_ctx {
struct mp_image_pool *swpool);
};
-// Used to communicate hardware decoder API handles from VO to video decoder.
-// The VO can set the context pointer for supported APIs.
-struct mp_hwdec_info {
- // (Since currently only 1 hwdec API is loaded at a time, this pointer
- // simply maps to the loaded one.)
- struct mp_hwdec_ctx *hwctx;
-
- // Can be used to lazily load a requested API.
- // api_name is e.g. "vdpau" (like the fields above, without "_ctx")
- // Can be NULL, is idempotent, caller checks hwctx fields for success/access.
- // Due to threading, the callback is the only code that is allowed to
- // change fields in this struct after initialization.
- void (*load_api)(struct mp_hwdec_info *info, const char *api_name);
- void *load_api_ctx;
+struct mp_vt_ctx {
+ void *priv;
+ uint32_t (*get_vt_fmt)(struct mp_vt_ctx *ctx);
};
-// Trivial helper to call info->load_api().
-// Implemented in vd_lavc.c.
-void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name);
+// Used to communicate hardware decoder device handles from VO to video decoder.
+struct mp_hwdec_devices;
+
+struct mp_hwdec_devices *hwdec_devices_create(void);
+void hwdec_devices_destroy(struct mp_hwdec_devices *devs);
+
+// Return the device context for the given API type. Returns NULL if none
+// available. Logically, the returned pointer remains valid until VO
+// uninitialization is started (all users of it must be uninitialized before).
+// hwdec_devices_request() may be used before this to lazily load devices.
+struct mp_hwdec_ctx *hwdec_devices_get(struct mp_hwdec_devices *devs,
+ enum hwdec_type type);
+
+// For code which still strictly assumes there is 1 (or none) device.
+struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs);
+
+// Add this to the list of internal devices. Adding the same pointer twice must
+// be avoided.
+void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx);
+
+// Remove this from the list of internal devices. Idempotent/ignores entries
+// not added yet.
+void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx);
+
+// Can be used to enable lazy loading of an API with hwdec_devices_request().
+// If used at all, this must be set/unset during initialization/uninitialization,
+// as concurrent use with hwdec_devices_request() is a race condition.
+void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
+ void (*load_api)(void *ctx, enum hwdec_type type), void *load_api_ctx);
+
+// Cause VO to lazily load the requested device, and will block until this is
+// done (even if not available).
+void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type);
+
+// Convenience function:
+// - return NULL if devs==NULL
+// - call hwdec_devices_request(devs, type)
+// - call hwdec_devices_get(devs, type)
+// - then return the mp_hwdec_ctx.ctx field
+void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type);
#endif
diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c
index 9c3bec1a0f..b4b5c23580 100644
--- a/video/out/opengl/hwdec.c
+++ b/video/out/opengl/hwdec.c
@@ -61,6 +61,7 @@ static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = {
static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl,
struct mpv_global *global,
+ struct mp_hwdec_devices *devs,
const struct gl_hwdec_driver *drv,
bool is_auto)
{
@@ -70,6 +71,7 @@ static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl,
.log = mp_log_new(hwdec, log, drv->name),
.global = global,
.gl = gl,
+ .devs = devs,
.gl_texture_target = GL_TEXTURE_2D,
.probing = is_auto,
};
@@ -79,19 +81,19 @@ static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl,
mp_verbose(log, "Loading failed.\n");
return NULL;
}
- if (hwdec->hwctx && !hwdec->hwctx->driver_name)
- hwdec->hwctx->driver_name = hwdec->driver->name;
return hwdec;
}
-struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl,
- struct mpv_global *g, int id)
+struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl,
+ struct mpv_global *g,
+ struct mp_hwdec_devices *devs,
+ enum hwdec_type api)
{
- bool is_auto = id == HWDEC_AUTO;
+ bool is_auto = api == HWDEC_AUTO;
for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
- if (is_auto || id == drv->api) {
- struct gl_hwdec *r = load_hwdec_driver(log, gl, g, drv, is_auto);
+ if (is_auto || api == drv->api) {
+ struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, is_auto);
if (r)
return r;
}
@@ -99,19 +101,6 @@ struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl,
return NULL;
}
-// Like gl_hwdec_load_api_id(), but use option names.
-struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl,
- struct mpv_global *g, const char *api_name)
-{
- int id = HWDEC_NONE;
- for (const struct m_opt_choice_alternatives *c = mp_hwdec_names; c->name; c++)
- {
- if (strcmp(c->name, api_name) == 0)
- id = c->value;
- }
- return gl_hwdec_load_api_id(log, gl, g, id);
-}
-
void gl_hwdec_uninit(struct gl_hwdec *hwdec)
{
if (hwdec)
diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h
index a9d524a1d7..fcc6d3c11e 100644
--- a/video/out/opengl/hwdec.h
+++ b/video/out/opengl/hwdec.h
@@ -4,14 +4,12 @@
#include "common.h"
#include "video/hwdec.h"
-struct mp_hwdec_info;
-
struct gl_hwdec {
const struct gl_hwdec_driver *driver;
struct mp_log *log;
struct mpv_global *global;
GL *gl;
- struct mp_hwdec_ctx *hwctx;