[vlc-devel] [PATCH 2/2] contrib: the D3D11 decoder context needs to be protected on WindowsPhone

Steve Lhomme robux4 at videolabs.io
Thu May 12 14:13:21 CEST 2016


From: Steve Lhomme <robUx4 at gmail.com>

--
It cannot be accessed from multiple thread. And since the decoder and vout
work in separate threads, we need a mutex to avoid crashes.
---
 modules/codec/avcodec/d3d11va.c         | 43 ++++++++++++++++++++--
 modules/video_output/win32/common.h     |  2 +
 modules/video_output/win32/direct3d11.c | 65 +++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c
index ed6733e..f930537 100644
--- a/modules/codec/avcodec/d3d11va.c
+++ b/modules/codec/avcodec/d3d11va.c
@@ -92,6 +92,7 @@ vlc_module_end()
 # include <dxgidebug.h>
 #endif
 
+DEFINE_GUID(GUID_CONTEXT_MUTEX,      0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
 DEFINE_GUID(IID_ID3D11VideoDevice,   0x10EC4D5B, 0x975A, 0x4689, 0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F, 0xE3, 0x33);
 DEFINE_GUID(IID_ID3D11VideoContext,  0x61F21C45, 0x3C0E, 0x4a74, 0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A, 0xD5, 0xE4);
 DEFINE_GUID(IID_IDXGIDevice,         0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c);
@@ -114,6 +115,9 @@ struct vlc_va_sys_t
     DXGI_FORMAT                  render;
 
     ID3D11DeviceContext          *d3dctx;
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 36, 0, 36, 100)
+    HANDLE                       context_mutex;
+#endif
 
     /* Video decoder */
     D3D11_VIDEO_DECODER_CONFIG   cfg;
@@ -170,6 +174,13 @@ void SetupAVCodecContext(vlc_va_t *va)
     sys->hw.cfg = &sys->cfg;
     sys->hw.surface_count = dx_sys->surface_count;
     sys->hw.surface = (ID3D11VideoDecoderOutputView**) dx_sys->hw_surface;
+#if LIBAVCODEC_VERSION_CHECK(56, 36, 0, 36, 100)
+#if VLC_WINSTORE_APP
+    sys->hw.context_mutex = sys->context_mutex;
+#else
+    sys->hw.context_mutex = INVALID_HANDLE_VALUE;
+#endif
+#endif
 
     if (IsEqualGUID(&dx_sys->input, &DXVA_Intel_H264_NoFGT_ClearVideo))
         sys->hw.workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
@@ -223,18 +234,25 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
     vlc_va_sys_t *sys = va->sys;
     ID3D11VideoDecoderOutputView *src = (ID3D11VideoDecoderOutputView*)(uintptr_t)data;
     vlc_va_surface_t *surface = output->context;
+    int ret = VLC_SUCCESS;
 
     if (output->format.i_chroma == VLC_CODEC_D3D11_OPAQUE)
     {
-        /* copy decoder slice to surface */
-        D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
         picture_sys_t *p_sys_out = output->p_sys;
         picture_sys_t *p_sys_in = surface->p_pic->p_sys;
 
         assert(p_sys_out->texture != NULL);
         assert(p_sys_in->decoder == src);
 
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 36, 0, 36, 100)
+        if( sys->context_mutex > 0 ) {
+            WaitForSingleObjectEx( sys->context_mutex, INFINITE, FALSE );
+        }
+#endif
+        D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
         ID3D11VideoDecoderOutputView_GetDesc( src, &viewDesc );
+
+        /* copy decoder slice to surface */
         ID3D11DeviceContext_CopySubresourceRegion(sys->d3dctx, (ID3D11Resource*) p_sys_out->texture,
                                                   0, 0, 0, 0,
                                                   (ID3D11Resource*) p_sys_in->texture,
@@ -247,10 +265,17 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
         va->sys->filter->pf_video_filter( va->sys->filter, surface->p_pic );
     } else {
         msg_Err(va, "Unsupported output picture format %08X", output->format.i_chroma );
-        return VLC_EGENERIC;
+        ret = VLC_EGENERIC;
     }
 
-    return VLC_SUCCESS;
+done:
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 36, 0, 36, 100)
+    if( sys->context_mutex > 0 ) {
+        ReleaseMutex( sys->context_mutex );
+    }
+#endif
+
+    return ret;
 }
 
 static int CheckDevice(vlc_va_t *va)
@@ -344,6 +369,16 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
            msg_Err(va, "Could not Query ID3D11VideoDevice Interface from the picture. (hr=0x%lX)", hr);
         } else {
             ID3D11DeviceContext_GetDevice( p_sys->context, (ID3D11Device**) &dx_sys->d3ddev );
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 36, 0, 36, 100)
+            HANDLE context_lock = INVALID_HANDLE_VALUE;
+            UINT dataSize = sizeof(context_lock);
+            hr = ID3D11Device_GetPrivateData((ID3D11Device*)dx_sys->d3ddev, &GUID_CONTEXT_MUTEX, &dataSize, &context_lock);
+            if (SUCCEEDED(hr))
+                sys->context_mutex = context_lock;
+            else
+                msg_Warn(va, "No mutex found to lock the decoder");
+#endif
+
             sys->d3dctx = p_sys->context;
             sys->d3dvidctx = d3dvidctx;
 
diff --git a/modules/video_output/win32/common.h b/modules/video_output/win32/common.h
index d698b94..8ebc2cb 100644
--- a/modules/video_output/win32/common.h
+++ b/modules/video_output/win32/common.h
@@ -175,6 +175,8 @@ struct vout_display_sys_t
     PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN OurD3D11CreateDeviceAndSwapChain;
     PFN_D3D11_CREATE_DEVICE                OurD3D11CreateDevice;
     pD3DCompile                            OurD3DCompile;
+#else
+    HANDLE                   context_lock;
 #endif
     IDXGISwapChain1          *dxgiswapChain;   /* DXGI 1.1 swap chain */
     ID3D11Device             *d3ddevice;       /* D3D device */
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index c2adcd9..b66cb08 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -25,6 +25,13 @@
 # include "config.h"
 #endif
 
+#if _WIN32_WINNT < 0x0600
+/* for CreateMutexEx */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x601
+#endif /* _WIN32_WINNT */
+
+#include <assert.h>
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_display.h>
@@ -53,6 +60,7 @@
 
 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH,  0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
+DEFINE_GUID(GUID_CONTEXT_MUTEX,    0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
 
 static int  Open(vlc_object_t *);
 static void Close(vlc_object_t *);
@@ -666,12 +674,24 @@ static void Manage(vout_display_t *vd)
     if (RECTWidth(size_before)  != RECTWidth(sys->rect_dest_clipped) ||
         RECTHeight(size_before) != RECTHeight(sys->rect_dest_clipped))
     {
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+        if( sys->context_lock > 0 )
+        {
+            WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
+        }
+#endif
         msg_Dbg(vd, "Manage detected size change %dx%d", RECTWidth(sys->rect_dest_clipped),
                 RECTHeight(sys->rect_dest_clipped));
 
         UpdateBackBuffer(vd);
 
         UpdatePicQuadPosition(vd);
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+        if( sys->context_lock > 0 )
+        {
+            ReleaseMutex( sys->context_lock );
+        }
+#endif
     }
     UncropStagingFormat( vd, &core_source );
 }
@@ -702,6 +722,12 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
 
 #ifdef HAVE_ID3D11VIDEODECODER 
     if (picture->format.i_chroma == VLC_CODEC_D3D11_OPAQUE) {
+#if VLC_WINSTORE_APP
+        if( sys->context_lock > 0 )
+        {
+            WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
+        }
+#endif
         D3D11_BOX box;
         box.left   = picture->format.i_x_offset;
         box.right  = picture->format.i_x_offset + picture->format.i_visible_width;
@@ -780,6 +806,11 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     {
         /* TODO device lost */
     }
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    if( picture->format.i_chroma == VLC_CODEC_D3D11_OPAQUE && sys->context_lock > 0) {
+        ReleaseMutex( sys->context_lock );
+    }
+#endif
 
     picture_Release(picture);
     if (subpicture)
@@ -1081,11 +1112,29 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
     UpdateRects(vd, NULL, NULL, true);
     UncropStagingFormat( vd, &core_source );
 
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    if( sys->context_lock > 0 )
+    {
+        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
+    }
+#endif
     if (Direct3D11CreateResources(vd, fmt)) {
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+        if( sys->context_lock > 0 )
+        {
+            ReleaseMutex( sys->context_lock );
+        }
+#endif
         msg_Err(vd, "Failed to allocate resources");
         Direct3D11DestroyResources(vd);
         return VLC_EGENERIC;
     }
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    if( sys->context_lock > 0 )
+    {
+        ReleaseMutex( sys->context_lock );
+    }
+#endif
 
 #if !VLC_WINSTORE_APP
     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
@@ -1153,6 +1202,16 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
     vout_display_sys_t *sys = vd->sys;
     HRESULT hr;
 
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    D3D11_FEATURE_DATA_THREADING threading;
+    hr = ID3D11Device_CheckFeatureSupport( sys->d3ddevice, D3D11_FEATURE_THREADING, &threading, sizeof( threading ) );
+    if( FAILED( hr ) || !threading.DriverConcurrentCreates )
+    {
+        sys->context_lock = CreateMutexEx( NULL, NULL, 0, SYNCHRONIZE );
+        ID3D11Device_SetPrivateData( sys->d3ddevice, &GUID_CONTEXT_MUTEX, sizeof( sys->context_lock ), &sys->context_lock );
+    }
+#endif
+
     hr = UpdateBackBuffer(vd);
     if (FAILED(hr)) {
        msg_Err(vd, "Could not update the backbuffer. (hr=0x%lX)", hr);
@@ -1570,6 +1629,12 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
         ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
     if (sys->pSPUPixelShader)
         ID3D11VertexShader_Release(sys->pSPUPixelShader);
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    if( sys->context_lock > 0 )
+    {
+        CloseHandle( sys->context_lock );
+    }
+#endif
 
     msg_Dbg(vd, "Direct3D11 resources destroyed");
 }
-- 
2.8.1



More information about the vlc-devel mailing list