Hello, I am rather new to DirectShow (or more specifically VMR-9). Right now I am using Renderless mode to grab the texture generated from my custom presenter-allocator, and store it later for my deferred renderer to use.
Currently, everything works perfectly for my machine (specs below), which is a Windows 7 machine. However, the target machine (Windows XP) for the game that I am making has issues. I hear the audio playing for the video just fine, but I am not getting a texture to use, so no video.
Here are the specs for the two machines:
My Machine:
Windows 7 Professional
Service Pack 1
Intel Core i5 CPU
M 520 @ 2.4 GHz
Graphics Card:
NVIDIA Quadro FX 2800M
3750 MB Approx. Total Memory
Version 8.17.12.7621
Target Machine:
Windows XP Professional 2002
Service Pack 2
Intel Core 2 Duo CPU
E8400 @ 3.0 GHz
Graphics Card:
NVIDIA GeForce 9800 GT
512.0 MB RAM
Version 6.14.0012.8026
Is there anything obvious that I'm missing, like does the VMR-9 simply not work on this machine, or some flag or extra call I need to make? Or is there something deeper?
To top it all off, I do not always have access to the machine (in fact I rarely do), so this makes testing difficult, and I need to make every test count.
I have my code listed below. Please help if you can.
VideoAllocator::VideoAllocator (void)
{
m_nRefCount = 0;
m_pConfig = NULL;
m_pNotify = NULL;
m_pDevice = NULL;
m_pSurfaces = NULL;
m_dwSurfaces = 0;
m_pTestMesh = NULL;
InitializeCriticalSection(&m_CriticalSection);
}
VideoAllocator::~VideoAllocator (void)
{
TerminateDevice(0);
m_nRefCount = 0;
m_pConfig = NULL;
m_pNotify = NULL;
m_pDevice = NULL;
m_pSurfaces = NULL;
m_dwSurfaces = 0;
if (m_pTestMesh)
{
m_pTestMesh->ReleaseTexture();
m_pTestMesh = NULL;
}
DeleteCriticalSection(&m_CriticalSection);
}
ULONG VideoAllocator::AddRef (void)
{
return InterlockedIncrement(&m_nRefCount);
}
HRESULT VideoAllocator::QueryInterface (REFIID riid, void** ppvObject)
{
if (ppvObject == NULL)
{
#ifndef _RELEASEBUILD
printf("The Allocator-Presenter's QueryInterface was passed an invalid pointer.\n");
#endif
return E_POINTER;
}
if (riid == IID_IVMRSurfaceAllocator9)
{
*ppvObject = static_cast<IVMRSurfaceAllocator9*>(this);
AddRef();
return S_OK;
}
if (riid == IID_IVMRImagePresenter9)
{
*ppvObject = static_cast<IVMRImagePresenter9*>(this);
AddRef();
return S_OK;
}
if (riid == IID_IUnknown)
{
*ppvObject = static_cast<IUnknown*>(static_cast<IVMRSurfaceAllocator9*>(this));
AddRef();
return S_OK;
}
#ifndef _RELEASEBUILD
if (riid != IID_IVMRImagePresenterConfig9 && riid != IID_IVMRSurfaceAllocatorEx9 &&
riid != IID_IVMRWindowlessControl9 && riid != IID_IVMRWindowlessControl9)
printf("The Allocator-Presenter's QueryInterface was passed an invalid ID.\n");
#endif
return E_NOINTERFACE;
}
ULONG VideoAllocator::Release (void)
{
ULONG uCount = InterlockedDecrement(&m_nRefCount);
if (uCount <= 0)
{
delete this;
}
return uCount;
}
HRESULT VideoAllocator::AdviseNotify (IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify)
{
EnterCriticalSection(&m_CriticalSection);
if (lpIVMRSurfAllocNotify == NULL)
{
LeaveCriticalSection(&m_CriticalSection);
return E_POINTER;
}
m_pNotify = lpIVMRSurfAllocNotify;
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
HRESULT VideoAllocator::GetSurface (DWORD_PTR dwUserID, DWORD SurfaceIndex,
DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface)
{
EnterCriticalSection(&m_CriticalSection);
if (lplpSurface == NULL)
{
#ifndef _RELEASEBUILD
printf("Invalid surface pointer in GetSurface().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_POINTER;
}
if (SurfaceIndex >= m_dwSurfaces)
{
#ifndef _RELEASEBUILD
printf("Invalid surface index in GetSurface().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_INVALIDARG;
}
*lplpSurface = m_pSurfaces[SurfaceIndex];
(*lplpSurface)->AddRef();
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
HRESULT VideoAllocator::InitializeDevice (DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers)
{
EnterCriticalSection(&m_CriticalSection);
if (lpAllocInfo == NULL)
{
#ifndef _RELEASEBUILD
printf("Invalid Allocation pointer in InitializeDevice().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_POINTER;
}
if (lpNumBuffers == NULL)
{
#ifndef _RELEASEBUILD
printf("Invalid Number of Buffers pointer in InitializeDevice().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_POINTER;
}
lpAllocInfo->dwFlags = VMR9AllocFlag_TextureSurface;
lpAllocInfo->Format = D3DFMT_X8R8G8B8;
ReleaseSurfaces();
m_pSurfaces = new IDirect3DSurface9* [*lpNumBuffers];
if (m_pSurfaces == NULL)
{
LeaveCriticalSection(&m_CriticalSection);
return E_OUTOFMEMORY;
}
HRESULT hr = m_pNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers,
m_pSurfaces);
m_dwSurfaces = *lpNumBuffers;
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Failed to Allocate the Surfaces in InitializeDevice().\n");
#endif
ReleaseSurfaces();
*lpNumBuffers = 0;
}
LeaveCriticalSection(&m_CriticalSection);
return hr;
}
HRESULT VideoAllocator::TerminateDevice (DWORD_PTR dwID)
{
EnterCriticalSection(&m_CriticalSection);
ReleaseSurfaces();
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
HRESULT VideoAllocator::PresentImage (DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo)
{
EnterCriticalSection(&m_CriticalSection);
if (m_pNotify == NULL)
{
#ifndef _RELEASEBUILD
printf("m_pNotify has not been created before PresentImage() was called.\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_FAIL;
}
if (lpPresInfo == NULL)
{
#ifndef _RELEASEBUILD
printf("No presentation info was passed into PresentImage().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_FAIL;
}
if (lpPresInfo->lpSurf == NULL)
{
#ifndef _RELEASEBUILD
printf("No surface was passed into PresentImage().\n");
#endif
LeaveCriticalSection(&m_CriticalSection);
return E_FAIL;
}
IDirect3DTexture9* texture;
lpPresInfo->lpSurf->GetContainer(IID_IDirect3DTexture9,
(void**)&texture);
if (texture && m_pTestMesh)
{
m_pTestMesh->SetTexture(texture);
}
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
HRESULT VideoAllocator::StartPresenting (DWORD_PTR dwUserID)
{
return S_OK;
}
HRESULT VideoAllocator::StopPresenting (DWORD_PTR dwUserID)
{
return S_OK;
}
void VideoAllocator::ReleaseSurfaces (void)
{
for (DWORD i = 0; i < m_dwSurfaces; ++i)
{
if (m_pSurfaces[i])
{
m_pSurfaces[i]->Release();
m_pSurfaces[i] = NULL;
}
}
if (m_pSurfaces)
{
delete m_pSurfaces;
m_pSurfaces = NULL;
}
m_dwSurfaces = 0;
m_pTestMesh = NULL;
}
VideoManager::VideoManager (void)
{
m_pGraph = NULL;
m_pControl = NULL;
m_pEvent = NULL;
m_pVMR9 = NULL;
m_pDSound = NULL;
m_pNotify = NULL;
m_pAllocator = NULL;
}
VideoManager::~VideoManager (void)
{
}
void VideoManager::Initialize (HWND hWnd, IDirect3DDevice9* device)
{
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not initialize the COM Library.\n");
#endif
return;
}
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&m_pGraph);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the Filter Graph Manager.\n");
#endif
return;
}
hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pControl);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the Media Control Interface.\n");
#endif
return;
}
hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (void**)&m_pEvent);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the Media Event Interface.\n");
#endif
return;
}
m_pEvent->SetNotifyWindow((OAHWND)hWnd, WM_GRAPH_EVENT, 0);
hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pVMR9));
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the VMR-9 Filter.\n");
#endif
return;
}
hr = m_pGraph->AddFilter(m_pVMR9, L"VMR9");
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not add the VMR-9 Filter to the graph.\n");
#endif
return;
}
IVMRFilterConfig9* pConfig = NULL;
m_pVMR9->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
hr = pConfig->SetRenderingMode(VMR9Mode_Renderless);
hr = pConfig->SetNumberOfStreams(1);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not properly configure the VMR-9 Filter.\n");
#endif
return;
}
pConfig->Release();
hr = m_pVMR9->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,
(void**)&m_pNotify);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the Surface Allocator Notify.\n");
#endif
return;
}
hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pDSound));
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not create the DirectSound Filter.\n");
#endif
return;
}
hr = m_pGraph->AddFilter(m_pDSound, L"DirectSound");
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not add the DirectSound Filter to the graph.\n");
#endif
return;
}
IBaseFilter* pSource = NULL;
hr = m_pGraph->AddSourceFilter(L"Resource/Videos/My Little Pony Friendship is Magic Opening.mp4",
L"Source1", &pSource);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not add the source filter to the graph.\n");
#endif
return;
}
IDirect3D9* pD3D = NULL;
device->GetDirect3D(&pD3D);
HMONITOR hMonitor = pD3D->GetAdapterMonitor(D3DADAPTER_DEFAULT);
hr = m_pNotify->SetD3DDevice(device, hMonitor);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Failed to hook up the VMR to the D3D Device.\n");
#endif
return;
}
m_pAllocator = new VideoAllocator();
m_pAllocator->AddRef();
m_pAllocator->SetD3DDevice(device);
hr = m_pNotify->AdviseSurfaceAllocator(0, m_pAllocator);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Failed to connect the Allocator to the Notify.\n");
#endif
return;
}
hr = m_pAllocator->AdviseNotify(m_pNotify);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Failed to connect the Notify to the Allocator.\n");
#endif
return;
}
IVMRMixerControl9* pMix = NULL;
hr = m_pVMR9->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix);
if (SUCCEEDED(hr))
{
DWORD dwPrefs = 0;
hr = pMix->GetMixingPrefs(&dwPrefs);
if (SUCCEEDED(hr))
{
dwPrefs &= ~MixerPref9_RenderTargetMask;
dwPrefs |= MixerPref9_RenderTargetYUV;
hr = pMix->SetMixingPrefs(dwPrefs);
}
pMix->Release();
}
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Could not prevent the VMR-9 from not changing Targets.\n");
#endif
return;
}
PinList pins;
hr = GetPinList(pSource, PINDIR_OUTPUT, pins);
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Error retrieving the source filter's pins.\n");
#endif
return;
}
IFilterGraph2* pGraph2 = NULL;
m_pGraph->QueryInterface(IID_IFilterGraph2, (void**)&pGraph2);
hr = E_FAIL;
for (PinIter iter (pins); !iter.end(); ++iter)
{
HRESULT hr2 = pGraph2->RenderEx(iter.current(),
AM_RENDEREX_RENDERTOEXISTINGRENDERERS, 0);
if (hr == E_FAIL && SUCCEEDED(hr2))
hr = S_OK;
}
if (FAILED(hr))
{
#ifndef _RELEASEBUILD
printf("Failed to render one of the source filter's pins.\n");
#endif
return;
}
pGraph2->Release();
pSource->Release();
}
void VideoManager::Test (void)
{
if (FAILED(m_pControl->Run()))
{
#ifndef _RELEASEBUILD
printf("Could not Run the Media Control.\n");
#endif
}
long evCode = 0;
m_pEvent->WaitForCompletion(0, &evCode);
}
void VideoManager::Exit (void)
{
if (m_pAllocator)
{
m_pAllocator->ReleaseSurfaces();
delete m_pAllocator;
m_pAllocator = NULL;
}
if (m_pGraph)
{
m_pGraph->Release();
m_pGraph = NULL;
}
CoUninitialize();
}
void VideoManager::ClearVideos (void)
{
EnterCriticalSection(&m_pAllocator->m_CriticalSection);
m_pAllocator->m_pTestMesh = NULL;
LeaveCriticalSection(&m_pAllocator->m_CriticalSection);
}
void VideoManager::HandleWindowsMsg (void)
{
long EventCode, param1, param2;
while (SUCCEEDED(m_pEvent->GetEvent(&EventCode, ¶m1, ¶m2, 0)))
{
switch (EventCode)
{
case EC_COMPLETE:
break;
};
}
m_pEvent->FreeEventParams(EventCode, param1, param2);
}
HRESULT VideoManager::GetPinList (IBaseFilter* pFilter, PIN_DIRECTION pinDir, PinList& pins)
{
if (pFilter == NULL)
return E_POINTER;
CComPtr<IEnumPins> pEnum;
HRESULT hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
return hr;
while (hr == S_OK)
{
CComPtr<IPin> pPin;
hr = pEnum->Next(1, &pPin, NULL);
if (hr != S_OK)
break;
PIN_DIRECTION curDir;
hr = pPin->QueryDirection(&curDir);
if (FAILED(hr))
return hr;
if (curDir == pinDir)
pins.addTail(pPin);
}
return S_OK;
}