summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-05-09 19:42:03 +0200
committerwm4 <wm4@nowhere>2016-05-09 20:03:22 +0200
commit46fff8d31af0b79fe3de4aaee93bb66c248118a0 (patch)
treeefe5b04a4e9daf89195a4c758fe93ace9bee385f
parentee4c00698f7e4b04579494f262e668840c2668b3 (diff)
downloadmpv-46fff8d31af0b79fe3de4aaee93bb66c248118a0.tar.bz2
mpv-46fff8d31af0b79fe3de4aaee93bb66c248118a0.tar.xz
video: refactor how VO exports hwdec device handles
The main change is with video/hwdec.h. mp_hwdec_info is made opaque (and renamed to mp_hwdec_devices). Its accessors are mainly thread-safe (or documented where not), which makes the whole thing saner and cleaner. In particular, thread-safety rules become less subtle and more obvious. The new internal API makes it easier to support multiple OpenGL interop backends. (Although this is not done yet, and it's not clear whether it ever will.) This also removes all the API-specific fields from mp_hwdec_ctx and replaces them with a "ctx" field. For d3d in particular, we drop the mp_d3d_ctx struct completely, and pass the interfaces directly. Remove the emulation checks from vaapi.c and vdpau.c; they are pointless, and the checks that matter are done on the VO layer. The d3d hardware decoders might slightly change behavior: dxva2-copy will not use the VO device anymore if the VO supports proper interop. This pretty much assumes that any in such cases the VO will not use any form of exclusive mode, which makes using the VO device in copy mode unnecessary. This is a big refactor. Some things may be untested and could be broken.
-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