Hello ! I'm trying to code a program which displays a 4k Video using Direct3D9 but without EVR....
For now, the video is displaying well but at some time during the rendering, the execution stops and blocks at "m_pD3D9Device->Present(...)"
I've tried a lot of things to solve the problem but none of these worked...
Could you please help me?
Here are the important lines of the code:
HEADER :
// -------------- Attributes --------------
wchar_t* m_MEDIA_FILE_PATH;
IMFSourceReader* m_pReader;
IMFMediaType* m_pVideoSourceMediaType, * m_pReadMediaType;
UINT32 m_VideoWidth, m_VideoHeight;
IDirect3DDevice9* m_pD3D9Device;
IDirect3DDeviceManager9* m_pDeviceManager;
IDirect3DSwapChain9* m_pSwapChain;
IDirect3DSurface9* m_pBackBuffer;
HANDLE m_hDevice;
UINT m_token;
CPP :
/* Main method.
* Returns S_OK if successful or an error code if not
*/
HRESULT D3D9Player::LaunchPlayer()
{
CHECK_HR(Initialize(), "Failed to initialize system.\n");
InitializeDirect3D();
//CHECK_HR(InitializeVideoProcessorContext(), "Failed to initialize video processor context.\n");
CHECK_HR(StartSampleLoop(), "Failed to process main loop.\n");
return S_OK;
}
/* Initialize MediaFoundation.
* Returns S_OK if successful or an error code if not
*/
HRESULT D3D9Player::Initialize()
{
CHECK_HR(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE), "COM initialisation failed.\n");
CHECK_HR(MFStartup(MF_VERSION), "Media Foundation initialisation failed.\n");
// Create a separate Window and thread to host the Video player.
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&D3D9PlayerServerThread, this, 0, NULL);
Sleep(1000);
return S_OK;
}
// Start the server thread
DWORD D3D9Player::D3D9PlayerServerThread(D3D9Player* mediaPlayer)
{
return mediaPlayer->InitializeWindow();
}
/*
* Initialize the Window where the video will be displayed.
* The window can also be found instead of being created (see FindWindowEx).
* Returns S_OK if successful or an error code if not
*/
DWORD D3D9Player::InitializeWindow() {
WNDCLASS wc = { 0 };
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = CLASS_NAME;
if (RegisterClass(&wc))
{
g_hwnd = CreateWindow(
CLASS_NAME,
WINDOW_NAME,
WS_EX_TOPMOST | WS_POPUP,
1920,
0,
1920,
1080,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
if (g_hwnd)
{
ShowWindow(g_hwnd, SW_SHOWDEFAULT);
MSG msg = { 0 };
while (true)
{
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
return 0;
}
HRESULT D3D9Player::InitializeDirect3D()
{
IMFAttributes* pSourceReaderAttributes = NULL;
CHECK_HR(MFCreateAttributes(&pSourceReaderAttributes, 2), "Failed to create attributes.\n");
CHECK_HR(DXVA2CreateDirect3DDeviceManager9(&m_token, &m_pDeviceManager), "Failed to create device Manager.\n");
CHECK_HR(pSourceReaderAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, m_pDeviceManager), "Failed to set SOURCE_READER_D3D_MANAGER attribute.\n");
CHECK_HR(pSourceReaderAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE), "Failed to set SOURCE_READER_D3D_MANAGER attribute.\n");
CHECK_HR(SetUpVideoSource(pSourceReaderAttributes), "Failed to set up Video Source.\n");
CHECK_HR(InitializeD3D9Device(), "Failed to initialize D3D9Device.\n");
CHECK_HR(m_pDeviceManager->ResetDevice(m_pD3D9Device, m_token), "Failed to set the device on the manager.\n");
CHECK_HR(MFCreateVideoSampleAllocator(IID_IMFVideoSampleAllocator, (void**)&m_pSampleAllocator), "Failed to create video sample allocator.\n");
CHECK_HR(m_pSampleAllocator->SetDirectXManager(m_pDeviceManager), "Failed to set Direct Manager on Video sample allocator.\n");
CHECK_HR(m_pSampleAllocator->InitializeSampleAllocator(1, m_pReadMediaType), "Failed to initialize sample allocator.\n");
CHECK_HR(m_pSampleAllocator->AllocateSample(&m_pD3DVideoSample), "Failed to allocate video sample.\n");
CHECK_HR(GetD3DSurfaceFromSample(), "Failed to get D3DSurface from sample.\n");
CHECK_HR(m_pDeviceManager->OpenDeviceHandle(&m_hDevice), "Failed to get the Handle Device from the pD3DManager.\n");
CHECK_HR(m_pD3DVideoSample->GetBufferByIndex(0, &m_pDstBuffer), "Failed to get destination buffer.\n");
CHECK_HR(m_pDstBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer)), "Failed to get pointer to 2D buffer.\n");
SAFE_RELEASE(pSourceReaderAttributes);
return S_OK;
}
HRESULT D3D9Player::InitializeD3D9Device() {
IDirect3D9* pD3D9Object = NULL;
D3DPRESENT_PARAMETERS presentDesc = { 0 };
presentDesc.BackBufferWidth = m_VideoWidth;
presentDesc.BackBufferHeight = m_VideoHeight;
presentDesc.BackBufferFormat = D3DFMT_X8R8G8B8;
presentDesc.BackBufferCount = 1;
presentDesc.MultiSampleType = D3DMULTISAMPLE_NONE;
presentDesc.MultiSampleQuality = 0;
presentDesc.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentDesc.hDeviceWindow = g_hwnd;
presentDesc.Windowed = TRUE;
presentDesc.EnableAutoDepthStencil = FALSE;
presentDesc.Flags = 0;
pD3D9Object = Direct3DCreate9(D3D_SDK_VERSION);
CHECK_HR(pD3D9Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presentDesc, &m_pD3D9Device), "Failed to create Direct 3D Device.\n");
return S_OK;
}
HRESULT D3D9Player::SetUpVideoSource(IMFAttributes* attributes)
{
CHECK_HR(MFCreateSourceReaderFromURL(m_MEDIA_FILE_PATH, attributes, &m_pReader), "Failed to create Source Reader from file.\n");
CHECK_HR(m_pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &m_pVideoSourceMediaType), "Error retrieving current media type from first video stream.\n");
//DSP input MediaType
CHECK_HR(MFCreateMediaType(&m_pReadMediaType), "Failed to create read media type.\n");
CHECK_HR(m_pVideoSourceMediaType->CopyAllItems(m_pReadMediaType), "Fail to copy all attributes from videoSourceOutpuType to pVideoSourceOutType\n");
CHECK_HR(m_pReadMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), "Failed to get source media type count.\n"); // TODO the subtype can be changed, see compatibilities with the current codec
CHECK_HR(m_pReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE), "Failed to set the first video stream on the source reader.\n");
CHECK_HR(m_pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, m_pReadMediaType), "Failed to set output media type on source reader.\n");
std::cout << "Input media type defined as:" << std::endl << GetMediaTypeDescription(m_pReadMediaType) << std::endl << std::endl;
MFGetAttributeSize(m_pReadMediaType, MF_MT_FRAME_SIZE, &m_VideoWidth, &m_VideoHeight);
return S_OK;
}
/*
* Retrieve the D3DSurface9 from the given IMFSample.
* Return S_OK on success, or an error value otherwise.
*/
HRESULT D3D9Player::GetD3DSurfaceFromSample()
{
IMFMediaBuffer* pBuffer = NULL;
CHECK_HR(m_pD3DVideoSample->GetBufferByIndex(0, &pBuffer), "Failed to get buffer by Index.\n");
CHECK_HR(MFGetService(pBuffer, MR_BUFFER_SERVICE, IID_PPV_ARGS(&m_pSurface)), "Failed to get 3DSurface via MR_BUFFER_SERVICE.\n");
pBuffer->Release();
return S_OK;
}
HRESULT D3D9Player::StartSampleLoop() {
DWORD previousT = timeGetTime(), currentT = -1;
IMFSample* sample = NULL;
FLOAT sum = 0.;
DWORD count = 0;
FLOAT originalStartTime = timeGetTime(), totalDuration = -1.;
DWORD flags;
HRESULT hrRes = S_OK;
IMFMediaBuffer* pBuffer = NULL;
BYTE* pbBuffer = NULL;
DWORD dwBuffer = 0;
CHECK_HR(m_pD3D9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer), "Failed to get BackBuffer from the device.\n");
hrRes=m_pD3D9Device->SetRenderTarget(0, m_pBackBuffer);
std::cout << "Started processing frames" << std::endl;
while (true)
{
DWORD loopStartTime = timeGetTime();
// Statistics
count++;
currentT = timeGetTime();
sum += (currentT - previousT);
std::cout << "FRAME NUMBER " << count << " DURATION:" << currentT - previousT << std::endl << std::endl;
previousT = currentT;
CHECK_HR(m_pReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, nullptr, &flags, NULL, &sample), "Failed to process readSample.\n");
if (flags & MF_SOURCE_READERF_ENDOFSTREAM || sample == nullptr) {
totalDuration = timeGetTime() - originalStartTime;
PROPVARIANT var = { 0 };
var.vt = VT_I8;
CHECK_HR(m_pReader->SetCurrentPosition(GUID_NULL, var), "Failed to set current position on source reader.\n");
std::cout << "End of stream.\nAverage time to display one Frame: " << sum / count << "s\nTotal Render Time : " << totalDuration * 0.001 << "s" << std::endl;
//return S_OK;
}
if (!sample)
{
std::cout << "Null video sample." << std::endl;
}
else
{
CHECK_HR(sample->ConvertToContiguousBuffer(&pBuffer), "Failed to get buffer from video sample.\n");
CHECK_HR(pBuffer->Lock(&pbBuffer, NULL, &dwBuffer), "Failed to lock sample buffer.\n");
{
CHECK_HR(m_p2DBuffer->ContiguousCopyFrom(pbBuffer, dwBuffer), "Failed to copy data to p2DBuffer from pbBuffer.\n");
}
CHECK_HR(pBuffer->Unlock(), "Failed to unlock source buffer.\n");
CHECK_HR(m_pDeviceManager->LockDevice(m_hDevice, &m_pD3D9Device, TRUE), "Failed to lock the device.\n");
{
CHECK_HR(m_pD3D9Device->BeginScene(), "Failed to begin the scene.\n");
CHECK_HR(m_pD3D9Device->StretchRect(m_pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE), "Failed to do the StretchRect.\n");
CHECK_HR(m_pD3D9Device->EndScene(), "Failed to begin the scene.\n");
CHECK_HR(m_pD3D9Device->Present(NULL, NULL, g_hwnd, NULL), "Failed to present the scene.\n");
Sleep(10);
}
CHECK_HR(m_pDeviceManager->UnlockDevice(m_hDevice, TRUE), "Failed to unlock th device.\n");
}
SAFE_RELEASE(sample);
SAFE_RELEASE(pBuffer);
}
std::cout << "Finished processing frames" << std::endl;
return S_OK;
}