[vlc-devel] [PATCH 06/22] contrib: the D3D11 decoder context needs to be protected on WindowsPhone
Steve Lhomme
robux4 at gmail.com
Fri Jul 31 16:54:50 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 | 39 ++++++++++
6 files changed, 186 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 e6c270f..0dc5977 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..b755a23 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, 33, 0, 33, 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, 33, 0, 33, 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, 33, 0, 33, 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, 33, 0, 33, 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 992b65b..4434396 100644
--- a/modules/video_output/msw/direct3d11.c
+++ b/modules/video_output/msw/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>
@@ -51,6 +58,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 *);
@@ -716,12 +724,18 @@ 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
+ 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
+ ReleaseMutex(sys->context_lock);
+#endif
}
}
@@ -731,6 +745,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 +816,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 +1116,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 +1195,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 +1571,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