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

Steve Lhomme robux4 at gmail.com
Mon Sep 14 13:30:31 CEST 2015


It cannot be accessed from multiple thread. And since the decoder and vout
work in separate threads, we need a mutex to avoid crashes.

--
replaces https://patches.videolan.org/patch/9667/ and https://patches.videolan.org/patch/9599/
---
 ...dowsPhone-requires-a-mutex-around-ID3D11V.patch | 90 ++++++++++++++++++++++
 contrib/src/ffmpeg/rules.mak                       |  1 +
 modules/codec/avcodec/d3d11va.c                    | 48 ++++++++++--
 modules/video_output/msw/common.h                  |  1 +
 modules/video_output/msw/direct3d11.c              | 64 +++++++++++++++
 5 files changed, 199 insertions(+), 5 deletions(-)
 create mode 100644 contrib/src/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch

diff --git a/contrib/src/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch b/contrib/src/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch
new file mode 100644
index 0000000..6bb34a7
--- /dev/null
+++ b/contrib/src/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch
@@ -0,0 +1,90 @@
+From 975eee36b493520d26f73c1e6cfaf53bf49f2e99 Mon Sep 17 00:00:00 2001
+From: Steve Lhomme <robux4 at gmail.com>
+Date: Tue, 30 Jun 2015 11:05:50 +0200
+Subject: [PATCH] d3d11va: WindowsPhone requires a mutex around
+ ID3D11VideoContext
+
+---
+ libavcodec/d3d11va.h |  5 +++++
+ libavcodec/dxva2.c   | 15 +++++++++++++--
+ libavcodec/version.h |  4 ++--
+ 3 files changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/libavcodec/d3d11va.h b/libavcodec/d3d11va.h
+index f5777c2..1316d47 100644
+--- a/libavcodec/d3d11va.h
++++ b/libavcodec/d3d11va.h
+@@ -89,6 +89,11 @@ struct AVD3D11VAContext {
+      * Private to the Libav AVHWAccel implementation
+      */
+     unsigned report_id;
++
++    /**
++      * Mutex to access video_context
++      */
++    HANDLE  context_mutex;
+ };
+ 
+ /**
+diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
+index d4ac98d..ca22de0 100644
+--- a/libavcodec/dxva2.c
++++ b/libavcodec/dxva2.c
+@@ -145,10 +145,13 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
+ 
+     do {
+ #if CONFIG_D3D11VA
+-        if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
++        if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
++            if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
++                WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE);
+             hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
+                                                       ff_dxva2_get_surface(frame),
+                                                       0, NULL);
++        }
+ #endif
+ #if CONFIG_DXVA2
+         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
+@@ -162,6 +165,11 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
+ 
+     if (FAILED(hr)) {
+         av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
++#if CONFIG_D3D11VA
++        if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
++            if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
++                ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
++#endif
+         return -1;
+     }
+ 
+@@ -261,8 +269,11 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
+ 
+ end:
+ #if CONFIG_D3D11VA
+-    if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
++    if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+         hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
++        if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
++            ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
++    }
+ #endif
+ #if CONFIG_DXVA2
+     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
+diff --git a/libavcodec/version.h b/libavcodec/version.h
+index 94cc775..d74a861 100644
+--- a/libavcodec/version.h
++++ b/libavcodec/version.h
+@@ -29,8 +29,8 @@
+ #include "libavutil/version.h"
+ 
+ #define LIBAVCODEC_VERSION_MAJOR 56
+-#define LIBAVCODEC_VERSION_MINOR 35
+-#define LIBAVCODEC_VERSION_MICRO  1
++#define LIBAVCODEC_VERSION_MINOR 36
++#define LIBAVCODEC_VERSION_MICRO  0
+ 
+ #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
+                                                LIBAVCODEC_VERSION_MINOR, \
+-- 
+1.9.5.msysgit.1
+
diff --git a/contrib/src/ffmpeg/rules.mak b/contrib/src/ffmpeg/rules.mak
index 30e51d6..7b06f0c 100644
--- a/contrib/src/ffmpeg/rules.mak
+++ b/contrib/src/ffmpeg/rules.mak
@@ -179,6 +179,7 @@ ffmpeg: ffmpeg-$(HASH).tar.xz .sum-ffmpeg
 	rm -Rf $@ $@-$(HASH)
 	mkdir -p $@-$(HASH)
 	$(XZCAT) "$<" | (cd $@-$(HASH) && tar xv --strip-components=1)
+	$(APPLY) $(SRC)/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch
 	$(MOVE)
 
 .ffmpeg: ffmpeg
diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c
index d4285d4..cbfba51 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);
@@ -112,6 +113,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;
@@ -179,6 +183,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;
@@ -232,6 +243,7 @@ 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)
     {
@@ -241,6 +253,11 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
         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
         if (sys->d3dprocessor)
         {
             // extract the decoded video to a the output Texture
@@ -258,7 +275,8 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
                 if (FAILED(hr))
                 {
                     msg_Err(va, "Failed to create the processor output. (hr=0x%lX)", hr);
-                    return VLC_EGENERIC;
+                    ret = VLC_EGENERIC;
+                    goto done;
                 }
             }
 
@@ -273,7 +291,8 @@ static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
             if (FAILED(hr))
             {
                 msg_Err(va, "Failed to process the video. (hr=0x%lX)", hr);
-                return VLC_EGENERIC;
+                ret = VLC_EGENERIC;
+                goto done;
             }
         }
         else
@@ -295,10 +314,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)
@@ -392,6 +418,14 @@ 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;
+#endif
+
             sys->d3dctx = p_sys->context;
             sys->d3dvidctx = d3dvidctx;
 
@@ -402,7 +436,11 @@ static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
         }
     }
 
-    err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, dx_sys->d3ddev==NULL || va->sys->d3dctx==NULL);
+#if VLC_WINSTORE_APP
+    err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, false);
+#else
+    err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, dx_sys->d3ddev == NULL || va->sys->d3dctx == NULL);
+#endif
     if (err!=VLC_SUCCESS)
         goto error;
 
diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index 0edf3c5..69d0316 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -182,6 +182,7 @@ struct vout_display_sys_t
     pD3DCompile                            OurD3DCompile;
 #else
     IDXGISwapChain1          *dxgiswapChain;   /* DXGI 1.1 swap chain */
+    HANDLE                   context_lock;
 #endif
     ID3D11Device             *d3ddevice;       /* D3D device */
     ID3D11DeviceContext      *d3dcontext;      /* D3D context */
diff --git a/modules/video_output/msw/direct3d11.c b/modules/video_output/msw/direct3d11.c
index ccad237..2ea8a0e 100644
--- a/modules/video_output/msw/direct3d11.c
+++ b/modules/video_output/msw/direct3d11.c
@@ -25,6 +25,12 @@
 # include "config.h"
 #endif
 
+#if _WIN32_WINNT < 0x0600 && defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+/* for CreateMutexEx */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x601
+#endif /* _WIN32_WINNT */
+
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_display.h>
@@ -53,6 +59,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 *);
@@ -707,12 +714,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
     }
 }
 
@@ -722,6 +741,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 = 0;
         box.right = picture->format.i_visible_width;
@@ -794,6 +819,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)
@@ -1090,11 +1120,29 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
 
     UpdateRects(vd, NULL, NULL, true);
 
+#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)");
@@ -1161,6 +1209,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);
@@ -1580,6 +1638,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.5.0



More information about the vlc-devel mailing list