summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/options.rst1
-rw-r--r--options/options.c1
-rw-r--r--video/d3d.h2
-rw-r--r--video/d3d11va.c13
-rw-r--r--video/d3d11va.h1
-rw-r--r--video/decode/d3d11va.c33
-rw-r--r--video/decode/dxva2.c3
-rw-r--r--video/decode/vd_lavc.c2
-rw-r--r--video/hwdec.h1
-rw-r--r--video/out/opengl/hwdec.c2
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c413
-rw-r--r--wscript_build.py1
12 files changed, 471 insertions, 2 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index c96c10efbb..f7f92caabf 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -588,6 +588,7 @@ Video
:dxva2: requires ``--vo=opengl:backend=angle`` or
``--vo=opengl:backend=dxinterop`` (Windows only)
:dxva2-copy: copies video back to system RAM (Windows only)
+ :d3d11va: experimental, requires ``--vo=opengl:backend=angle`` (Windows only)
:d3d11va-copy: experimental (Windows only)
:rpi: requires ``--vo=rpi`` (Raspberry Pi only - default if available)
diff --git a/options/options.c b/options/options.c
index 1ae48a6fc2..90a72ee7c3 100644
--- a/options/options.c
+++ b/options/options.c
@@ -88,6 +88,7 @@ const struct m_opt_choice_alternatives mp_hwdec_names[] = {
{"vaapi-copy", HWDEC_VAAPI_COPY},
{"dxva2", HWDEC_DXVA2},
{"dxva2-copy", HWDEC_DXVA2_COPY},
+ {"d3d11va", HWDEC_D3D11VA},
{"d3d11va-copy",HWDEC_D3D11VA_COPY},
{"rpi", HWDEC_RPI},
{"mediacodec", HWDEC_MEDIACODEC},
diff --git a/video/d3d.h b/video/d3d.h
index 30bee49adc..b5cf365f7f 100644
--- a/video/d3d.h
+++ b/video/d3d.h
@@ -2,12 +2,14 @@
#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/d3d11va.c b/video/d3d11va.c
index e27d7952cd..e64c26191c 100644
--- a/video/d3d11va.c
+++ b/video/d3d11va.c
@@ -21,6 +21,7 @@
struct d3d11va_surface {
HMODULE d3d11_dll;
ID3D11Texture2D *texture;
+ int subindex;
ID3D11VideoDecoderOutputView *surface;
};
@@ -38,6 +39,14 @@ ID3D11Texture2D *d3d11_texture_in_mp_image(struct mp_image *mpi)
return surface->texture;
}
+int d3d11_subindex_in_mp_image(struct mp_image *mpi)
+{
+ if (!mpi || mpi->imgfmt != IMGFMT_D3D11VA)
+ return -1;
+ struct d3d11va_surface *surface = (void *)mpi->planes[0];
+ return surface->subindex;
+}
+
static void d3d11va_release_img(void *arg)
{
struct d3d11va_surface *surface = arg;
@@ -69,6 +78,10 @@ struct mp_image *d3d11va_new_ref(ID3D11VideoDecoderOutputView *view,
ID3D11VideoDecoderOutputView_GetResource(
surface->surface, (ID3D11Resource **)&surface->texture);
+ D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC surface_desc;
+ ID3D11VideoDecoderOutputView_GetDesc(surface->surface, &surface_desc);
+ surface->subindex = surface_desc.Texture2D.ArraySlice;
+
struct mp_image *mpi =
mp_image_new_custom_ref(NULL, surface, d3d11va_release_img);
if (!mpi)
diff --git a/video/d3d11va.h b/video/d3d11va.h
index db2f295241..bbe2c4639f 100644
--- a/video/d3d11va.h
+++ b/video/d3d11va.h
@@ -24,6 +24,7 @@ struct mp_image;
ID3D11VideoDecoderOutputView *d3d11_surface_in_mp_image(struct mp_image *mpi);
ID3D11Texture2D *d3d11_texture_in_mp_image(struct mp_image *mpi);
+int d3d11_subindex_in_mp_image(struct mp_image *mpi);
struct mp_image *d3d11va_new_ref(ID3D11VideoDecoderOutputView *view,
int w, int h);
diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c
index c73ce2cab6..b94869d29b 100644
--- a/video/decode/d3d11va.c
+++ b/video/decode/d3d11va.c
@@ -26,6 +26,7 @@
#include "video/hwdec.h"
#include "video/d3d11va.h"
+#include "video/d3d.h"
#include "d3d.h"
#define ADDITIONAL_SURFACES (4 + HWDEC_DELAY_QUEUE_COUNT)
@@ -449,8 +450,22 @@ static int d3d11va_init(struct lavc_ctx *s)
p->sw_pool = talloc_steal(p, mp_image_pool_new(17));
}
- if (!create_device(s, FALSE))
+ if (s->hwdec_info && s->hwdec_info->hwctx && s->hwdec_info->hwctx->d3d_ctx)
+ p->device = s->hwdec_info->hwctx->d3d_ctx->d3d11_device;
+
+ if (p->device) {
+ ID3D11Device_AddRef(p->device);
+ ID3D11Device_GetImmediateContext(p->device, &p->device_ctx);
+ if (!p->device_ctx)
+ goto fail;
+ MP_VERBOSE(p, "Using VO-supplied device %p.\n", p->device);
+ } else if (s->hwdec->type == HWDEC_D3D11VA) {
+ MP_ERR(p, "No Direct3D device provided for native d3d11 decoding\n");
goto fail;
+ } else {
+ if (!create_device(s, FALSE))
+ goto fail;
+ }
hr = ID3D11DeviceContext_QueryInterface(p->device_ctx,
&IID_ID3D11VideoContext,
@@ -487,9 +502,25 @@ static int d3d11va_probe(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)
+ return HWDEC_ERR_NO_CTX;
+ }
return d3d_probe_codec(codec);
}
+const struct vd_lavc_hwdec mp_vd_lavc_d3d11va = {
+ .type = HWDEC_D3D11VA,
+ .image_format = IMGFMT_D3D11VA,
+ .probe = d3d11va_probe,
+ .init = d3d11va_init,
+ .uninit = d3d11va_uninit,
+ .init_decoder = d3d11va_init_decoder,
+ .allocate_image = d3d11va_allocate_image,
+};
+
const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy = {
.type = HWDEC_D3D11VA_COPY,
.image_format = IMGFMT_D3D11VA,
diff --git a/video/decode/dxva2.c b/video/decode/dxva2.c
index 2c98c3abcc..e6499f96f2 100644
--- a/video/decode/dxva2.c
+++ b/video/decode/dxva2.c
@@ -494,7 +494,8 @@ static int dxva2_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
// 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->type == HWDEC_DXVA2_COPY ||
+ !info->hwctx->d3d_ctx->d3d9_device)
return HWDEC_ERR_NO_CTX;
}
return d3d_probe_codec(codec);
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 45aaa22599..810753cf74 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -126,6 +126,7 @@ extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2;
extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy;
+extern const struct vd_lavc_hwdec mp_vd_lavc_d3d11va;
extern const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy;
static const struct vd_lavc_hwdec mp_vd_lavc_rpi = {
@@ -158,6 +159,7 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = {
&mp_vd_lavc_dxva2_copy,
#endif
#if HAVE_D3D11VA_HWACCEL
+ &mp_vd_lavc_d3d11va,
&mp_vd_lavc_d3d11va_copy,
#endif
#if HAVE_ANDROID
diff --git a/video/hwdec.h b/video/hwdec.h
index 4deba76211..377f6779d1 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -15,6 +15,7 @@ enum hwdec_type {
HWDEC_VAAPI_COPY,
HWDEC_DXVA2,
HWDEC_DXVA2_COPY,
+ HWDEC_D3D11VA,
HWDEC_D3D11VA_COPY,
HWDEC_RPI,
HWDEC_MEDIACODEC,
diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c
index b58af9bae9..02aa0c2cd2 100644
--- a/video/out/opengl/hwdec.c
+++ b/video/out/opengl/hwdec.c
@@ -29,6 +29,7 @@ extern const struct gl_hwdec_driver gl_hwdec_vaglx;
extern const struct gl_hwdec_driver gl_hwdec_videotoolbox;
extern const struct gl_hwdec_driver gl_hwdec_vdpau;
extern const struct gl_hwdec_driver gl_hwdec_dxva2egl;
+extern const struct gl_hwdec_driver gl_hwdec_d3d11egl;
extern const struct gl_hwdec_driver gl_hwdec_dxva2gldx;
extern const struct gl_hwdec_driver gl_hwdec_dxva2;
@@ -47,6 +48,7 @@ static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = {
#endif
#if HAVE_DXVA2_HWACCEL
#if HAVE_EGL_ANGLE
+ &gl_hwdec_d3d11egl,
&gl_hwdec_dxva2egl,
#endif
#if HAVE_GL_DXINTEROP
diff --git a/video/out/opengl/hwdec_d3d11egl.c b/video/out/opengl/hwdec_d3d11egl.c
new file mode 100644
index 0000000000..44bab2c245
--- /dev/null
+++ b/video/out/opengl/hwdec_d3d11egl.c
@@ -0,0 +1,413 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <windows.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "common/common.h"
+#include "osdep/timer.h"
+#include "osdep/windows_utils.h"
+#include "hwdec.h"
+#include "video/d3d11va.h"
+#include "video/d3d.h"
+#include "video/hwdec.h"
+
+struct priv {
+ struct mp_d3d_ctx ctx;
+
+ ID3D11Device *d3d11_device;
+ ID3D11VideoDevice *video_dev;
+ ID3D11VideoContext *video_ctx;
+
+ EGLDisplay egl_display;
+ EGLConfig egl_config;
+ EGLSurface egl_surface;
+
+ ID3D11Texture2D *texture;
+ ID3D11VideoProcessor *video_proc;
+ ID3D11VideoProcessorEnumerator *vp_enum;
+ ID3D11VideoProcessorOutputView *out_view;
+ int c_w, c_h;
+
+ GLuint gl_texture;
+};
+
+static void destroy_video_proc(struct gl_hwdec *hw)
+{
+ struct priv *p = hw->priv;
+
+ if (p->out_view)
+ ID3D11VideoProcessorOutputView_Release(p->out_view);
+ p->out_view = NULL;
+
+ if (p->video_proc)
+ ID3D11VideoProcessor_Release(p->video_proc);
+ p->video_proc = NULL;
+
+ if (p->vp_enum)
+ ID3D11VideoProcessorEnumerator_Release(p->vp_enum);
+ p->vp_enum = NULL;
+}
+
+static void destroy_objects(struct gl_hwdec *hw)
+{
+ struct priv *p = hw->priv;
+ GL *gl = hw->gl;
+
+ gl->DeleteTextures(1, &p->gl_texture);
+ p->gl_texture = 0;
+
+ if (p->egl_display && p->egl_surface) {
+ eglReleaseTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER);
+ eglDestroySurface(p->egl_display, p->egl_surface);
+ }
+ p->egl_surface = NULL;
+
+ if (p->texture)
+ ID3D11Texture2D_Release(p->texture);
+ p->texture = NULL;
+
+ destroy_video_proc(hw);
+}
+
+static void destroy(struct gl_hwdec *hw)
+{
+ struct priv *p = hw->priv;
+
+ destroy_objects(hw);
+
+ if (p->video_ctx)
+ ID3D11VideoContext_Release(p->video_ctx);
+ p->video_ctx = NULL;
+
+ if (p->video_dev)
+ ID3D11VideoDevice_Release(p->video_dev);
+ p->video_dev = NULL;
+
+ if (p->d3d11_device)
+ ID3D11Device_Release(p->d3d11_device);
+ p->d3d11_device = NULL;
+}
+
+static int create(struct gl_hwdec *hw)
+{
+ if (hw->hwctx)
+ return -1;
+
+ EGLDisplay egl_display = eglGetCurrentDisplay();
+ if (!egl_display)
+ return -1;
+
+ const char *exts = eglQueryString(egl_display, EGL_EXTENSIONS);
+ if (!exts || !strstr(exts, "EGL_ANGLE_d3d_share_handle_client_buffer") ||
+ !strstr(exts, "EGL_EXT_device_query"))
+ return -1;
+
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC p_eglQueryDisplayAttribEXT =
+ (void *)eglGetProcAddress("eglQueryDisplayAttribEXT");
+ PFNEGLQUERYDEVICEATTRIBEXTPROC p_eglQueryDeviceAttribEXT =
+ (void *)eglGetProcAddress("eglQueryDeviceAttribEXT");
+ if (!p_eglQueryDisplayAttribEXT || !p_eglQueryDeviceAttribEXT)
+ return -1;
+
+ HRESULT hr;
+ struct priv *p = talloc_zero(hw, struct priv);
+ hw->priv = p;
+
+ p->egl_display = egl_display;
+
+ EGLAttrib device = 0;
+ if (!p_eglQueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &device))
+ goto fail;
+ EGLAttrib d3d_device = 0;
+ if (!p_eglQueryDeviceAttribEXT((EGLDeviceEXT)device, EGL_D3D11_DEVICE_ANGLE,
+ &d3d_device))
+ {
+ MP_ERR(hw, "Could not get EGL_D3D11_DEVICE_ANGLE from ANGLE.\n");
+ goto fail;
+ }
+
+ p->d3d11_device = (ID3D11Device *)d3d_device;
+ if (!p->d3d11_device)
+ goto fail;
+ ID3D11Device_AddRef(p->d3d11_device);
+
+ ID3D10Multithread *multithread;
+ hr = ID3D11Device_QueryInterface(p->d3d11_device, &IID_ID3D10Multithread,
+ (void **)&multithread);
+ if (FAILED(hr)) {
+ ID3D10Multithread_Release(multithread);
+ MP_ERR(hw, "Failed to get Multithread interface: %s\n",
+ mp_HRESULT_to_str(hr));
+ goto fail;
+ }
+ ID3D10Multithread_SetMultithreadProtected(multithread, TRUE);
+ ID3D10Multithread_Release(multithread);
+
+ hr = ID3D11Device_QueryInterface(p->d3d11_device, &IID_ID3D11VideoDevice,
+ (void **)&p->video_dev);
+ if (FAILED(hr))
+ goto fail;
+
+ ID3D11DeviceContext *device_ctx;
+ ID3D11Device_GetImmediateContext(p->d3d11_device, &device_ctx);
+ if (!device_ctx)
+ goto fail;
+ hr = ID3D11DeviceContext_QueryInterface(device_ctx, &IID_ID3D11VideoContext,
+ (void **)&p->video_ctx);
+ ID3D11DeviceContext_Release(device_ctx);
+ if (FAILED(hr))
+ goto fail;
+
+ EGLint attrs[] = {
+ EGL_BUFFER_SIZE, 32,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_ALPHA_SIZE, 8,
+ EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
+ EGL_NONE
+ };
+ EGLint count;
+ if (!eglChooseConfig(p->egl_display, attrs, &p->egl_config, 1, &count) ||
+ !count) {
+ MP_ERR(hw, "Failed to get EGL surface configuration\n");
+ goto fail;
+ }
+
+ hw->converted_imgfmt = IMGFMT_RGB0;
+
+ p->ctx.d3d11_device = p->d3d11_device;
+ p->ctx.hwctx.type = HWDEC_D3D11VA;
+ p->ctx.hwctx.d3d_ctx = &p->ctx;
+
+ hw->hwctx = &p->ctx.hwctx;
+ return 0;
+fail:
+ destroy(hw);
+ return -1;
+}
+
+static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
+{
+ struct priv *p = hw->priv;
+ GL *gl = hw->gl;
+ HRESULT hr;
+
+ destroy_objects(hw);
+
+ assert(params->imgfmt == hw->driver->imgfmt);
+
+ D3D11_TEXTURE2D_DESC texdesc = {
+ .Width = params->w,
+ .Height = params->h,
+ .Format = DXGI_FORMAT_B8G8R8A8_UNORM,
+ .MipLevels = 1,
+ .ArraySize = 1,
+ .SampleDesc = { .Count = 1 },
+ .Usage = D3D11_USAGE_DEFAULT,
+ .BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
+ .MiscFlags = D3D11_RESOURCE_MISC_SHARED,
+ };
+ hr = ID3D11Device_CreateTexture2D(p->d3d11_device, &texdesc, NULL, &p->texture);
+ if (FAILED(hr)) {
+ MP_ERR(hw, "Failed to create texture: %s\n", mp_HRESULT_to_str(hr));
+ goto fail;
+ }
+
+ HANDLE share_handle = NULL;
+ IDXGIResource *res;
+
+ hr = IUnknown_QueryInterface(p->texture, &IID_IDXGIResource, (void **)&res);
+ if (FAILED(hr))
+ goto fail;
+
+ hr = IDXGIResource_GetSharedHandle(res, &share_handle);
+ if (FAILED(hr))
+ share_handle = NULL;
+
+ IDXGIResource_Release(res);
+
+ if (!share_handle)
+ goto fail;
+
+ EGLint attrib_list[] = {
+ EGL_WIDTH, params->w,
+ EGL_HEIGHT, params->h,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_NONE
+ };
+ p->egl_surface = eglCreatePbufferFromClientBuffer(
+ p->egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+ share_handle, p->egl_config, attrib_list);
+ if (p->egl_surface == EGL_NO_SURFACE) {
+ MP_ERR(hw, "Failed to create EGL surface\n");
+ goto fail;
+ }
+
+ gl->GenTextures(1, &p->gl_texture);
+ gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl->BindTexture(GL_TEXTURE_2D, 0);
+
+ return 0;
+fail:
+ destroy_objects(hw);
+ return -1;
+}
+
+static int create_video_proc(struct gl_hwdec *hw, struct mp_image_params *params)
+{
+ struct priv *p = hw->priv;
+ HRESULT hr;
+
+ destroy_video_proc(hw);
+
+ // Note: we skip any deinterlacing considerations for now.
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC vpdesc = {
+ .InputWidth = p->c_w,
+ .InputHeight = p->c_h,
+ .OutputWidth = params->w,
+ .OutputHeight = params->h,
+ };
+ hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(p->video_dev, &vpdesc,
+ &p->vp_enum);
+ if (FAILED(hr))
+ goto fail;
+
+ // Assume RateConversionIndex==0 always works fine for us.
+ hr = ID3D11VideoDevice_CreateVideoProcessor(p->video_dev, p->vp_enum, 0,
+ &p->video_proc);
+ if (FAILED(hr)) {
+ MP_ERR(hw, "Failed to create D3D11 video processor.\n");
+ goto fail;
+ }
+
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outdesc = {
+ .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
+ };
+ hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(p->video_dev,
+ (ID3D11Resource *)p->texture,
+ p->vp_enum, &outdesc,
+ &p->out_view);
+ if (FAILED(hr))
+ goto fail;
+
+ // Note: libavcodec does not support cropping left/top with hwaccel.
+ RECT src_rc = {
+ .right = params->w,
+ .bottom = params->h,
+ };
+ ID3D11VideoContext_VideoProcessorSetStreamSourceRect(p->video_ctx,
+ p->video_proc,
+ 0, TRUE, &src_rc);
+
+ // This is supposed to stop drivers from fucking up the video quality.
+ ID3D11VideoContext_VideoProcessorSetStreamAutoProcessingMode(p->video_ctx,
+ p->video_proc,
+ 0, FALSE);
+
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE csp = {
+ .YCbCr_Matrix = params->colorspace != MP_CSP_BT_601,
+ };
+ ID3D11VideoContext_VideoProcessorSetStreamColorSpace(p->video_ctx,
+ p->video_proc,
+ 0, &csp);
+
+ return 0;
+fail:
+ destroy_video_proc(hw);
+ return -1;
+}
+
+static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image,
+ GLuint *out_textures)
+{
+ struct priv *p = hw->priv;
+ GL *gl = hw->gl;
+ HRESULT hr;
+ ID3D11VideoProcessorInputView *in_view = NULL;
+
+ if (!p->gl_texture)
+ return -1;
+
+ ID3D11Texture2D *d3d_tex = d3d11_texture_in_mp_image(hw_image);
+ int d3d_subindex = d3d11_subindex_in_mp_image(hw_image);
+ if (!d3d_tex)
+ return -1;
+
+ D3D11_TEXTURE2D_DESC texdesc;
+ ID3D11Texture2D_GetDesc(d3d_tex, &texdesc);
+ if (!p->video_proc || p->c_w != texdesc.Width || p->c_h != texdesc.Height) {
+ p->c_w = texdesc.Width;
+ p->c_h = texdesc.Height;
+ if (create_video_proc(hw, &hw_image->params) < 0)
+ return -1;
+ }
+
+ D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC indesc = {
+ .FourCC = 0, // huh?
+ .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
+ .Texture2D = {
+ .ArraySlice = d3d_subindex,
+ },
+ };
+ hr = ID3D11VideoDevice_CreateVideoProcessorInputView(p->video_dev,
+ (ID3D11Resource *)d3d_tex,
+ p->vp_enum, &indesc,
+ &in_view);
+ if (FAILED(hr)) {
+ MP_ERR(hw, "Could not create ID3D11VideoProcessorInputView\n");
+ return -1;
+ }
+
+ D3D11_VIDEO_PROCESSOR_STREAM stream = {
+ .Enable = TRUE,
+ .pInputSurface = in_view,
+ };
+ hr = ID3D11VideoContext_VideoProcessorBlt(p->video_ctx, p->video_proc,
+ p->out_view, 0, 1, &stream);
+ ID3D11VideoProcessorInputView_Release(in_view);
+ if (FAILED(hr)) {
+ MP_ERR(hw, "VideoProcessorBlt failed.\n");
+ return -1;
+ }
+
+ gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
+ eglBindTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER);
+ gl->BindTexture(GL_TEXTURE_2D, 0);
+
+ out_textures[0] = p->gl_texture;
+ return 0;
+}
+
+const struct gl_hwdec_driver gl_hwdec_d3d11egl = {
+ .name = "d3d11-egl",
+ .api = HWDEC_D3D11VA,
+ .imgfmt = IMGFMT_D3D11VA,
+ .create = create,
+ .reinit = reinit,
+ .map_image = map_image,
+ .destroy = destroy,
+};
diff --git a/wscript_build.py b/wscript_build.py
index 7dd28c31bb..3ee2b31d65 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -342,6 +342,7 @@ def build(ctx):
( "video/out/opengl/context_x11egl.c", "egl-x11" ),
( "video/out/opengl/egl_helpers.c", "egl-helpers" ),
( "video/out/opengl/hwdec.c", "gl" ),
+ ( "video/out/opengl/hwdec_d3d11egl.c", "egl-angle" ),
( "video/out/opengl/hwdec_dxva2.c", "gl-win32" ),
( "video/out/opengl/hwdec_dxva2gldx.c", "gl-dxinterop" ),
( "video/out/opengl/hwdec_dxva2egl.c", "egl-angle" ),