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

Steve Lhomme robux4 at gmail.com
Mon Jul 20 16:52:45 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.
---
 ...dowsPhone-requires-a-mutex-around-ID3D11V.patch | 88 ++++++++++++++++++++++
 contrib/src/ffmpeg/rules.mak                       |  1 +
 modules/codec/avcodec/d3d11va.c                    | 25 +++++-
 modules/codec/avcodec/video.c                      | 33 ++++++++
 modules/video_output/msw/common.h                  |  1 +
 modules/video_output/msw/direct3d11.c              | 32 ++++++++
 6 files changed, 179 insertions(+), 1 deletion(-)
 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..2344e68
--- /dev/null
+++ b/contrib/src/ffmpeg/0001-d3d11va-WindowsPhone-requires-a-mutex-around-ID3D11V.patch
@@ -0,0 +1,88 @@
+From 43b72da12b6ff8e9d9be8346b2662aedf67c7e70 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 |  2 +-
+ 3 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/libavcodec/d3d11va.h b/libavcodec/d3d11va.h
+index 292e798..71409db 100644
+--- a/libavcodec/d3d11va.h
++++ b/libavcodec/d3d11va.h
+@@ -99,6 +99,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..cb3e965 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 f043b3f..67be2ce 100644
+--- a/libavcodec/version.h
++++ b/libavcodec/version.h
+@@ -29,7 +29,7 @@
+ #include "libavutil/version.h"
+ 
+ #define LIBAVCODEC_VERSION_MAJOR 56
+-#define LIBAVCODEC_VERSION_MINOR 32
++#define LIBAVCODEC_VERSION_MINOR 33
+ #define LIBAVCODEC_VERSION_MICRO  0
+ 
+ #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
+-- 
+1.9.5.msysgit.0
+
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 7140f28..c2a7c56 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, 30, 0, 30, 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, 30, 0, 30, 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;
@@ -392,6 +403,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, 30, 0, 30, 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 +421,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/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index c84ecb9..f9a10eb 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -40,6 +40,10 @@
 #include <libavutil/mem.h>
 #include <libavutil/pixdesc.h>
 
+#if VLC_WINSTORE_APP
+#include <libavcodec/d3d11va.h>
+#endif
+
 #include "avcodec.h"
 #include "va.h"
 
@@ -442,6 +446,11 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
             break;
     }
 
+#if VLC_WINSTORE_APP
+    // not supported until DeviceContext accesses are thread safe
+    p_context->thread_type = 0;
+#endif
+
     if( p_context->thread_type & FF_THREAD_FRAME )
         p_dec->i_extra_picture_buffers = 2 * p_context->thread_count;
 #endif
@@ -675,8 +684,20 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
             p_block->i_dts = VLC_TS_INVALID;
         }
 
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 30, 0, 30, 100)
+        if (p_context->hwaccel_context && p_context->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+            struct AVD3D11VAContext *d3d11va = (struct AVD3D11VAContext*)p_context->hwaccel_context;
+            WaitForSingleObjectEx(d3d11va->context_mutex, INFINITE, FALSE);
+        }
+#endif
         i_used = avcodec_decode_video2( p_context, frame, &b_gotpicture,
                                         &pkt );
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 30, 0, 30, 100)
+        if (p_context->hwaccel_context && p_context->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+            struct AVD3D11VAContext *d3d11va = (struct AVD3D11VAContext*)p_context->hwaccel_context;
+            ReleaseMutex(d3d11va->context_mutex);
+        }
+#endif
         av_free_packet( &pkt );
 
         wait_mt( p_sys );
@@ -772,6 +793,12 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
         }
 
         picture_t *p_pic = frame->opaque;
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 30, 0, 30, 100)
+        if (p_context->hwaccel_context && p_context->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+            struct AVD3D11VAContext *d3d11va = (struct AVD3D11VAContext*)p_context->hwaccel_context;
+            WaitForSingleObjectEx(d3d11va->context_mutex, INFINITE, FALSE);
+        }
+#endif
         if( p_pic == NULL )
         {
             /* Get a new picture */
@@ -792,6 +819,12 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
                 vlc_va_Extract( p_sys->p_va, p_pic, frame->data[3] );
             picture_Hold( p_pic );
         }
+#if VLC_WINSTORE_APP && LIBAVCODEC_VERSION_CHECK(56, 30, 0, 30, 100)
+        if (p_context->hwaccel_context && p_context->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
+            struct AVD3D11VAContext *d3d11va = (struct AVD3D11VAContext*)p_context->hwaccel_context;
+            ReleaseMutex(d3d11va->context_mutex);
+        }
+#endif
 
         if( !p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den )
         {
diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index 7064dd8..a1c1aad 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -181,6 +181,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 486e94b..7fd44f9 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
+/* 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>
@@ -51,6 +57,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 *);
@@ -731,6 +738,9 @@ 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
+        WaitForSingleObjectEx(sys->context_lock, INFINITE, FALSE);
+#endif
         D3D11_BOX box;
         box.left = 0;
         box.right = picture->format.i_visible_width;
@@ -799,6 +809,10 @@ 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)
+        ReleaseMutex(sys->context_lock);
+#endif
 
     picture_Release(picture);
     if (subpicture)
@@ -1095,11 +1109,20 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
 
     UpdateRects(vd, NULL, NULL, true);
 
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    WaitForSingleObjectEx(sys->context_lock, INFINITE, FALSE);
+#endif
     if (Direct3D11CreateResources(vd, fmt)) {
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+        ReleaseMutex(sys->context_lock);
+#endif
         msg_Err(vd, "Failed to allocate resources");
         Direct3D11DestroyResources(vd);
         return VLC_EGENERIC;
     }
+#if defined(HAVE_ID3D11VIDEODECODER) && VLC_WINSTORE_APP
+    ReleaseMutex(sys->context_lock);
+#endif
 
 #if !VLC_WINSTORE_APP
     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
@@ -1165,6 +1188,11 @@ 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
+    sys->context_lock = CreateMutexEx(NULL, TEXT("D3DDeviceContextMutex"), 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);
@@ -1536,6 +1564,10 @@ 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.4.2




More information about the vlc-devel mailing list