浏览代码

obs-qsv11: Use d3d9 allocator on Win7

Use a d3d9 device and allocator to encode in QSV.

This fixes a random crash that could only happen on Windows 7. The QSV
Deviced returned a DEVICE_FAILURE after a random amount of time with the
old method.

This fix is totally based on Shinck's QSVHelper.exe patch for OBS
Classic (see
https://obsproject.com/forum/threads/0-633b-qsvhelper-exe-was-killed-encode-failed.19230/page-3#post-161984
for more information)

This is more like a proof of concept, but that fix is currently stable
and tested more than 50 hours, with a single session of +14 hours.

That commit doesn't respect all OBS Guidelines. It is currently
recommended to wait for a more "cleaner" implementation.
Alexandre Biny 9 年之前
父节点
当前提交
b276b1633e

+ 6 - 0
plugins/obs-qsv11/CMakeLists.txt

@@ -48,9 +48,11 @@ set(obs-qsv11_libmfx_HEADERS
 	)
 
 set(obs-qsv11_SOURCES
+	common_directx9.cpp
 	common_directx11.cpp
 	common_utils.cpp
 	common_utils_windows.cpp
+	device_directx9.cpp
 	QSV_Encoder.cpp
 	QSV_Encoder_Internal.cpp
 	obs-qsv11.c
@@ -59,7 +61,9 @@ set(obs-qsv11_SOURCES
 set(obs-qsv11_HEADERS
 	bits/linux_defs.h
 	bits/windows_defs.h
+	common_directx9.h
 	common_directx11.h
+	device_directx9.h
 	common_utils.h
 	QSV_Encoder.h
 	QSV_Encoder_Internal.h)
@@ -72,7 +76,9 @@ add_library(obs-qsv11 MODULE
 	)
 target_link_libraries(obs-qsv11
 	libobs
+	d3d9
 	d3d11
+	dxva2
 	dxgi
 	)
 

+ 29 - 10
plugins/obs-qsv11/QSV_Encoder_Internal.cpp

@@ -83,6 +83,7 @@ QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL& impl, mfxVersion& version) :
 
 	m_bIsWindows8OrGreater = IsWindows8OrGreater();
 	m_bUseD3D11 = false;
+	m_bD3D9HACK = true;
 
 	if (m_bIsWindows8OrGreater) {
 		tempImpl = impl | MFX_IMPL_VIA_D3D11;
@@ -107,6 +108,21 @@ QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL& impl, mfxVersion& version) :
 			return;
 		}
 	}
+	else if (m_bD3D9HACK) {
+		tempImpl = impl | MFX_IMPL_VIA_D3D9;
+		sts = m_session.Init(tempImpl, &version);
+		if (sts == MFX_ERR_NONE) {
+			m_session.QueryVersion(&version);
+			m_session.Close();
+
+			blog(LOG_INFO, "\timpl:           D3D09\n"
+				       "\tsurf:           Hack");
+
+			m_impl = tempImpl;
+			m_ver = version;
+			return;
+		}
+	}
 
 	// Either windows 7 or D3D11 failed at this point.
 	tempImpl = impl | MFX_IMPL_VIA_D3D9;
@@ -136,11 +152,14 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t * pParams)
 
 	if (m_bUseD3D11)
 		// Use D3D11 surface
-		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator);
+		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, false);
+	else if (m_bD3D9HACK)
+		// Use hack
+		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, true);
 	else
-		// Use system memory
 		sts = Initialize(m_impl, m_ver, &m_session, NULL);
 
+
 	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
 	m_pmfxENC = new MFXVideoENCODE(m_session);
@@ -260,7 +279,7 @@ bool QSV_Encoder_Internal::InitParams(qsv_param_t * pParams)
 	m_mfxEncParams.mfx.FrameInfo.Width = MSDK_ALIGN16(pParams->nWidth);
 	m_mfxEncParams.mfx.FrameInfo.Height = MSDK_ALIGN16(pParams->nHeight);
 
-	if (m_bUseD3D11)
+	if (m_bUseD3D11 || m_bD3D9HACK)
 		m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
 	else
 		m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
@@ -282,7 +301,7 @@ mfxStatus QSV_Encoder_Internal::AllocateSurfaces()
 	EncRequest.NumFrameSuggested += m_mfxEncParams.AsyncDepth;
 
 	// Allocate required surfaces
-	if (m_bUseD3D11) {
+	if (m_bUseD3D11 || m_bD3D9HACK) {
 		sts = m_mfxAllocator.Alloc(m_mfxAllocator.pthis, &EncRequest,
 				&m_mfxResponse);
 		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
@@ -498,14 +517,14 @@ mfxStatus QSV_Encoder_Internal::Encode(uint64_t ts, uint8_t *pDataY,
 	}
 
 	mfxFrameSurface1 *pSurface = m_pmfxSurfaces[nSurfIdx];
-	if (m_bUseD3D11)
+	if (m_bUseD3D11 || m_bD3D9HACK)
 		sts = m_mfxAllocator.Lock(m_mfxAllocator.pthis,
 				pSurface->Data.MemId, &(pSurface->Data));
 
 	sts = LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV);
 	pSurface->Data.TimeStamp = ts;
 
-	if (m_bUseD3D11)
+	if (m_bUseD3D11 || m_bD3D9HACK)
 		sts = m_mfxAllocator.Unlock(m_mfxAllocator.pthis,
 				pSurface->Data.MemId, &(pSurface->Data));
 
@@ -538,7 +557,7 @@ mfxStatus QSV_Encoder_Internal::Drain()
 {
 	mfxStatus sts = MFX_ERR_NONE;
 
-	while (m_pTaskPool[m_nFirstSyncTask].syncp) {
+	while (m_pTaskPool && m_pTaskPool[m_nFirstSyncTask].syncp) {
 		sts = m_session.SyncOperation(m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
 		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
@@ -556,11 +575,11 @@ mfxStatus QSV_Encoder_Internal::ClearData()
 
 	sts = m_pmfxENC->Close();
 
-	if (m_bUseD3D11)
+	if (m_bUseD3D11 || m_bD3D9HACK)
 		m_mfxAllocator.Free(m_mfxAllocator.pthis, &m_mfxResponse);
 
 	for (int i = 0; i < m_nSurfNum; i++) {
-		if (!m_bUseD3D11)
+		if (!m_bUseD3D11 && !m_bD3D9HACK)
 			delete m_pmfxSurfaces[i]->Data.Y;
 
 		delete m_pmfxSurfaces[i];
@@ -578,7 +597,7 @@ mfxStatus QSV_Encoder_Internal::ClearData()
 		m_pmfxENC = NULL;
 	}
 
-	if (m_bUseD3D11)
+	if (m_bUseD3D11 || m_bD3D9HACK)
 		Release();
 
 	m_session.Close();

+ 1 - 0
plugins/obs-qsv11/QSV_Encoder_Internal.h

@@ -108,5 +108,6 @@ private:
 	mfxBitstream                   m_outBitstream;
 	bool                           m_bIsWindows8OrGreater;
 	bool                           m_bUseD3D11;
+	bool                           m_bD3D9HACK;
 };
 

+ 457 - 0
plugins/obs-qsv11/common_directx9.cpp

@@ -0,0 +1,457 @@
+#include "common_directx9.h"
+#include "device_directx9.h"
+
+#include <objbase.h>
+#include <initguid.h>
+#include <d3d9.h>
+#include <map>
+#include <atlbase.h>
+
+
+#define D3DFMT_NV12 (D3DFORMAT)MAKEFOURCC('N','V','1','2')
+#define D3DFMT_YV12 (D3DFORMAT)MAKEFOURCC('Y','V','1','2')
+#define D3DFMT_P010 (D3DFORMAT)MAKEFOURCC('P','0','1','0')
+#define MSDK_SAFE_FREE(X) {if (X) { free(X); X = NULL; }}
+
+std::map<mfxMemId*, mfxHDL>             dx9_allocResponses;
+std::map<mfxHDL, mfxFrameAllocResponse> dx9_allocDecodeResponses;
+std::map<mfxHDL, int>                   dx9_allocDecodeRefCount;
+
+CComPtr<IDirect3DDeviceManager9> m_manager;
+CComPtr<IDirectXVideoDecoderService> m_decoderService;
+CComPtr<IDirectXVideoProcessorService> m_processorService;
+HANDLE m_hDecoder;
+HANDLE m_hProcessor;
+DWORD m_surfaceUsage;
+
+CD3D9Device* g_hwdevice;
+
+const struct {
+	mfxIMPL impl;       // actual implementation
+	mfxU32  adapterID;  // device adapter number
+} implTypes[] = {
+	{ MFX_IMPL_HARDWARE, 0 },
+	{ MFX_IMPL_HARDWARE2, 1 },
+	{ MFX_IMPL_HARDWARE3, 2 },
+	{ MFX_IMPL_HARDWARE4, 3 }
+};
+
+struct mfxAllocatorParams
+{
+    virtual ~mfxAllocatorParams(){};
+};
+
+struct D3DAllocatorParams : mfxAllocatorParams
+{
+    IDirect3DDeviceManager9 *pManager;
+    DWORD surfaceUsage;
+
+    D3DAllocatorParams()
+        : pManager()
+        , surfaceUsage()
+    {
+    }
+};
+
+mfxStatus DX9_Alloc_Init(D3DAllocatorParams *pParams)
+{
+    D3DAllocatorParams *pd3dParams = 0;
+    pd3dParams = dynamic_cast<D3DAllocatorParams *>(pParams);
+    if (!pd3dParams)
+        return MFX_ERR_NOT_INITIALIZED;
+
+    m_manager = pd3dParams->pManager;
+    m_surfaceUsage = pd3dParams->surfaceUsage;
+
+    return MFX_ERR_NONE;
+}
+
+mfxStatus DX9_CreateHWDevice(mfxSession session, mfxHDL* deviceHandle, HWND, bool)
+{
+	mfxStatus result;
+
+	g_hwdevice = new CD3D9Device;
+	mfxU32  adapterNum = 0;
+	mfxIMPL impl;
+
+	MFXQueryIMPL(session, &impl);
+
+	mfxIMPL baseImpl = MFX_IMPL_BASETYPE(impl); // Extract Media SDK base implementation type
+
+						    // get corresponding adapter number
+	for (mfxU8 i = 0; i < sizeof(implTypes) / sizeof(implTypes[0]); i++) {
+		if (implTypes[i].impl == baseImpl) {
+			adapterNum = implTypes[i].adapterID;
+			break;
+		}
+	}
+
+	POINT point = { 0, 0 };
+	HWND window = WindowFromPoint(point);
+
+	result = g_hwdevice->Init(window, 0, adapterNum);
+	if (result != MFX_ERR_NONE) {
+		return result;
+	}
+
+	g_hwdevice->GetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle);
+
+
+	D3DAllocatorParams dx9_allocParam;
+	dx9_allocParam.pManager = reinterpret_cast<IDirect3DDeviceManager9 *>(*deviceHandle);
+	DX9_Alloc_Init(&dx9_allocParam);
+	return MFX_ERR_NONE;
+}
+
+void DX9_CleanupHWDevice()
+{
+	if (g_hwdevice) {
+		// g_hwdevice->Close();
+		delete g_hwdevice;
+		g_hwdevice = NULL;
+	}
+	if (m_manager && m_hDecoder) {
+		m_manager->CloseDeviceHandle(m_hDecoder);
+		m_manager = NULL;
+		m_hDecoder = NULL;
+	}
+
+	if (m_manager && m_hProcessor) {
+		m_manager->CloseDeviceHandle(m_hProcessor);
+		m_manager = NULL;
+		m_hProcessor = NULL;
+	}
+
+	if (m_decoderService) {
+		// delete m_decoderService;
+		m_decoderService = NULL;
+	}
+
+	if (m_processorService) {
+		// delete m_processorService;
+		m_processorService = NULL;
+	}
+}
+
+D3DFORMAT ConvertMfxFourccToD3dFormat(mfxU32 fourcc)
+{
+	switch (fourcc)
+	{
+	case MFX_FOURCC_NV12:
+		return D3DFMT_NV12;
+	case MFX_FOURCC_YV12:
+		return D3DFMT_YV12;
+	case MFX_FOURCC_YUY2:
+		return D3DFMT_YUY2;
+	case MFX_FOURCC_RGB3:
+		return D3DFMT_R8G8B8;
+	case MFX_FOURCC_RGB4:
+		return D3DFMT_A8R8G8B8;
+	case MFX_FOURCC_P8:
+		return D3DFMT_P8;
+	case MFX_FOURCC_P010:
+		return D3DFMT_P010;
+	case MFX_FOURCC_A2RGB10:
+		return D3DFMT_A2R10G10B10;
+	default:
+		return D3DFMT_UNKNOWN;
+	}
+}
+
+mfxStatus dx9_simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr)
+{
+	pthis; // To suppress warning for this unused parameter
+
+	if (!ptr || !mid)
+		return MFX_ERR_NULL_PTR;
+
+	mfxHDLPair *dxmid = (mfxHDLPair*)mid;
+	IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9*>(dxmid->first);
+	if (pSurface == 0)
+		return MFX_ERR_INVALID_HANDLE;
+
+	D3DSURFACE_DESC desc;
+	HRESULT hr = pSurface->GetDesc(&desc);
+	if (FAILED(hr))
+		return MFX_ERR_LOCK_MEMORY;
+
+	if (desc.Format != D3DFMT_NV12 &&
+		desc.Format != D3DFMT_YV12 &&
+		desc.Format != D3DFMT_YUY2 &&
+		desc.Format != D3DFMT_R8G8B8 &&
+		desc.Format != D3DFMT_A8R8G8B8 &&
+		desc.Format != D3DFMT_P8 &&
+		desc.Format != D3DFMT_P010 &&
+		desc.Format != D3DFMT_A2R10G10B10)
+		return MFX_ERR_LOCK_MEMORY;
+
+	D3DLOCKED_RECT locked;
+
+	hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
+	if (FAILED(hr))
+		return MFX_ERR_LOCK_MEMORY;
+
+	switch ((DWORD)desc.Format)
+	{
+	case D3DFMT_NV12:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->Y = (mfxU8 *)locked.pBits;
+		ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
+		ptr->V = ptr->U + 1;
+		break;
+	case D3DFMT_YV12:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->Y = (mfxU8 *)locked.pBits;
+		ptr->V = ptr->Y + desc.Height * locked.Pitch;
+		ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4;
+		break;
+	case D3DFMT_YUY2:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->Y = (mfxU8 *)locked.pBits;
+		ptr->U = ptr->Y + 1;
+		ptr->V = ptr->Y + 3;
+		break;
+	case D3DFMT_R8G8B8:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->B = (mfxU8 *)locked.pBits;
+		ptr->G = ptr->B + 1;
+		ptr->R = ptr->B + 2;
+		break;
+	case D3DFMT_A8R8G8B8:
+	case D3DFMT_A2R10G10B10:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->B = (mfxU8 *)locked.pBits;
+		ptr->G = ptr->B + 1;
+		ptr->R = ptr->B + 2;
+		ptr->A = ptr->B + 3;
+		break;
+	case D3DFMT_P8:
+		ptr->Pitch = (mfxU16)locked.Pitch;
+		ptr->Y = (mfxU8 *)locked.pBits;
+		ptr->U = 0;
+		ptr->V = 0;
+		break;
+	case D3DFMT_P010:
+		ptr->PitchHigh = (mfxU16)(locked.Pitch / (1 << 16));
+		ptr->PitchLow = (mfxU16)(locked.Pitch % (1 << 16));
+		ptr->Y = (mfxU8 *)locked.pBits;
+		ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
+		ptr->V = ptr->U + 1;
+		break;
+	}
+
+	return MFX_ERR_NONE;
+}
+
+mfxStatus dx9_simple_unlock(mfxHDL, mfxMemId mid, mfxFrameData* ptr)
+{
+	if (!mid)
+		return MFX_ERR_NULL_PTR;
+
+	mfxHDLPair *dxmid = (mfxHDLPair*)mid;
+	IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9*>(dxmid->first);
+	if (pSurface == 0)
+		return MFX_ERR_INVALID_HANDLE;
+
+	pSurface->UnlockRect();
+
+	if (NULL != ptr)
+	{
+		ptr->Pitch = 0;
+		ptr->Y = 0;
+		ptr->U = 0;
+		ptr->V = 0;
+	}
+
+	return MFX_ERR_NONE;
+}
+
+mfxStatus dx9_simple_gethdl(mfxHDL, mfxMemId mid, mfxHDL* handle)
+{
+	if (!mid || !handle)
+		return MFX_ERR_NULL_PTR;
+
+	mfxHDLPair *dxMid = (mfxHDLPair*)mid;
+	*handle = dxMid->first;
+	return MFX_ERR_NONE;
+}
+
+mfxStatus _dx9_simple_free(mfxFrameAllocResponse* response)
+{
+	if (!response)
+		return MFX_ERR_NULL_PTR;
+
+	mfxStatus sts = MFX_ERR_NONE;
+
+	if (response->mids) {
+		for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
+			if (response->mids[i]) {
+				mfxHDLPair *dxMids = (mfxHDLPair*)response->mids[i];
+				static_cast<IDirect3DSurface9*>(dxMids->first)->Release();
+			}
+		}
+		MSDK_SAFE_FREE(response->mids[0]);
+	}
+	MSDK_SAFE_FREE(response->mids);
+
+	return sts;
+}
+
+mfxStatus dx9_simple_free(mfxHDL pthis, mfxFrameAllocResponse* response)
+{
+    if (NULL == response)
+        return MFX_ERR_NULL_PTR;
+
+    if (dx9_allocResponses.find(response->mids) == dx9_allocResponses.end()) {
+        // Decode free response handling
+        if (--dx9_allocDecodeRefCount[pthis] == 0) {
+            _dx9_simple_free(response);
+            dx9_allocDecodeResponses.erase(pthis);
+            dx9_allocDecodeRefCount.erase(pthis);
+        }
+    } else {
+        // Encode and VPP free response handling
+        dx9_allocResponses.erase(response->mids);
+        _dx9_simple_free(response);
+    }
+
+    return MFX_ERR_NONE;
+}
+
+mfxStatus _dx9_simple_alloc(mfxFrameAllocRequest* request, mfxFrameAllocResponse* response)
+{
+	HRESULT hr;
+
+	MSDK_CHECK_POINTER(request, MFX_ERR_NULL_PTR);
+	if (request->NumFrameSuggested == 0)
+		return MFX_ERR_UNKNOWN;
+
+	D3DFORMAT format = ConvertMfxFourccToD3dFormat(request->Info.FourCC);
+
+	if (format == D3DFMT_UNKNOWN)
+		return MFX_ERR_UNSUPPORTED;
+
+	DWORD   target;
+
+	if (MFX_MEMTYPE_DXVA2_DECODER_TARGET & request->Type)
+	{
+		target = DXVA2_VideoDecoderRenderTarget;
+	}
+	else if (MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET & request->Type)
+	{
+		target = DXVA2_VideoProcessorRenderTarget;
+	}
+	else
+		return MFX_ERR_UNSUPPORTED;
+
+	IDirectXVideoAccelerationService* videoService = NULL;
+
+	if (target == DXVA2_VideoProcessorRenderTarget) {
+		if (!m_hProcessor) {
+			hr = m_manager->OpenDeviceHandle(&m_hProcessor);
+			if (FAILED(hr))
+				return MFX_ERR_MEMORY_ALLOC;
+
+			hr = m_manager->GetVideoService(m_hProcessor, IID_IDirectXVideoProcessorService, (void**)&m_processorService);
+			if (FAILED(hr))
+				return MFX_ERR_MEMORY_ALLOC;
+		}
+		videoService = m_processorService;
+	}
+	else {
+		if (!m_hDecoder)
+		{
+			hr = m_manager->OpenDeviceHandle(&m_hDecoder);
+			if (FAILED(hr))
+				return MFX_ERR_MEMORY_ALLOC;
+
+			hr = m_manager->GetVideoService(m_hDecoder, IID_IDirectXVideoDecoderService, (void**)&m_decoderService);
+			if (FAILED(hr))
+				return MFX_ERR_MEMORY_ALLOC;
+		}
+		videoService = m_decoderService;
+	}
+
+	mfxHDLPair *dxMids = NULL, **dxMidPtrs = NULL;
+	dxMids = (mfxHDLPair*)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair));
+	dxMidPtrs = (mfxHDLPair**)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair*));
+
+	if (!dxMids || !dxMidPtrs) {
+		MSDK_SAFE_FREE(dxMids);
+		MSDK_SAFE_FREE(dxMidPtrs);
+		return MFX_ERR_MEMORY_ALLOC;
+	}
+
+	response->mids = (mfxMemId*)dxMidPtrs;
+	response->NumFrameActual = request->NumFrameSuggested;
+
+	if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
+		for (int i = 0; i < request->NumFrameSuggested; i++) {
+			hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, 0, format,
+				D3DPOOL_DEFAULT, m_surfaceUsage, target, (IDirect3DSurface9**)&dxMids[i].first, &dxMids[i].second);
+			if (FAILED(hr)) {
+				_dx9_simple_free(response);
+				MSDK_SAFE_FREE(dxMids);
+				return MFX_ERR_MEMORY_ALLOC;
+			}
+			dxMidPtrs[i] = &dxMids[i];
+		}
+	}
+	else {
+		safe_array<IDirect3DSurface9*> dxSrf(new IDirect3DSurface9*[request->NumFrameSuggested]);
+		if (!dxSrf.get())
+		{
+			MSDK_SAFE_FREE(dxMids);
+			return MFX_ERR_MEMORY_ALLOC;
+		}
+		hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, request->NumFrameSuggested - 1, format,
+			D3DPOOL_DEFAULT, m_surfaceUsage, target, dxSrf.get(), NULL);
+		if (FAILED(hr))
+		{
+			MSDK_SAFE_FREE(dxMids);
+			return MFX_ERR_MEMORY_ALLOC;
+		}
+
+
+		for (int i = 0; i < request->NumFrameSuggested; i++) {
+			dxMids[i].first = dxSrf.get()[i];
+			dxMidPtrs[i] = &dxMids[i];
+		}
+	}
+	return MFX_ERR_NONE;
+}
+
+mfxStatus dx9_simple_alloc(mfxHDL pthis, mfxFrameAllocRequest* request, mfxFrameAllocResponse* response)
+{
+    mfxStatus sts = MFX_ERR_NONE;
+
+    if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY)
+        return MFX_ERR_UNSUPPORTED;
+
+    if (dx9_allocDecodeResponses.find(pthis) != dx9_allocDecodeResponses.end() &&
+        MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
+        MFX_MEMTYPE_FROM_DECODE & request->Type) {
+        // Memory for this request was already allocated during manual allocation stage. Return saved response
+        //   When decode acceleration device (DXVA) is created it requires a list of d3d surfaces to be passed.
+        //   Therefore Media SDK will ask for the surface info/mids again at Init() stage, thus requiring us to return the saved response
+        //   (No such restriction applies to Encode or VPP)
+        *response = dx9_allocDecodeResponses[pthis];
+        dx9_allocDecodeRefCount[pthis]++;
+    } else {
+        sts = _dx9_simple_alloc(request, response);
+
+        if (MFX_ERR_NONE == sts) {
+            if ( MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
+                 MFX_MEMTYPE_FROM_DECODE & request->Type) {
+                // Decode alloc response handling
+                dx9_allocDecodeResponses[pthis] = *response;
+                dx9_allocDecodeRefCount[pthis]++;
+            } else {
+                // Encode and VPP alloc response handling
+                dx9_allocResponses[response->mids] = pthis;
+            }
+        }
+    }
+
+    return sts;
+}

+ 70 - 0
plugins/obs-qsv11/common_directx9.h

@@ -0,0 +1,70 @@
+/*********************************************************************************
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved.
+
+**********************************************************************************/
+
+#pragma once
+
+#include "common_utils.h"
+#include <initguid.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include <dxva.h>
+#include <windows.h>
+
+#define VIDEO_MAIN_FORMAT D3DFMT_YUY2
+
+class IGFXS3DControl;
+
+/** Direct3D 9 device implementation.
+@note Can be initilized for only 1 or two 2 views. Handle to
+MFX_HANDLE_GFXS3DCONTROL must be set prior if initializing for 2 views.
+
+@note Device always set D3DPRESENT_PARAMETERS::Windowed to TRUE.
+*/
+    template <class T>
+    class safe_array
+    {
+    public:
+        safe_array(T *ptr = 0):m_ptr(ptr)
+        { // construct from object pointer
+        };
+        ~safe_array()
+        {
+            reset(0);
+        }
+        T* get()
+        { // return wrapped pointer
+            return m_ptr;
+        }
+        T* release()
+        { // return wrapped pointer and give up ownership
+            T* ptr = m_ptr;
+            m_ptr = 0;
+            return ptr;
+        }
+        void reset(T* ptr)
+        { // destroy designated object and store new pointer
+            if (m_ptr)
+            {
+                delete[] m_ptr;
+            }
+            m_ptr = ptr;
+        }
+    protected:
+        T* m_ptr; // the wrapped object pointer
+    };
+
+mfxStatus dx9_simple_alloc(mfxHDL pthis, mfxFrameAllocRequest* request, mfxFrameAllocResponse* response);
+mfxStatus dx9_simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr);
+mfxStatus dx9_simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr);
+mfxStatus dx9_simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL* handle);
+mfxStatus dx9_simple_free(mfxHDL pthis, mfxFrameAllocResponse* response);
+
+mfxStatus DX9_CreateHWDevice(mfxSession session, mfxHDL* deviceHandle, HWND hWnd, bool bCreateSharedHandles);
+void DX9_CleanupHWDevice();

+ 1 - 1
plugins/obs-qsv11/common_utils.h

@@ -95,7 +95,7 @@ typedef struct {
 int GetFreeTaskIndex(Task* pTaskPool, mfxU16 nPoolSize);
 
 // Initialize Intel Media SDK Session, device/display and memory manager
-mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles = false);
+mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles = false, bool dx9hack = false);
 
 // Release resources (device/display)
 void Release();

+ 37 - 11
plugins/obs-qsv11/common_utils_windows.cpp

@@ -16,13 +16,14 @@ Copyright(c) 2005-2014 Intel Corporation. All Rights Reserved.
 #include "common_directx.h"
 #elif DX11_D3D
 #include "common_directx11.h"
+#include "common_directx9.h"
 #endif
 
 /* =======================================================
  * Windows implementation of OS-specific utility functions
  */
 
-mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles)
+mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles, bool dx9hack)
 {
     bCreateSharedHandles; // (Hugh) Currently unused
     pmfxAllocator; // (Hugh) Currently unused
@@ -30,10 +31,10 @@ mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mf
     mfxStatus sts = MFX_ERR_NONE;
 
     // If mfxFrameAllocator is provided it means we need to setup DirectX device and memory allocator
-    if (pmfxAllocator) {
-		// Initialize Intel Media SDK Session
-		sts = pSession->Init(impl, &ver);
-		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+    if (pmfxAllocator && !dx9hack) {
+        // Initialize Intel Media SDK Session
+        sts = pSession->Init(impl, &ver);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
         // Create DirectX device context
         mfxHDL deviceHandle;
@@ -54,13 +55,37 @@ mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mf
         // Since we are using video memory we must provide Media SDK with an external allocator
         sts = pSession->SetFrameAllocator(pmfxAllocator);
         MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+    } else if (pmfxAllocator && dx9hack) {
+        // Initialize Intel Media SDK Session
+        sts = pSession->Init(impl, &ver);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+        // Create DirectX device context
+        mfxHDL deviceHandle;
+        sts = DX9_CreateHWDevice(*pSession, &deviceHandle, NULL, bCreateSharedHandles);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+        // Provide device manager to Media SDK
+        sts = pSession->SetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+        pmfxAllocator->pthis  = *pSession; // We use Media SDK session ID as the allocation identifier
+        pmfxAllocator->Alloc  = dx9_simple_alloc;
+        pmfxAllocator->Free   = dx9_simple_free;
+        pmfxAllocator->Lock   = dx9_simple_lock;
+        pmfxAllocator->Unlock = dx9_simple_unlock;
+        pmfxAllocator->GetHDL = dx9_simple_gethdl;
+
+        // Since we are using video memory we must provide Media SDK with an external allocator
+        sts = pSession->SetFrameAllocator(pmfxAllocator);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+    } else {
+        // Initialize Intel Media SDK Session
+        sts = pSession->Init(impl, &ver);
+        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
     }
-	else
-	{
-		// Initialize Intel Media SDK Session
-		sts = pSession->Init(impl, &ver);
-		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
-	}
     return sts;
 }
 
@@ -68,6 +93,7 @@ void Release()
 {
 #if defined(DX9_D3D) || defined(DX11_D3D)
     CleanupHWDevice();
+    DX9_CleanupHWDevice();
 #endif
 }
 

+ 451 - 0
plugins/obs-qsv11/device_directx9.cpp

@@ -0,0 +1,451 @@
+/*********************************************************************************
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2011-2015 Intel Corporation. All Rights Reserved.
+
+**********************************************************************************/
+
+// #include "mfx_samples_config.h"
+
+#if defined(WIN32) || defined(WIN64)
+
+//prefast singnature used in combaseapi.h
+#ifndef _PREFAST_
+    #pragma warning(disable:4068)
+#endif
+
+#include "device_directx9.h"
+// #include "igfx_s3dcontrol.h"
+
+#include "atlbase.h"
+
+// Macros
+#define MSDK_ZERO_MEMORY(VAR)                    {memset(&VAR, 0, sizeof(VAR));}
+#define MSDK_MEMCPY_VAR(dstVarName, src, count) memcpy_s(&(dstVarName), sizeof(dstVarName), (src), (count))
+
+CD3D9Device::CD3D9Device()
+{
+    m_pD3D9 = NULL;
+    m_pD3DD9 = NULL;
+    m_pDeviceManager9 = NULL;
+    MSDK_ZERO_MEMORY(m_D3DPP);
+    m_resetToken = 0;
+
+    m_nViews = 0;
+    m_pS3DControl = NULL;
+
+    MSDK_ZERO_MEMORY(m_backBufferDesc);
+    m_pDXVAVPS = NULL;
+    m_pDXVAVP_Left = NULL;
+    m_pDXVAVP_Right = NULL;
+
+    MSDK_ZERO_MEMORY(m_targetRect);
+
+    MSDK_ZERO_MEMORY(m_VideoDesc);
+    MSDK_ZERO_MEMORY(m_BltParams);
+    MSDK_ZERO_MEMORY(m_Sample);
+
+    // Initialize DXVA structures
+
+    DXVA2_AYUVSample16 color = {
+        0x8000,          // Cr
+        0x8000,          // Cb
+        0x1000,          // Y
+        0xffff           // Alpha
+    };
+
+    DXVA2_ExtendedFormat format =   {           // DestFormat
+        DXVA2_SampleProgressiveFrame,           // SampleFormat
+        DXVA2_VideoChromaSubsampling_MPEG2,     // VideoChromaSubsampling
+        DXVA_NominalRange_0_255,                // NominalRange
+        DXVA2_VideoTransferMatrix_BT709,        // VideoTransferMatrix
+        DXVA2_VideoLighting_bright,             // VideoLighting
+        DXVA2_VideoPrimaries_BT709,             // VideoPrimaries
+        DXVA2_VideoTransFunc_709                // VideoTransferFunction
+    };
+
+    // init m_VideoDesc structure
+    MSDK_MEMCPY_VAR(m_VideoDesc.SampleFormat, &format, sizeof(DXVA2_ExtendedFormat));
+    m_VideoDesc.SampleWidth                         = 0;
+    m_VideoDesc.SampleHeight                        = 0;
+    m_VideoDesc.InputSampleFreq.Numerator           = 60;
+    m_VideoDesc.InputSampleFreq.Denominator         = 1;
+    m_VideoDesc.OutputFrameFreq.Numerator           = 60;
+    m_VideoDesc.OutputFrameFreq.Denominator         = 1;
+
+    // init m_BltParams structure
+    MSDK_MEMCPY_VAR(m_BltParams.DestFormat, &format, sizeof(DXVA2_ExtendedFormat));
+    MSDK_MEMCPY_VAR(m_BltParams.BackgroundColor, &color, sizeof(DXVA2_AYUVSample16));
+
+    // init m_Sample structure
+    m_Sample.Start = 0;
+    m_Sample.End = 1;
+    m_Sample.SampleFormat = format;
+    m_Sample.PlanarAlpha.Fraction = 0;
+    m_Sample.PlanarAlpha.Value = 1;
+
+    m_bIsA2rgb10 = FALSE;
+}
+
+bool CD3D9Device::CheckOverlaySupport()
+{
+    D3DCAPS9                d3d9caps;
+    D3DOVERLAYCAPS          d3doverlaycaps = {0};
+    IDirect3D9ExOverlayExtension *d3d9overlay = NULL;
+    bool overlaySupported = false;
+
+    memset(&d3d9caps, 0, sizeof(d3d9caps));
+    HRESULT hr = m_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d9caps);
+    if (FAILED(hr) || !(d3d9caps.Caps & D3DCAPS_OVERLAY))
+    {
+        overlaySupported = false;
+    }
+    else
+    {
+        hr = m_pD3D9->QueryInterface(IID_PPV_ARGS(&d3d9overlay));
+        if (FAILED(hr) || (d3d9overlay == NULL))
+        {
+            overlaySupported = false;
+        }
+        else
+        {
+            hr = d3d9overlay->CheckDeviceOverlayType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+                m_D3DPP.BackBufferWidth,
+                m_D3DPP.BackBufferHeight,
+                m_D3DPP.BackBufferFormat, NULL,
+                D3DDISPLAYROTATION_IDENTITY, &d3doverlaycaps);
+            MSDK_SAFE_RELEASE(d3d9overlay);
+
+            if (FAILED(hr))
+            {
+                overlaySupported = false;
+            }
+            else
+            {
+                overlaySupported = true;
+            }
+        }
+    }
+
+    return overlaySupported;
+}
+
+mfxStatus CD3D9Device::FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS &D3DPP)
+{
+    mfxStatus sts = MFX_ERR_NONE;
+
+    D3DPP.Windowed = true;
+    D3DPP.hDeviceWindow = (HWND)hWindow;
+
+    D3DPP.Flags                      = D3DPRESENTFLAG_VIDEO;
+    D3DPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
+    D3DPP.PresentationInterval       = D3DPRESENT_INTERVAL_ONE; // note that this setting leads to an implicit timeBeginPeriod call
+    D3DPP.BackBufferCount            = 1;
+    D3DPP.BackBufferFormat           = (m_bIsA2rgb10) ? D3DFMT_A2R10G10B10 : D3DFMT_X8R8G8B8;
+
+    if (hWindow)
+    {
+        RECT r;
+        GetClientRect((HWND)hWindow, &r);
+        int x = GetSystemMetrics(SM_CXSCREEN);
+        int y = GetSystemMetrics(SM_CYSCREEN);
+        D3DPP.BackBufferWidth  = min(r.right - r.left, x);
+        D3DPP.BackBufferHeight = min(r.bottom - r.top, y);
+    }
+    else
+    {
+        D3DPP.BackBufferWidth  = GetSystemMetrics(SM_CYSCREEN);
+        D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
+    }
+    //
+    // Mark the back buffer lockable if software DXVA2 could be used.
+    // This is because software DXVA2 device requires a lockable render target
+    // for the optimal performance.
+    //
+    {
+        D3DPP.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+    }
+
+    bool isOverlaySupported = CheckOverlaySupport();
+    if (2 == nViews && !isOverlaySupported)
+        return MFX_ERR_UNSUPPORTED;
+
+    bool needOverlay = (2 == nViews) ? true : false;
+
+    D3DPP.SwapEffect = needOverlay ? D3DSWAPEFFECT_OVERLAY : D3DSWAPEFFECT_DISCARD;
+
+    return sts;
+}
+
+mfxStatus CD3D9Device::Init(
+    mfxHDL hWindow,
+    mfxU16 nViews,
+    mfxU32 nAdapterNum)
+{
+    mfxStatus sts = MFX_ERR_NONE;
+
+    if (2 < nViews)
+        return MFX_ERR_UNSUPPORTED;
+
+    m_nViews = nViews;
+
+    HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9);
+    if (!m_pD3D9 || FAILED(hr))
+        return MFX_ERR_DEVICE_FAILED;
+
+    ZeroMemory(&m_D3DPP, sizeof(m_D3DPP));
+    sts = FillD3DPP(hWindow, nViews, m_D3DPP);
+    MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+
+    hr = m_pD3D9->CreateDeviceEx(
+        nAdapterNum,
+        D3DDEVTYPE_HAL,
+        (HWND)hWindow,
+        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
+        &m_D3DPP,
+        NULL,
+        &m_pD3DD9);
+    if (FAILED(hr))
+        return MFX_ERR_NULL_PTR;
+
+    if(hWindow)
+    {
+        hr = m_pD3DD9->ResetEx(&m_D3DPP, NULL);
+        if (FAILED(hr))
+            return MFX_ERR_UNDEFINED_BEHAVIOR;
+        hr = m_pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
+        if (FAILED(hr))
+            return MFX_ERR_UNDEFINED_BEHAVIOR;
+    }
+    UINT resetToken = 0;
+
+    hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &m_pDeviceManager9);
+    if (FAILED(hr))
+        return MFX_ERR_NULL_PTR;
+
+    hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, resetToken);
+    if (FAILED(hr))
+        return MFX_ERR_UNDEFINED_BEHAVIOR;
+
+    m_resetToken = resetToken;
+
+    return sts;
+}
+
+mfxStatus CD3D9Device::Reset()
+{
+    HRESULT hr = NO_ERROR;
+    MSDK_CHECK_POINTER(m_pD3DD9, MFX_ERR_NULL_PTR);
+
+    if (m_D3DPP.Windowed)
+    {
+        RECT r;
+        GetClientRect((HWND)m_D3DPP.hDeviceWindow, &r);
+        int x = GetSystemMetrics(SM_CXSCREEN);
+        int y = GetSystemMetrics(SM_CYSCREEN);
+        m_D3DPP.BackBufferWidth  = min(r.right - r.left, x);
+        m_D3DPP.BackBufferHeight = min(r.bottom - r.top, y);
+    }
+    else
+    {
+        m_D3DPP.BackBufferWidth  = GetSystemMetrics(SM_CXSCREEN);
+        m_D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
+    }
+
+    // Reset will change the parameters, so use a copy instead.
+    D3DPRESENT_PARAMETERS d3dpp = m_D3DPP;
+    hr = m_pD3DD9->ResetEx(&d3dpp, NULL);
+
+    if (FAILED(hr))
+        return MFX_ERR_UNDEFINED_BEHAVIOR;
+
+    hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, m_resetToken);
+    if (FAILED(hr))
+        return MFX_ERR_UNDEFINED_BEHAVIOR;
+
+    return MFX_ERR_NONE;
+}
+
+void CD3D9Device::Close()
+{
+    MSDK_SAFE_RELEASE(m_pDXVAVP_Left);
+    MSDK_SAFE_RELEASE(m_pDXVAVP_Right);
+    MSDK_SAFE_RELEASE(m_pDXVAVPS);
+
+    MSDK_SAFE_RELEASE(m_pDeviceManager9);
+    MSDK_SAFE_RELEASE(m_pD3DD9);
+    MSDK_SAFE_RELEASE(m_pD3D9);
+    m_pS3DControl = NULL;
+}
+
+CD3D9Device::~CD3D9Device()
+{
+    Close();
+}
+
+mfxStatus CD3D9Device::GetHandle(mfxHandleType type, mfxHDL *pHdl)
+{
+    if (MFX_HANDLE_DIRECT3D_DEVICE_MANAGER9 == type && pHdl != NULL)
+    {
+        *pHdl = m_pDeviceManager9;
+
+        return MFX_ERR_NONE;
+    }
+    else if (MFX_HANDLE_GFXS3DCONTROL == type && pHdl != NULL)
+    {
+        *pHdl = m_pS3DControl;
+
+        return MFX_ERR_NONE;
+    }
+    return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus CD3D9Device::SetHandle(mfxHandleType type, mfxHDL hdl)
+{
+    if (MFX_HANDLE_GFXS3DCONTROL == type && hdl != NULL)
+    {
+        m_pS3DControl = (IGFXS3DControl*)hdl;
+        return MFX_ERR_NONE;
+    }
+    else if (MFX_HANDLE_DEVICEWINDOW == type && hdl != NULL) //for render window handle
+    {
+        m_D3DPP.hDeviceWindow = (HWND)hdl;
+        return MFX_ERR_NONE;
+    }
+    return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus CD3D9Device::RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc)
+{
+    HRESULT hr = S_OK;
+
+    if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl)))
+        return MFX_ERR_UNDEFINED_BEHAVIOR;
+
+    MSDK_CHECK_POINTER(pSurface, MFX_ERR_NULL_PTR);
+    MSDK_CHECK_POINTER(m_pDeviceManager9, MFX_ERR_NOT_INITIALIZED);
+    MSDK_CHECK_POINTER(pmfxAlloc, MFX_ERR_NULL_PTR);
+
+    // don't try to render second view if output rect changed since first view
+    if (2 == m_nViews && (0 != pSurface->Info.FrameId.ViewId))
+        return MFX_ERR_NONE;
+
+    hr = m_pD3DD9->TestCooperativeLevel();
+
+    switch (hr)
+    {
+        case D3D_OK :
+            break;
+
+        case D3DERR_DEVICELOST :
+        {
+            return MFX_ERR_DEVICE_LOST;
+        }
+
+        case D3DERR_DEVICENOTRESET :
+            {
+            return MFX_ERR_UNKNOWN;
+        }
+
+        default :
+        {
+            return MFX_ERR_UNKNOWN;
+        }
+    }
+
+    CComPtr<IDirect3DSurface9> pBackBuffer;
+    hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
+
+    mfxHDLPair* dxMemId = (mfxHDLPair*)pSurface->Data.MemId;
+
+    hr = m_pD3DD9->StretchRect((IDirect3DSurface9*)dxMemId->first, NULL, pBackBuffer, NULL, D3DTEXF_LINEAR);
+    if (FAILED(hr))
+    {
+        return MFX_ERR_UNKNOWN;
+    }
+
+    if (SUCCEEDED(hr)&& (1 == m_nViews || pSurface->Info.FrameId.ViewId == 1))
+    {
+        hr = m_pD3DD9->Present(NULL, NULL, NULL, NULL);
+    }
+
+    return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED;
+}
+
+/*
+mfxStatus CD3D9Device::CreateVideoProcessors()
+{
+    if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl)))
+        return MFX_ERR_UNDEFINED_BEHAVIOR;
+
+   MSDK_SAFE_RELEASE(m_pDXVAVP_Left);
+   MSDK_SAFE_RELEASE(m_pDXVAVP_Right);
+
+   HRESULT hr ;
+
+   if (2 == m_nViews && NULL != m_pS3DControl)
+   {
+       hr = m_pS3DControl->SetDevice(m_pDeviceManager9);
+       if (FAILED(hr))
+       {
+           return MFX_ERR_DEVICE_FAILED;
+       }
+   }
+
+   ZeroMemory(&m_backBufferDesc, sizeof(m_backBufferDesc));
+   IDirect3DSurface9 *backBufferTmp = NULL;
+   hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBufferTmp);
+   if (NULL != backBufferTmp)
+       backBufferTmp->GetDesc(&m_backBufferDesc);
+   MSDK_SAFE_RELEASE(backBufferTmp);
+
+   if (SUCCEEDED(hr))
+   {
+       // Create DXVA2 Video Processor Service.
+       hr = DXVA2CreateVideoService(m_pD3DD9,
+           IID_IDirectXVideoProcessorService,
+           (void**)&m_pDXVAVPS);
+   }
+
+   if (2 == m_nViews)
+   {
+        // Activate L channel
+        if (SUCCEEDED(hr))
+        {
+           hr = m_pS3DControl->SelectLeftView();
+        }
+
+        if (SUCCEEDED(hr))
+        {
+           // Create VPP device for the L channel
+           hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice,
+               &m_VideoDesc,
+               m_D3DPP.BackBufferFormat,
+               1,
+               &m_pDXVAVP_Left);
+        }
+
+        // Activate R channel
+        if (SUCCEEDED(hr))
+        {
+           hr = m_pS3DControl->SelectRightView();
+        }
+
+   }
+   if (SUCCEEDED(hr))
+   {
+       hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice,
+           &m_VideoDesc,
+           m_D3DPP.BackBufferFormat,
+           1,
+           &m_pDXVAVP_Right);
+   }
+
+   return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED;
+}
+*/
+
+#endif // #if defined(WIN32) || defined(WIN64)

+ 118 - 0
plugins/obs-qsv11/device_directx9.h

@@ -0,0 +1,118 @@
+/*********************************************************************************
+
+INTEL CORPORATION PROPRIETARY INFORMATION
+This software is supplied under the terms of a license agreement or nondisclosure
+agreement with Intel Corporation and may not be copied or disclosed except in
+accordance with the terms of that agreement
+Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved.
+
+**********************************************************************************/
+
+#pragma once
+
+#if defined( _WIN32 ) || defined ( _WIN64 )
+
+#include "common_utils.h"
+
+#pragma warning(disable : 4201)
+#include <initguid.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include <dxva.h>
+#include <windows.h>
+
+#define VIDEO_MAIN_FORMAT D3DFMT_YUY2
+
+class IGFXS3DControl;
+
+
+/// Base class for hw device
+class CHWDevice
+{
+public:
+    virtual ~CHWDevice(){}
+    /** Initializes device for requested processing.
+    @param[in] hWindow Window handle to bundle device to.
+    @param[in] nViews Number of views to process.
+    @param[in] nAdapterNum Number of adapter to use
+    */
+    virtual mfxStatus Init(
+        mfxHDL hWindow,
+        mfxU16 nViews,
+        mfxU32 nAdapterNum) = 0;
+    /// Reset device.
+    virtual mfxStatus Reset() = 0;
+    /// Get handle can be used for MFX session SetHandle calls
+    virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl) = 0;
+    /** Set handle.
+    Particular device implementation may require other objects to operate.
+    */
+    virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl) = 0;
+    virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc) = 0;
+    virtual void      Close() = 0;
+};
+
+enum {
+    MFX_HANDLE_GFXS3DCONTROL = 0x100, /* A handle to the IGFXS3DControl instance */
+    MFX_HANDLE_DEVICEWINDOW  = 0x101 /* A handle to the render window */
+}; //mfxHandleType
+
+/** Direct3D 9 device implementation.
+@note Can be initilized for only 1 or two 2 views. Handle to
+MFX_HANDLE_GFXS3DCONTROL must be set prior if initializing for 2 views.
+
+@note Device always set D3DPRESENT_PARAMETERS::Windowed to TRUE.
+*/
+class CD3D9Device : public CHWDevice
+{
+public:
+    CD3D9Device();
+    virtual ~CD3D9Device();
+
+    virtual mfxStatus Init(
+        mfxHDL hWindow,
+        mfxU16 nViews,
+        mfxU32 nAdapterNum);
+    virtual mfxStatus Reset();
+    virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl);
+    virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl);
+    virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc);
+    virtual void      UpdateTitle(double /*fps*/) { }
+    virtual void      Close() ;
+            void      DefineFormat(bool isA2rgb10) { m_bIsA2rgb10 = (isA2rgb10) ? TRUE : FALSE; }
+protected:
+    mfxStatus CreateVideoProcessors();
+    bool CheckOverlaySupport();
+    virtual mfxStatus FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS &D3DPP);
+private:
+    IDirect3D9Ex*               m_pD3D9;
+    IDirect3DDevice9Ex*         m_pD3DD9;
+    IDirect3DDeviceManager9*    m_pDeviceManager9;
+    D3DPRESENT_PARAMETERS       m_D3DPP;
+    UINT                        m_resetToken;
+
+    mfxU16                      m_nViews;
+    IGFXS3DControl*             m_pS3DControl;
+
+
+    D3DSURFACE_DESC                 m_backBufferDesc;
+
+    // service required to create video processors
+    IDirectXVideoProcessorService*  m_pDXVAVPS;
+    //left channel processor
+    IDirectXVideoProcessor*         m_pDXVAVP_Left;
+    // right channel processor
+    IDirectXVideoProcessor*         m_pDXVAVP_Right;
+
+    // target rectangle
+    RECT                            m_targetRect;
+
+    // various structures for DXVA2 calls
+    DXVA2_VideoDesc                 m_VideoDesc;
+    DXVA2_VideoProcessBltParams     m_BltParams;
+    DXVA2_VideoSample               m_Sample;
+
+    BOOL                            m_bIsA2rgb10;
+};
+
+#endif // #if defined( _WIN32 ) || defined ( _WIN64 )