From b276b1633e7c37deec4e8a56dec65e4eb36bfc1e Mon Sep 17 00:00:00 2001 From: Alexandre Biny Date: Tue, 14 Jun 2016 13:44:34 +0200 Subject: [PATCH] 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. --- plugins/obs-qsv11/CMakeLists.txt | 6 + plugins/obs-qsv11/QSV_Encoder_Internal.cpp | 39 +- plugins/obs-qsv11/QSV_Encoder_Internal.h | 1 + plugins/obs-qsv11/common_directx9.cpp | 457 +++++++++++++++++++++ plugins/obs-qsv11/common_directx9.h | 70 ++++ plugins/obs-qsv11/common_utils.h | 2 +- plugins/obs-qsv11/common_utils_windows.cpp | 48 ++- plugins/obs-qsv11/device_directx9.cpp | 451 ++++++++++++++++++++ plugins/obs-qsv11/device_directx9.h | 118 ++++++ 9 files changed, 1170 insertions(+), 22 deletions(-) create mode 100644 plugins/obs-qsv11/common_directx9.cpp create mode 100644 plugins/obs-qsv11/common_directx9.h create mode 100644 plugins/obs-qsv11/device_directx9.cpp create mode 100644 plugins/obs-qsv11/device_directx9.h diff --git a/plugins/obs-qsv11/CMakeLists.txt b/plugins/obs-qsv11/CMakeLists.txt index 611c7aa47..71ce3fb82 100644 --- a/plugins/obs-qsv11/CMakeLists.txt +++ b/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 ) diff --git a/plugins/obs-qsv11/QSV_Encoder_Internal.cpp b/plugins/obs-qsv11/QSV_Encoder_Internal.cpp index c73838b6e..49f2a01dd 100644 --- a/plugins/obs-qsv11/QSV_Encoder_Internal.cpp +++ b/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(); diff --git a/plugins/obs-qsv11/QSV_Encoder_Internal.h b/plugins/obs-qsv11/QSV_Encoder_Internal.h index b2648a1a9..def736f28 100644 --- a/plugins/obs-qsv11/QSV_Encoder_Internal.h +++ b/plugins/obs-qsv11/QSV_Encoder_Internal.h @@ -108,5 +108,6 @@ private: mfxBitstream m_outBitstream; bool m_bIsWindows8OrGreater; bool m_bUseD3D11; + bool m_bD3D9HACK; }; diff --git a/plugins/obs-qsv11/common_directx9.cpp b/plugins/obs-qsv11/common_directx9.cpp new file mode 100644 index 000000000..8483e3909 --- /dev/null +++ b/plugins/obs-qsv11/common_directx9.cpp @@ -0,0 +1,457 @@ +#include "common_directx9.h" +#include "device_directx9.h" + +#include +#include +#include +#include +#include + + +#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 dx9_allocResponses; +std::map dx9_allocDecodeResponses; +std::map dx9_allocDecodeRefCount; + +CComPtr m_manager; +CComPtr m_decoderService; +CComPtr 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(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(*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(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(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(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 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; +} diff --git a/plugins/obs-qsv11/common_directx9.h b/plugins/obs-qsv11/common_directx9.h new file mode 100644 index 000000000..0817cc86e --- /dev/null +++ b/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 +#include +#include +#include +#include + +#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 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(); diff --git a/plugins/obs-qsv11/common_utils.h b/plugins/obs-qsv11/common_utils.h index 4cb5c5751..b2adf79d4 100644 --- a/plugins/obs-qsv11/common_utils.h +++ b/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(); diff --git a/plugins/obs-qsv11/common_utils_windows.cpp b/plugins/obs-qsv11/common_utils_windows.cpp index 2bb9f869e..29c6b987f 100644 --- a/plugins/obs-qsv11/common_utils_windows.cpp +++ b/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 } diff --git a/plugins/obs-qsv11/device_directx9.cpp b/plugins/obs-qsv11/device_directx9.cpp new file mode 100644 index 000000000..1fb201906 --- /dev/null +++ b/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 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) \ No newline at end of file diff --git a/plugins/obs-qsv11/device_directx9.h b/plugins/obs-qsv11/device_directx9.h new file mode 100644 index 000000000..fff1c3806 --- /dev/null +++ b/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 +#include +#include +#include +#include + +#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 ) \ No newline at end of file