summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--player/command.c17
-rw-r--r--player/core.h2
-rw-r--r--player/screenshot.c5
-rw-r--r--player/video.c6
-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
-rw-r--r--wscript_build.py1
39 files changed, 352 insertions, 271 deletions
diff --git a/player/command.c b/player/command.c
index 8ff2914c66..c8394c403c 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2198,14 +2198,14 @@ static int mp_property_hwdec_interop(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
- if (!mpctx->video_out)
+ if (!mpctx->video_out || !mpctx->video_out->hwdec_devs)
return M_PROPERTY_UNAVAILABLE;
- struct mp_hwdec_info *hwdec_info = NULL;
- vo_control(mpctx->video_out, VOCTRL_GET_HWDEC_INFO, &hwdec_info);
- struct mp_hwdec_ctx *hwctx = hwdec_info ? hwdec_info->hwctx : NULL;
+ struct mp_hwdec_ctx *hwctx =
+ hwdec_devices_get_first(mpctx->video_out->hwdec_devs);
+
const char *name = hwctx ? hwctx->driver_name : NULL;
- if (!name && hwctx && hwctx->type != HWDEC_NONE && hwctx->type != HWDEC_AUTO)
+ if (!name && hwctx)
name = m_opt_choice_str(mp_hwdec_names, hwctx->type);
return m_property_strdup_ro(action, arg, name);
@@ -2244,8 +2244,11 @@ static int mp_property_detected_hwdec(void *ctx, struct m_property *prop,
if (vd)
video_vd_control(vd, VDCTRL_GET_HWDEC, &current);
- if (current <= 0 && vd && vd->hwdec_info && vd->hwdec_info->hwctx)
- current = vd->hwdec_info->hwctx->type;
+ if (current <= 0 && vd && vd->hwdec_devs) {
+ struct mp_hwdec_ctx *hwctx = hwdec_devices_get_first(vd->hwdec_devs);
+ if (hwctx)
+ current = hwctx->type;
+ }
// In case of the "-copy" ones, which are "detected" every time the
// decoder is opened, return "no" if no decoding is active.
diff --git a/player/core.h b/player/core.h
index 489d1f8d3f..3a5689b9f3 100644
--- a/player/core.h
+++ b/player/core.h
@@ -153,7 +153,7 @@ struct track {
struct vo_chain {
struct mp_log *log;
- struct mp_hwdec_info *hwdec_info;
+ struct mp_hwdec_devices *hwdec_devs;
double container_fps;
struct vf_chain *vf;
diff --git a/player/screenshot.c b/player/screenshot.c
index 33b972bb25..13532ec1a3 100644
--- a/player/screenshot.c
+++ b/player/screenshot.c
@@ -346,8 +346,9 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
}
}
- if (image && mpctx->vo_chain && mpctx->vo_chain->hwdec_info) {
- struct mp_hwdec_ctx *ctx = mpctx->vo_chain->hwdec_info->hwctx;
+ if (image && mpctx->vo_chain && mpctx->vo_chain->hwdec_devs) {
+ struct mp_hwdec_ctx *ctx =
+ hwdec_devices_get_first(mpctx->vo_chain->hwdec_devs);
struct mp_image *nimage = NULL;
if (ctx && ctx->download_image && (image->fmt.flags & MP_IMGFLAG_HWACCEL))
nimage = ctx->download_image(ctx, image, NULL);
diff --git a/player/video.c b/player/video.c
index de3eb963fa..1d2dc29fc6 100644
--- a/player/video.c
+++ b/player/video.c
@@ -204,7 +204,7 @@ static void recreate_video_filters(struct MPContext *mpctx)
vf_destroy(vo_c->vf);
vo_c->vf = vf_new(mpctx->global);
- vo_c->vf->hwdec = vo_c->hwdec_info;
+ vo_c->vf->hwdec_devs = vo_c->hwdec_devs;
vo_c->vf->wakeup_callback = wakeup_playloop;
vo_c->vf->wakeup_callback_ctx = mpctx;
vo_c->vf->container_fps = vo_c->container_fps;
@@ -334,7 +334,7 @@ int init_video_decoder(struct MPContext *mpctx, struct track *track)
d_video->codec = track->stream->codec;
d_video->fps = d_video->header->codec->fps;
if (mpctx->vo_chain)
- d_video->hwdec_info = mpctx->vo_chain->hwdec_info;
+ d_video->hwdec_devs = mpctx->vo_chain->hwdec_devs;
MP_VERBOSE(d_video, "Container reported FPS: %f\n", d_video->fps);
@@ -404,7 +404,7 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
vo_c->vo = mpctx->video_out;
vo_c->vf = vf_new(mpctx->global);
- vo_control(vo_c->vo, VOCTRL_GET_HWDEC_INFO, &vo_c->hwdec_info);
+ vo_c->hwdec_devs = vo_c->vo->hwdec_devs;
vo_c->filter_src = src;
if (!vo_c->filter_src) {
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