hwcontext_dxva2: implement device creation
authorAnton Khirnov <anton@khirnov.net>
Thu, 19 May 2016 17:19:20 +0000 (19:19 +0200)
committerAnton Khirnov <anton@khirnov.net>
Thu, 26 May 2016 13:40:33 +0000 (15:40 +0200)
libavutil/hwcontext_dxva2.c

index 62cca6f..e2c27bf 100644 (file)
@@ -37,6 +37,9 @@
 #include "pixdesc.h"
 #include "pixfmt.h"
 
+typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
+typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);
+
 typedef struct DXVA2FramesContext {
     IDirect3DSurface9 **surfaces_internal;
     int              nb_surfaces_used;
@@ -47,6 +50,16 @@ typedef struct DXVA2FramesContext {
     D3DFORMAT format;
 } DXVA2FramesContext;
 
+typedef struct DXVA2DevicePriv {
+    HMODULE d3dlib;
+    HMODULE dxva2lib;
+
+    HANDLE device_handle;
+
+    IDirect3D9       *d3d9;
+    IDirect3DDevice9 *d3d9device;
+} DXVA2DevicePriv;
+
 static const struct {
     D3DFORMAT d3d_format;
     enum AVPixelFormat pix_fmt;
@@ -273,6 +286,125 @@ static int dxva2_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
     return 0;
 }
 
+static void dxva2_device_free(AVHWDeviceContext *ctx)
+{
+    AVDXVA2DeviceContext *hwctx = ctx->hwctx;
+    DXVA2DevicePriv       *priv = ctx->user_opaque;
+
+    if (hwctx->devmgr && priv->device_handle != INVALID_HANDLE_VALUE)
+        IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, priv->device_handle);
+
+    if (hwctx->devmgr)
+        IDirect3DDeviceManager9_Release(hwctx->devmgr);
+
+    if (priv->d3d9device)
+        IDirect3DDevice9_Release(priv->d3d9device);
+
+    if (priv->d3d9)
+        IDirect3D9_Release(priv->d3d9);
+
+    if (priv->d3dlib)
+        FreeLibrary(priv->d3dlib);
+
+    if (priv->dxva2lib)
+        FreeLibrary(priv->dxva2lib);
+
+    av_freep(&ctx->user_opaque);
+}
+
+static int dxva2_device_create(AVHWDeviceContext *ctx, const char *device,
+                               AVDictionary *opts, int flags)
+{
+    AVDXVA2DeviceContext *hwctx = ctx->hwctx;
+    DXVA2DevicePriv *priv;
+
+    pDirect3DCreate9 *createD3D = NULL;
+    pCreateDeviceManager9 *createDeviceManager = NULL;
+    D3DPRESENT_PARAMETERS d3dpp = {0};
+    D3DDISPLAYMODE        d3ddm;
+    unsigned resetToken = 0;
+    UINT adapter = D3DADAPTER_DEFAULT;
+    HRESULT hr;
+
+    if (device)
+        adapter = atoi(device);
+
+    priv = av_mallocz(sizeof(*priv));
+    if (!priv)
+        return AVERROR(ENOMEM);
+
+    ctx->user_opaque = priv;
+    ctx->free        = dxva2_device_free;
+
+    priv->device_handle = INVALID_HANDLE_VALUE;
+
+    priv->d3dlib = LoadLibrary("d3d9.dll");
+    if (!priv->d3dlib) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to load D3D9 library\n");
+        return AVERROR_UNKNOWN;
+    }
+    priv->dxva2lib = LoadLibrary("dxva2.dll");
+    if (!priv->dxva2lib) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to load DXVA2 library\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    createD3D = (pDirect3DCreate9 *)GetProcAddress(priv->d3dlib, "Direct3DCreate9");
+    if (!createD3D) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to locate Direct3DCreate9\n");
+        return AVERROR_UNKNOWN;
+    }
+    createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(priv->dxva2lib,
+                                                                  "DXVA2CreateDirect3DDeviceManager9");
+    if (!createDeviceManager) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    priv->d3d9 = createD3D(D3D_SDK_VERSION);
+    if (!priv->d3d9) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to create IDirect3D object\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    IDirect3D9_GetAdapterDisplayMode(priv->d3d9, adapter, &d3ddm);
+    d3dpp.Windowed         = TRUE;
+    d3dpp.BackBufferWidth  = 640;
+    d3dpp.BackBufferHeight = 480;
+    d3dpp.BackBufferCount  = 0;
+    d3dpp.BackBufferFormat = d3ddm.Format;
+    d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
+    d3dpp.Flags            = D3DPRESENTFLAG_VIDEO;
+
+    hr = IDirect3D9_CreateDevice(priv->d3d9, adapter, D3DDEVTYPE_HAL, GetShellWindow(),
+                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
+                                 &d3dpp, &priv->d3d9device);
+    if (FAILED(hr)) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    hr = createDeviceManager(&resetToken, &hwctx->devmgr);
+    if (FAILED(hr)) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device manager\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    hr = IDirect3DDeviceManager9_ResetDevice(hwctx->devmgr, priv->d3d9device, resetToken);
+    if (FAILED(hr)) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to bind Direct3D device to device manager\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &priv->device_handle);
+    if (FAILED(hr)) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
 const HWContextType ff_hwcontext_type_dxva2 = {
     .type                 = AV_HWDEVICE_TYPE_DXVA2,
     .name                 = "DXVA2",
@@ -281,6 +413,7 @@ const HWContextType ff_hwcontext_type_dxva2 = {
     .frames_hwctx_size    = sizeof(AVDXVA2FramesContext),
     .frames_priv_size     = sizeof(DXVA2FramesContext),
 
+    .device_create        = dxva2_device_create,
     .frames_init          = dxva2_frames_init,
     .frames_uninit        = dxva2_frames_uninit,
     .frames_get_buffer    = dxva2_get_buffer,