mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
video: refactor hw device creation for hwdec copy modes
Lots of shit code for nothing. We probably could just use libavutil's code for all of this. But for now go with this, since it tends to prevent stupid terminal messages during probing (libavutil has no mechanism to selectively suppress errors specifically during probing). Ignores the "emulated" API flag (for avoiding vaapi/vdpau wrappers), but it doesn't matter that much for -copy anyway.
This commit is contained in:
@@ -124,8 +124,38 @@ static void d3d11_complete_image_params(struct mp_image *img)
|
||||
mp_image_setfmt(img, IMGFMT_D3D11NV12);
|
||||
}
|
||||
|
||||
static struct AVBufferRef *d3d11_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, struct hwcontext_create_dev_params *params)
|
||||
{
|
||||
ID3D11Device *device = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
d3d_load_dlls();
|
||||
if (!d3d11_D3D11CreateDevice) {
|
||||
mp_err(plog, "Failed to load D3D11 library\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = d3d11_D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
|
||||
D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0,
|
||||
D3D11_SDK_VERSION, &device, NULL, NULL);
|
||||
if (FAILED(hr)) {
|
||||
mp_err(plog, "Failed to create D3D11 Device: %s\n",
|
||||
mp_HRESULT_to_str(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVBufferRef *avref = d3d11_wrap_device_ref(device);
|
||||
ID3D11Device_Release(device);
|
||||
if (!avref)
|
||||
mp_err(plog, "Failed to allocate AVHWDeviceContext.\n");
|
||||
|
||||
return avref;
|
||||
}
|
||||
|
||||
const struct hwcontext_fns hwcontext_fns_d3d11 = {
|
||||
.av_hwdevice_type = AV_HWDEVICE_TYPE_D3D11VA,
|
||||
.complete_image_params = d3d11_complete_image_params,
|
||||
.refine_hwframes = d3d11_refine_hwframes,
|
||||
.av_hwdevice_type = AV_HWDEVICE_TYPE_D3D11VA,
|
||||
.complete_image_params = d3d11_complete_image_params,
|
||||
.refine_hwframes = d3d11_refine_hwframes,
|
||||
.create_dev = d3d11_create_standalone,
|
||||
};
|
||||
|
||||
@@ -33,50 +33,6 @@
|
||||
#include <libavutil/hwcontext.h>
|
||||
#include <libavutil/hwcontext_d3d11va.h>
|
||||
|
||||
static void d3d11_destroy_dev(struct mp_hwdec_ctx *ctx)
|
||||
{
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
ID3D11Device_Release((ID3D11Device *)ctx->ctx);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
static struct mp_hwdec_ctx *d3d11_create_dev(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing)
|
||||
{
|
||||
ID3D11Device *device = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
d3d_load_dlls();
|
||||
if (!d3d11_D3D11CreateDevice) {
|
||||
mp_err(plog, "Failed to load D3D11 library\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = d3d11_D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
|
||||
D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0,
|
||||
D3D11_SDK_VERSION, &device, NULL, NULL);
|
||||
if (FAILED(hr)) {
|
||||
mp_err(plog, "Failed to create D3D11 Device: %s\n",
|
||||
mp_HRESULT_to_str(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mp_hwdec_ctx *ctx = talloc_ptrtype(NULL, ctx);
|
||||
*ctx = (struct mp_hwdec_ctx) {
|
||||
.type = HWDEC_D3D11VA_COPY,
|
||||
.ctx = device,
|
||||
.destroy = d3d11_destroy_dev,
|
||||
.av_device_ref = d3d11_wrap_device_ref(device),
|
||||
};
|
||||
|
||||
if (!ctx->av_device_ref) {
|
||||
mp_err(plog, "Failed to allocate AVHWDeviceContext.\n");
|
||||
d3d11_destroy_dev(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_d3d11va = {
|
||||
.type = HWDEC_D3D11VA,
|
||||
@@ -90,7 +46,8 @@ const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy = {
|
||||
.copying = true,
|
||||
.image_format = IMGFMT_D3D11VA,
|
||||
.generic_hwaccel = true,
|
||||
.create_dev = d3d11_create_dev,
|
||||
.create_standalone_dev = true,
|
||||
.create_standalone_dev_type = AV_HWDEVICE_TYPE_D3D11VA,
|
||||
.set_hwframes = true,
|
||||
.delay_queue = HWDEC_DELAY_QUEUE_COUNT,
|
||||
};
|
||||
|
||||
@@ -88,15 +88,8 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void d3d9_destroy_dev(struct mp_hwdec_ctx *ctx)
|
||||
{
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
IDirect3DDevice9_Release((IDirect3DDevice9 *)ctx->ctx);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
static struct mp_hwdec_ctx *d3d9_create_dev(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing)
|
||||
static struct AVBufferRef *d3d9_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, struct hwcontext_create_dev_params *params)
|
||||
{
|
||||
d3d_load_dlls();
|
||||
if (!d3d9_dll || !dxva2_dll) {
|
||||
@@ -149,23 +142,19 @@ static struct mp_hwdec_ctx *d3d9_create_dev(struct mpv_global *global,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mp_hwdec_ctx *ctx = talloc_ptrtype(NULL, ctx);
|
||||
*ctx = (struct mp_hwdec_ctx) {
|
||||
.type = HWDEC_D3D11VA_COPY,
|
||||
.ctx = exdev,
|
||||
.destroy = d3d9_destroy_dev,
|
||||
.av_device_ref = d3d9_wrap_device_ref((IDirect3DDevice9 *)exdev),
|
||||
};
|
||||
|
||||
if (!ctx->av_device_ref) {
|
||||
AVBufferRef *avref = d3d9_wrap_device_ref((IDirect3DDevice9 *)exdev);
|
||||
IDirect3DDevice9Ex_Release(exdev);
|
||||
if (!avref)
|
||||
mp_err(plog, "Failed to allocate AVHWDeviceContext.\n");
|
||||
d3d9_destroy_dev(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
return avref;
|
||||
}
|
||||
|
||||
const struct hwcontext_fns hwcontext_fns_dxva2 = {
|
||||
.av_hwdevice_type = AV_HWDEVICE_TYPE_DXVA2,
|
||||
.create_dev = d3d9_create_standalone,
|
||||
};
|
||||
|
||||
const struct vd_lavc_hwdec mp_vd_lavc_dxva2 = {
|
||||
.type = HWDEC_DXVA2,
|
||||
.image_format = IMGFMT_DXVA2,
|
||||
@@ -178,7 +167,8 @@ const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy = {
|
||||
.copying = true,
|
||||
.image_format = IMGFMT_DXVA2,
|
||||
.generic_hwaccel = true,
|
||||
.create_dev = d3d9_create_dev,
|
||||
.create_standalone_dev = true,
|
||||
.create_standalone_dev_type = AV_HWDEVICE_TYPE_DXVA2,
|
||||
.set_hwframes = true,
|
||||
.delay_queue = HWDEC_DELAY_QUEUE_COUNT,
|
||||
};
|
||||
|
||||
@@ -97,10 +97,6 @@ struct vd_lavc_hwdec {
|
||||
int (*init)(struct lavc_ctx *ctx);
|
||||
int (*init_decoder)(struct lavc_ctx *ctx);
|
||||
void (*uninit)(struct lavc_ctx *ctx);
|
||||
// For copy hwdecs. If probing is true, don't log errors if unavailable.
|
||||
// The returned device will be freed with mp_hwdec_ctx->destroy.
|
||||
struct mp_hwdec_ctx *(*create_dev)(struct mpv_global *global,
|
||||
struct mp_log *log, bool probing);
|
||||
// Suffix for libavcodec decoder. If non-NULL, the codec is overridden
|
||||
// with hwdec_find_decoder.
|
||||
// Intuitively, this will force the corresponding wrapper decoder.
|
||||
|
||||
@@ -200,7 +200,8 @@ static const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = {
|
||||
.image_format = IMGFMT_VAAPI,
|
||||
.generic_hwaccel = true,
|
||||
.set_hwframes = true,
|
||||
.create_dev = va_create_standalone,
|
||||
.create_standalone_dev = true,
|
||||
.create_standalone_dev_type = AV_HWDEVICE_TYPE_VAAPI,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -220,7 +221,8 @@ static const struct vd_lavc_hwdec mp_vd_lavc_vdpau_copy = {
|
||||
.image_format = IMGFMT_VDPAU,
|
||||
.generic_hwaccel = true,
|
||||
.set_hwframes = true,
|
||||
.create_dev = vdpau_create_standalone,
|
||||
.create_standalone_dev = true,
|
||||
.create_standalone_dev_type = AV_HWDEVICE_TYPE_VDPAU,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -358,16 +360,27 @@ static struct mp_hwdec_ctx *hwdec_create_dev(struct dec_video *vd,
|
||||
.ctx = NULL,
|
||||
.destroy = standalone_dev_destroy,
|
||||
};
|
||||
if (av_hwdevice_ctx_create(&ctx->av_device_ref,
|
||||
const struct hwcontext_fns *fns =
|
||||
hwdec_get_hwcontext_fns(hwdec->create_standalone_dev_type);
|
||||
if (fns && fns->create_dev) {
|
||||
struct hwcontext_create_dev_params params = {
|
||||
.probing = autoprobe,
|
||||
};
|
||||
ctx->av_device_ref = fns->create_dev(vd->global, vd->log, ¶ms);
|
||||
if (!ctx->av_device_ref) {
|
||||
standalone_dev_destroy(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
} else {
|
||||
if (av_hwdevice_ctx_create(&ctx->av_device_ref,
|
||||
hwdec->create_standalone_dev_type, NULL, NULL, 0) < 0)
|
||||
{
|
||||
standalone_dev_destroy(ctx);
|
||||
ctx = NULL;
|
||||
{
|
||||
standalone_dev_destroy(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
if (hwdec->create_dev)
|
||||
return hwdec->create_dev(vd->global, vd->log, autoprobe);
|
||||
if (vd->hwdec_devs) {
|
||||
int type = hwdec->interop_type ? hwdec->interop_type : hwdec->type;
|
||||
hwdec_devices_request_all(vd->hwdec_devs);
|
||||
@@ -391,8 +404,7 @@ static int hwdec_probe(struct dec_video *vd, struct vd_lavc_hwdec *hwdec,
|
||||
return hwdec->copying ? -1 : HWDEC_ERR_NO_CTX;
|
||||
if (dev->emulated)
|
||||
r = HWDEC_ERR_EMULATED;
|
||||
bool owns_hwdec_dev = !!hwdec->create_dev ||
|
||||
hwdec->create_standalone_dev;
|
||||
bool owns_hwdec_dev = !!hwdec->create_standalone_dev;
|
||||
if (owns_hwdec_dev && dev->destroy)
|
||||
dev->destroy(dev);
|
||||
}
|
||||
@@ -594,8 +606,7 @@ static void init_avctx(struct dec_video *vd, const char *decoder,
|
||||
ctx->hwdec_dev = hwdec_create_dev(vd, ctx->hwdec, false);
|
||||
if (!ctx->hwdec_dev)
|
||||
goto error;
|
||||
ctx->owns_hwdec_dev = !!ctx->hwdec->create_dev ||
|
||||
ctx->hwdec->create_standalone_dev;
|
||||
ctx->owns_hwdec_dev = ctx->hwdec->create_standalone_dev;
|
||||
if (ctx->hwdec_dev->restore_device)
|
||||
ctx->hwdec_dev->restore_device(ctx->hwdec_dev);
|
||||
if (!ctx->hwdec->set_hwframes)
|
||||
|
||||
@@ -107,13 +107,18 @@ char *hwdec_devices_get_names(struct mp_hwdec_devices *devs)
|
||||
return res;
|
||||
}
|
||||
|
||||
#if HAVE_D3D_HWACCEL
|
||||
extern const struct hwcontext_fns hwcontext_fns_d3d11;
|
||||
#endif
|
||||
|
||||
static const struct hwcontext_fns *const hwcontext_fns[] = {
|
||||
#if HAVE_D3D_HWACCEL
|
||||
&hwcontext_fns_d3d11,
|
||||
#endif
|
||||
#if HAVE_D3D9_HWACCEL
|
||||
&hwcontext_fns_dxva2,
|
||||
#endif
|
||||
#if HAVE_VAAPI
|
||||
&hwcontext_fns_vaapi,
|
||||
#endif
|
||||
#if HAVE_VDPAU
|
||||
&hwcontext_fns_vdpau,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -111,9 +111,14 @@ void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type);
|
||||
char *hwdec_devices_get_names(struct mp_hwdec_devices *devs);
|
||||
|
||||
struct mp_image;
|
||||
struct mpv_global;
|
||||
|
||||
struct hwcontext_create_dev_params {
|
||||
bool probing; // if true, don't log errors if unavailable
|
||||
};
|
||||
|
||||
// Per AV_HWDEVICE_TYPE_* functions, queryable via hwdec_get_hwcontext_fns().
|
||||
// For now, all entries are strictly optional.
|
||||
// All entries are strictly optional.
|
||||
struct hwcontext_fns {
|
||||
int av_hwdevice_type;
|
||||
// Set any mp_image fields that require hwcontext specific code, such as
|
||||
@@ -124,10 +129,19 @@ struct hwcontext_fns {
|
||||
void (*complete_image_params)(struct mp_image *img);
|
||||
// Fill in special format-specific requirements.
|
||||
void (*refine_hwframes)(struct AVBufferRef *hw_frames_ctx);
|
||||
// Returns a AVHWDeviceContext*. Used for copy hwdecs.
|
||||
struct AVBufferRef *(*create_dev)(struct mpv_global *global,
|
||||
struct mp_log *log,
|
||||
struct hwcontext_create_dev_params *params);
|
||||
};
|
||||
|
||||
// The parameter is of type enum AVHWDeviceType (as in int to avoid extensive
|
||||
// recursive includes). May return NULL for unknown device types.
|
||||
const struct hwcontext_fns *hwdec_get_hwcontext_fns(int av_hwdevice_type);
|
||||
|
||||
extern const struct hwcontext_fns hwcontext_fns_d3d11;
|
||||
extern const struct hwcontext_fns hwcontext_fns_dxva2;
|
||||
extern const struct hwcontext_fns hwcontext_fns_vaapi;
|
||||
extern const struct hwcontext_fns hwcontext_fns_vdpau;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -97,36 +97,57 @@ static void va_info_callback(const char *msg)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void open_lavu_vaapi_device(struct mp_vaapi_ctx *ctx)
|
||||
static void free_device_ref(struct AVHWDeviceContext *hwctx)
|
||||
{
|
||||
ctx->av_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
|
||||
if (!ctx->av_device_ref)
|
||||
return;
|
||||
struct mp_vaapi_ctx *ctx = hwctx->user_opaque;
|
||||
|
||||
AVHWDeviceContext *hwctx = (void *)ctx->av_device_ref->data;
|
||||
AVVAAPIDeviceContext *vactx = hwctx->hwctx;
|
||||
if (ctx->display)
|
||||
vaTerminate(ctx->display);
|
||||
|
||||
vactx->display = ctx->display;
|
||||
if (ctx->destroy_native_ctx)
|
||||
ctx->destroy_native_ctx(ctx->native_ctx);
|
||||
|
||||
if (av_hwdevice_ctx_init(ctx->av_device_ref) < 0)
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
#if !VA_CHECK_VERSION(1, 0, 0)
|
||||
pthread_mutex_lock(&va_log_mutex);
|
||||
for (int n = 0; n < num_va_mpv_clients; n++) {
|
||||
if (va_mpv_clients[n] == ctx) {
|
||||
MP_TARRAY_REMOVE_AT(va_mpv_clients, num_va_mpv_clients, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num_va_mpv_clients == 0)
|
||||
TA_FREEP(&va_mpv_clients); // avoid triggering leak detectors
|
||||
pthread_mutex_unlock(&va_log_mutex);
|
||||
#endif
|
||||
|
||||
ctx->hwctx.av_device_ref = ctx->av_device_ref;
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog,
|
||||
bool probing)
|
||||
{
|
||||
AVBufferRef *avref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
|
||||
if (!avref)
|
||||
return NULL;
|
||||
|
||||
AVHWDeviceContext *hwctx = (void *)avref->data;
|
||||
AVVAAPIDeviceContext *vactx = hwctx->hwctx;
|
||||
|
||||
struct mp_vaapi_ctx *res = talloc_ptrtype(NULL, res);
|
||||
*res = (struct mp_vaapi_ctx) {
|
||||
.log = mp_log_new(res, plog, "/vaapi"),
|
||||
.display = display,
|
||||
.av_device_ref = avref,
|
||||
.hwctx = {
|
||||
.type = HWDEC_VAAPI,
|
||||
.ctx = res,
|
||||
.av_device_ref = avref,
|
||||
},
|
||||
};
|
||||
|
||||
hwctx->free = free_device_ref;
|
||||
hwctx->user_opaque = res;
|
||||
|
||||
#if VA_CHECK_VERSION(1, 0, 0)
|
||||
vaSetErrorCallback(display, va_error_callback, res);
|
||||
vaSetInfoCallback(display, va_info_callback, res);
|
||||
@@ -152,9 +173,10 @@ struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog,
|
||||
}
|
||||
MP_VERBOSE(res, "Initialized VAAPI: version %d.%d\n", major, minor);
|
||||
|
||||
// For now, some code will still work even if libavutil fails on old crap
|
||||
// libva drivers (such as the vdpau wraper). So don't error out on failure.
|
||||
open_lavu_vaapi_device(res);
|
||||
vactx->display = res->display;
|
||||
|
||||
if (av_hwdevice_ctx_init(res->av_device_ref) < 0)
|
||||
goto error;
|
||||
|
||||
res->hwctx.emulated = va_guess_if_emulated(res);
|
||||
|
||||
@@ -169,30 +191,11 @@ error:
|
||||
// Undo va_initialize, and close the VADisplay.
|
||||
void va_destroy(struct mp_vaapi_ctx *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (ctx->display)
|
||||
vaTerminate(ctx->display);
|
||||
|
||||
if (ctx->destroy_native_ctx)
|
||||
ctx->destroy_native_ctx(ctx->native_ctx);
|
||||
|
||||
#if !VA_CHECK_VERSION(1, 0, 0)
|
||||
pthread_mutex_lock(&va_log_mutex);
|
||||
for (int n = 0; n < num_va_mpv_clients; n++) {
|
||||
if (va_mpv_clients[n] == ctx) {
|
||||
MP_TARRAY_REMOVE_AT(va_mpv_clients, num_va_mpv_clients, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num_va_mpv_clients == 0)
|
||||
TA_FREEP(&va_mpv_clients); // avoid triggering leak detectors
|
||||
pthread_mutex_unlock(&va_log_mutex);
|
||||
#endif
|
||||
|
||||
talloc_free(ctx);
|
||||
}
|
||||
AVBufferRef *ref = ctx->av_device_ref;
|
||||
av_buffer_unref(&ref); // frees ctx as well
|
||||
}
|
||||
|
||||
VASurfaceID va_surface_id(struct mp_image *mpi)
|
||||
@@ -298,20 +301,16 @@ static const struct va_native_display *const native_displays[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static void va_destroy_ctx(struct mp_hwdec_ctx *ctx)
|
||||
{
|
||||
va_destroy(ctx->ctx);
|
||||
}
|
||||
|
||||
struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing)
|
||||
static struct AVBufferRef *va_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *log, struct hwcontext_create_dev_params *params)
|
||||
{
|
||||
for (int n = 0; native_displays[n]; n++) {
|
||||
VADisplay *display = NULL;
|
||||
void *native_ctx = NULL;
|
||||
native_displays[n]->create(&display, &native_ctx);
|
||||
if (display) {
|
||||
struct mp_vaapi_ctx *ctx = va_initialize(display, plog, probing);
|
||||
struct mp_vaapi_ctx *ctx =
|
||||
va_initialize(display, log, params->probing);
|
||||
if (!ctx) {
|
||||
vaTerminate(display);
|
||||
native_displays[n]->destroy(native_ctx);
|
||||
@@ -319,9 +318,13 @@ struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global,
|
||||
}
|
||||
ctx->native_ctx = native_ctx;
|
||||
ctx->destroy_native_ctx = native_displays[n]->destroy;
|
||||
ctx->hwctx.destroy = va_destroy_ctx;
|
||||
return &ctx->hwctx;
|
||||
return ctx->hwctx.av_device_ref;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct hwcontext_fns hwcontext_fns_vaapi = {
|
||||
.av_hwdevice_type = AV_HWDEVICE_TYPE_VAAPI,
|
||||
.create_dev = va_create_standalone,
|
||||
};
|
||||
|
||||
@@ -49,8 +49,4 @@ VASurfaceID va_surface_id(struct mp_image *mpi);
|
||||
|
||||
bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx);
|
||||
|
||||
struct mpv_global;
|
||||
struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing);
|
||||
|
||||
#endif
|
||||
|
||||
141
video/vdpau.c
141
video/vdpau.c
@@ -337,60 +337,9 @@ static void recheck_preemption(struct mp_hwdec_ctx *hwctx)
|
||||
mp_vdpau_handle_preemption(ctx, NULL);
|
||||
}
|
||||
|
||||
static bool open_lavu_vdpau_device(struct mp_vdpau_ctx *ctx)
|
||||
static void free_device_ref(struct AVHWDeviceContext *hwctx)
|
||||
{
|
||||
ctx->av_device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VDPAU);
|
||||
if (!ctx->av_device_ref)
|
||||
return false;
|
||||
|
||||
AVHWDeviceContext *hwctx = (void *)ctx->av_device_ref->data;
|
||||
AVVDPAUDeviceContext *vdctx = hwctx->hwctx;
|
||||
|
||||
vdctx->device = ctx->vdp_device;
|
||||
vdctx->get_proc_address = ctx->get_proc_address;
|
||||
|
||||
if (av_hwdevice_ctx_init(ctx->av_device_ref) < 0)
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
|
||||
ctx->hwctx.av_device_ref = ctx->av_device_ref;
|
||||
|
||||
return !!ctx->av_device_ref;
|
||||
}
|
||||
|
||||
struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11,
|
||||
bool probing)
|
||||
{
|
||||
struct mp_vdpau_ctx *ctx = talloc_ptrtype(NULL, ctx);
|
||||
*ctx = (struct mp_vdpau_ctx) {
|
||||
.log = log,
|
||||
.x11 = x11,
|
||||
.preemption_counter = 1,
|
||||
.hwctx = {
|
||||
.type = HWDEC_VDPAU,
|
||||
.ctx = ctx,
|
||||
.restore_device = recheck_preemption,
|
||||
},
|
||||
};
|
||||
mpthread_mutex_init_recursive(&ctx->preempt_lock);
|
||||
pthread_mutex_init(&ctx->pool_lock, NULL);
|
||||
|
||||
mark_vdpau_objects_uninitialized(ctx);
|
||||
|
||||
if (win_x11_init_vdpau_procs(ctx, probing) < 0) {
|
||||
mp_vdpau_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
if (!open_lavu_vdpau_device(ctx)) {
|
||||
mp_vdpau_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
struct mp_vdpau_ctx *ctx = hwctx->user_opaque;
|
||||
|
||||
struct vdp_functions *vdp = &ctx->vdp;
|
||||
VdpStatus vdp_st;
|
||||
@@ -408,8 +357,6 @@ void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
av_buffer_unref(&ctx->av_device_ref);
|
||||
|
||||
if (ctx->preemption_obj != VDP_INVALID_HANDLE) {
|
||||
vdp_st = vdp->output_surface_destroy(ctx->preemption_obj);
|
||||
CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_destroy");
|
||||
@@ -420,11 +367,70 @@ void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
|
||||
CHECK_VDP_WARNING(ctx, "Error when calling vdp_device_destroy");
|
||||
}
|
||||
|
||||
if (ctx->close_display)
|
||||
XCloseDisplay(ctx->x11);
|
||||
|
||||
pthread_mutex_destroy(&ctx->pool_lock);
|
||||
pthread_mutex_destroy(&ctx->preempt_lock);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11,
|
||||
bool probing)
|
||||
{
|
||||
AVBufferRef *avref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VDPAU);
|
||||
if (!avref)
|
||||
return NULL;
|
||||
|
||||
AVHWDeviceContext *hwctx = (void *)avref->data;
|
||||
AVVDPAUDeviceContext *vdctx = hwctx->hwctx;
|
||||
|
||||
struct mp_vdpau_ctx *ctx = talloc_ptrtype(NULL, ctx);
|
||||
*ctx = (struct mp_vdpau_ctx) {
|
||||
.log = log,
|
||||
.x11 = x11,
|
||||
.preemption_counter = 1,
|
||||
.av_device_ref = avref,
|
||||
.hwctx = {
|
||||
.type = HWDEC_VDPAU,
|
||||
.ctx = ctx,
|
||||
.restore_device = recheck_preemption,
|
||||
.av_device_ref = avref,
|
||||
},
|
||||
};
|
||||
mpthread_mutex_init_recursive(&ctx->preempt_lock);
|
||||
pthread_mutex_init(&ctx->pool_lock, NULL);
|
||||
|
||||
hwctx->free = free_device_ref;
|
||||
hwctx->user_opaque = ctx;
|
||||
|
||||
mark_vdpau_objects_uninitialized(ctx);
|
||||
|
||||
if (win_x11_init_vdpau_procs(ctx, probing) < 0) {
|
||||
mp_vdpau_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdctx->device = ctx->vdp_device;
|
||||
vdctx->get_proc_address = ctx->get_proc_address;
|
||||
|
||||
if (av_hwdevice_ctx_init(ctx->av_device_ref) < 0) {
|
||||
mp_vdpau_destroy(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
AVBufferRef *ref = ctx->av_device_ref;
|
||||
av_buffer_unref(&ref); // frees ctx as well
|
||||
}
|
||||
|
||||
bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type,
|
||||
VdpYCbCrFormat *out_pixel_format)
|
||||
{
|
||||
@@ -531,16 +537,8 @@ bool mp_vdpau_guess_if_emulated(struct mp_vdpau_ctx *ctx)
|
||||
return vdp_st == VDP_STATUS_OK && info && strstr(info, "VAAPI");
|
||||
}
|
||||
|
||||
static void vdpau_destroy_standalone(struct mp_hwdec_ctx *ctx)
|
||||
{
|
||||
struct mp_vdpau_ctx *vdp = ctx->ctx;
|
||||
Display *display = vdp->x11;
|
||||
mp_vdpau_destroy(vdp);
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
struct mp_hwdec_ctx *vdpau_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing)
|
||||
static struct AVBufferRef *vdpau_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *log, struct hwcontext_create_dev_params *params)
|
||||
{
|
||||
XInitThreads();
|
||||
|
||||
@@ -548,13 +546,20 @@ struct mp_hwdec_ctx *vdpau_create_standalone(struct mpv_global *global,
|
||||
if (!display)
|
||||
return NULL;
|
||||
|
||||
struct mp_vdpau_ctx *vdp = mp_vdpau_create_device_x11(plog, display, probing);
|
||||
struct mp_vdpau_ctx *vdp =
|
||||
mp_vdpau_create_device_x11(log, display, params->probing);
|
||||
if (!vdp) {
|
||||
XCloseDisplay(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdp->hwctx.emulated = mp_vdpau_guess_if_emulated(vdp);
|
||||
vdp->hwctx.destroy = vdpau_destroy_standalone;
|
||||
return &vdp->hwctx;
|
||||
vdp->close_display = true;
|
||||
mp_warn(log, "idk\n");
|
||||
return vdp->hwctx.av_device_ref;
|
||||
}
|
||||
|
||||
const struct hwcontext_fns hwcontext_fns_vdpau = {
|
||||
.av_hwdevice_type = AV_HWDEVICE_TYPE_VDPAU,
|
||||
.create_dev = vdpau_create_standalone,
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ struct vdp_functions {
|
||||
struct mp_vdpau_ctx {
|
||||
struct mp_log *log;
|
||||
Display *x11;
|
||||
bool close_display;
|
||||
|
||||
struct mp_hwdec_ctx hwctx;
|
||||
struct AVBufferRef *av_device_ref;
|
||||
@@ -90,10 +91,6 @@ struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11
|
||||
bool probing);
|
||||
void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx);
|
||||
|
||||
struct mpv_global;
|
||||
struct mp_hwdec_ctx *vdpau_create_standalone(struct mpv_global *global,
|
||||
struct mp_log *plog, bool probing);
|
||||
|
||||
int mp_vdpau_handle_preemption(struct mp_vdpau_ctx *ctx, uint64_t *counter);
|
||||
|
||||
struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
|
||||
|
||||
Reference in New Issue
Block a user