[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