Skip to main content
GameDev.net gamedev.net
🔒 Locked

VMR9 Renderless Mode Help!

Started by jesse121 Apr 8, 2007 at 1:42 AM 5 replies 7.6k views
Original Post
jesse121
jesse121
Hello everyone. I am trying to implement the VMR9 in nightmare mode, I mean Renderless mode. I managed to get my code to the point where everything is created without fail, but I still can't get anything rendering. For some reason the IVMRImagePresenter9::PresentImage callback function is never called. When I make the call to m_pGraph->RenderFile(), the only callbacks that are called by the application are InitializeDevice(), GetSurface(), and TerminateDevice(). When I call IVMRFilterConfig9::SetNumberOfStreams() with a zero the following calls are made: InitializeDevice() GetSurface() TerminateDevice() InitializeDevice() GetSurface() TerminateDevice() InitializeDevice() GetSurface() TerminateDevice() and then the video is rendered in a pop up window not in my main window. When I call IVMRFilterConfig9::SetNumberOfStreams() with a one the following calls are made: TerminateDevice() TerminateDevice() TerminateDevice() InitializeDevice() GetSurface() and then nothing happens at all, just a blank screen, no audio. Is there a specific reason why IVMRImagePresenter9::PresentImage never gets called? When I call IMediaControl::Run() shouldn't the IVMRImagePresenter9::PresentImage function be called? I am trying to play a movie that has both video and sound should I SetNumberOfStreams() to 0, 1, or 2? I setup the VMR9AllocationInfo with the following flags: D3DDISPLAYMODE dm; m_pd3dDevice->GetDisplayMode( 0, &dm ); pAllocInfo->dwFlags = VMR9AllocFlag_3DRenderTarget; pAllocInfo->Format = dm.Format; pAllocInfo->Pool = D3DPOOL_DEFAULT; Should I be using a different flag such as VMR9AllocFlag_OffscreenSurface or VMR9AllocFlag_TextureSurface? I am sorry if this post is kind of confusing but VMR9 is confusing, there is just to many things that I could be doing wrong so, I don't really know where to look to solve this problem. By the way I have read all the posts on msdn, and tutorials I found on the internet referring to VMR9 Renderless mode.
Muhammad Haggag
Muhammad Haggag
Any chance you could upload your source somewhere? I'm familiar with DirectShow, even though I've not written anything using the VMR9 renderless mode before, so perhaps I can come up with something by tinkering with it a bit.

Oh, and kudos for trying out the renderless mode. You're one brave man indeed [grin] (The closest I got to that mode is skimming the docs, then deciding I didn't want to waste my life just yet)

jesse121
jesse121
VMR9Allocator.h
	// Class VMR9Allocator inherits from IVMRSurfaceAllocator9 and IVMRImagePresenter9	class CVMR9Allocator : public IVMRSurfaceAllocator9, private IVMRImagePresenter9	{		public:			CVMR9Allocator();			~CVMR9Allocator();			// VMR9 mutators			HRESULT STDMETHODCALLTYPE InitializeDevice( DWORD_PTR dwUserID, VMR9AllocationInfo* pAllocInfo, DWORD* pNumBuffers );			HRESULT STDMETHODCALLTYPE TerminateDevice( DWORD_PTR dwID );			HRESULT STDMETHODCALLTYPE GetSurface( DWORD_PTR dwUserID, DWORD dwSurfaceIndex, DWORD dwSurfaceFlags, IDirect3DSurface9** lplpSurface );			HRESULT STDMETHODCALLTYPE AdviseNotify( IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify );			HRESULT STDMETHODCALLTYPE StartPresenting( DWORD_PTR dwUserID );			HRESULT STDMETHODCALLTYPE StopPresenting( DWORD_PTR dwUserID );			HRESULT STDMETHODCALLTYPE PresentImage( DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo );			HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppvObject );			ULONG   STDMETHODCALLTYPE AddRef();			ULONG   STDMETHODCALLTYPE Release();			// User mutators			void SetDevice( HWND hWnd, IDirect3DDevice9* pd3dDevice );			void SetVideoWindow( float x, float y, float fWidth, float fHeight );			// Engine accessors			DWORD GetMovieWidth() const;			DWORD GetMovieHeight() const;		protected:			// Support member functions			void	DeleteSurfaces();			HRESULT PresentHelper( VMR9PresentationInfo *lpPresInfo );		private:			ULONG						 m_lRefCount;			DWORD						 m_dwSurfaceNum;			DWORD						 m_dwMovieWidth;			DWORD						 m_dwMovieHeight;			LPDIRECT3DTEXTURE9			 m_pTexture;			CPolygon<CTDVertex>*		 m_pVideoWindow;			IVMRSurfaceAllocatorNotify9* m_pIVMRSurfAllocNotify;			vector<IDirect3DSurface9*>	 m_vpSurfaces;			HWND						 m_hWnd;			IDirect3DDevice9*			 m_pd3dDeviceInst;	};


VMR9Allocator.cpp
// CVMR9Allocator constructorCVMR9Allocator::CVMR9Allocator():	m_lRefCount(0),	m_dwSurfaceNum(0),	m_dwMovieWidth(0),	m_dwMovieHeight(0),	m_pTexture(NULL),	m_pVideoWindow(NULL),	m_pIVMRSurfAllocNotify(NULL),	m_hWnd(0),	m_pd3dDeviceInst(NULL){}// CVMR9Allocator destructorCVMR9Allocator::~CVMR9Allocator(){	SafeRelease( m_pTexture );	SafeDelete( m_pVideoWindow );	DeleteSurfaces();}// InitializeDevice callback handlerHRESULT STDMETHODCALLTYPE CVMR9Allocator::InitializeDevice( DWORD_PTR dwUserID, VMR9AllocationInfo* pAllocInfo, DWORD* pNumBuffers ){    if( !pNumBuffers )			  return E_POINTER;    if( !m_pIVMRSurfAllocNotify ) return E_FAIL;	if( !m_pd3dDeviceInst )		  return E_FAIL;	// Adjust the surface size to powers of two	m_dwMovieWidth  = pAllocInfo->dwWidth;	m_dwMovieHeight = pAllocInfo->dwHeight;	DWORD dwWidth(1), dwHeight(1);	while( dwWidth < pAllocInfo->dwWidth  )  dwWidth  <<= 1;	while( dwHeight < pAllocInfo->dwHeight ) dwHeight <<= 1;	pAllocInfo->dwWidth  = dwWidth;	pAllocInfo->dwHeight = dwHeight;	// Setup the allocator to render to a back buffer	D3DDISPLAYMODE dm; m_pd3dDeviceInst->GetDisplayMode( 0, &dm );	pAllocInfo->dwFlags = VMR9AllocFlag_3DRenderTarget;	pAllocInfo->Format  = dm.Format;	pAllocInfo->Pool    = D3DPOOL_DEFAULT;	// Resize the array of surfaces	DeleteSurfaces();	m_dwSurfaceNum = *pNumBuffers;	m_vpSurfaces.resize( m_dwSurfaceNum );	// Allocate the array of surfaces	if( FAILED( m_pIVMRSurfAllocNotify->AllocateSurfaceHelper( pAllocInfo, &m_dwSurfaceNum, &m_vpSurfaces[0] ) ) )		return E_FAIL;	// Create the texture as a render target	if( FAILED( m_pd3dDeviceInst->CreateTexture( pAllocInfo->dwWidth, pAllocInfo->dwHeight, 1, D3DUSAGE_RENDERTARGET, dm.Format, D3DPOOL_DEFAULT, &m_pTexture, NULL ) ) )		return E_FAIL;	// Create a textured diffused polygon to map the texture to	m_pVideoWindow = new CPolygon<CTDVertex>;	if( m_pVideoWindow->CreatePolygon( m_pd3dDeviceInst, 2, 6, 4, 0, D3DPOOL_MANAGED, D3DPT_TRIANGLELIST ) )	{	// Scale the Quad to the texture size by default		D3DXVECTOR2 vPolySize((float)m_dwMovieWidth, (float)m_dwMovieHeight);		D3DXVECTOR2 vPolyPos(0.0f, 0.0f);		// Create four vertice's for the quad		vector<CTDVertex> vVertices( 4 );		vVertices[0].SetData( vPolyPos.x,				vPolyPos.y - vPolySize.y, 0.0f, 0xffffffff, 0.0f, 0.0f );	// Top left		vVertices[1].SetData( vPolyPos.x + vPolySize.x, vPolyPos.y - vPolySize.y, 0.0f, 0xffffffff, 1.0f, 0.0f );	// Top right		vVertices[2].SetData( vPolyPos.x + vPolySize.x, vPolyPos.y,				  0.0f, 0xffffffff, 1.0f, 1.0f );	// Bottom right		vVertices[3].SetData( vPolyPos.x,				vPolyPos.y,				  0.0f, 0xffffffff, 0.0f, 1.0f );	// Bottom left		m_pVideoWindow->SetVertices( vVertices );		// Create the indice's		vector<WORD> vIndices( 6 );		vIndices[0] = 0; vIndices[1] = 1; vIndices[2] = 2;	// Triangle one		vIndices[3] = 3; vIndices[4] = 0; vIndices[5] = 2;	// Triangle two		m_pVideoWindow->SetIndices( vIndices );	}	else return E_FAIL;	MessageBox( NULL, "Success", "InitializeDevice", MB_OK );	return S_OK;}// TerminateDevice callback handlerHRESULT STDMETHODCALLTYPE CVMR9Allocator::TerminateDevice( DWORD_PTR dwID ){	SafeRelease( m_pTexture );	SafeDelete( m_pVideoWindow );    DeleteSurfaces();	MessageBox( NULL, "Success", "TerminateDevice", MB_OK );    return S_OK;}// GetSurface callback handlerHRESULT STDMETHODCALLTYPE CVMR9Allocator::GetSurface( DWORD_PTR dwUserID, DWORD dwSurfaceIndex, DWORD dwSurfaceFlags, IDirect3DSurface9** ppSurface ){	if( !ppSurface )					   return E_POINTER;    if( dwSurfaceIndex >= m_dwSurfaceNum ) return E_FAIL;	if( !m_vpSurfaces[dwSurfaceIndex] )	   return E_FAIL;	// Create a reference to the surface	*ppSurface = m_vpSurfaces[dwSurfaceIndex];	m_vpSurfaces[dwSurfaceIndex]->AddRef();	MessageBox( NULL, "Success", "GetSurface", MB_OK );	return S_OK;}// AdviseNotify callback handlerHRESULT STDMETHODCALLTYPE CVMR9Allocator::AdviseNotify( IVMRSurfaceAllocatorNotify9* pIVMRSurfAllocNotify ){	if( !m_pd3dDeviceInst ) return E_FAIL;	// Set the device	m_pIVMRSurfAllocNotify = pIVMRSurfAllocNotify;	if( FAILED( m_pIVMRSurfAllocNotify->SetD3DDevice( m_pd3dDeviceInst, MonitorFromWindow( m_hWnd, MONITOR_DEFAULTTOPRIMARY ) ) ) )		return E_FAIL;    return S_OK;}// Start presentingHRESULT STDMETHODCALLTYPE CVMR9Allocator::StartPresenting( DWORD_PTR dwUserID ){    return S_OK;}// Stop presentingHRESULT STDMETHODCALLTYPE CVMR9Allocator::StopPresenting( DWORD_PTR dwUserID ){    return S_OK;}// Present the imageHRESULT STDMETHODCALLTYPE CVMR9Allocator::PresentImage( DWORD_PTR dwUserID, VMR9PresentationInfo* pPresInfo ){	MessageBox( NULL, "", "PresentImage", MB_OK );	return PresentHelper( pPresInfo );}// Present helperHRESULT CVMR9Allocator::PresentHelper( VMR9PresentationInfo *pPresInfo ){	if( !pPresInfo )		 return E_POINTER;	if( !pPresInfo->lpSurf ) return E_POINTER;	if( !m_pd3dDeviceInst )	 return E_FAIL;	if( !m_pTexture )		 return E_FAIL;	if( !m_pVideoWindow )	 return E_FAIL;	// Blit the surface onto the texture	IDirect3DSurface9* pSurface(NULL);	if( SUCCEEDED( m_pTexture->GetSurfaceLevel( 0, &pSurface ) ) )	{	m_pd3dDeviceInst->StretchRect( pPresInfo->lpSurf, NULL, pSurface, NULL, D3DTEXF_NONE );		SafeRelease( pSurface );		m_pd3dDeviceInst->Clear( 0, 0, D3DCLEAR_TARGET, 0xff000000, 1.0f, 0 );		if( SUCCEEDED( m_pd3dDeviceInst->BeginScene() ) )		{	// Render the texture onto the quad			m_pd3dDeviceInst->SetTexture( 0, m_pTexture );			m_pVideoWindow->OnRender( m_pd3dDeviceInst );						m_pd3dDeviceInst->EndScene();			m_pd3dDeviceInst->Present( 0, 0, 0, 0 );		}	}	MessageBox( NULL, "Success", "PresentHelper", MB_OK );	return S_OK;}// Query the interfaceHRESULT STDMETHODCALLTYPE CVMR9Allocator::QueryInterface( REFIID riid, void** ppvObject ){	if( !ppvObject ) return E_POINTER;    if( riid == IID_IVMRSurfaceAllocator9 )	{	*ppvObject = (IVMRSurfaceAllocator9*)this;        AddRef();    }     else if( riid == IID_IVMRImagePresenter9 )	{	*ppvObject = (IVMRImagePresenter9*)this;        AddRef();    }     else if( riid == IID_IUnknown )	{	*ppvObject = (IUnknown*)((IVMRSurfaceAllocator9*)this);        AddRef();    }    return S_OK;}// Add a reference to the interfaceULONG STDMETHODCALLTYPE CVMR9Allocator::AddRef( void ){	return ++m_lRefCount;}// Release interfaceULONG STDMETHODCALLTYPE CVMR9Allocator::Release( void ){	if( m_lRefCount > 0 ) return --m_lRefCount;	return m_lRefCount;}// Set the devicevoid CVMR9Allocator::SetDevice( HWND hWnd, IDirect3DDevice9* pd3dDevice ){	m_hWnd			 = hWnd;	m_pd3dDeviceInst = pd3dDevice;}// Set the size of the video windowvoid CVMR9Allocator::SetVideoWindow( float x, float y, float fWidth, float fHeight ){	if( m_pVideoWindow )	{	// Get the vertice's		vector<CTDVertex> vVertices;		m_pVideoWindow->GetVertices( vVertices );		if( vVertices.size() < 4 ) return;		// Adjust the vertice's positions		vVertices[0].m_vPosition.x = x;		vVertices[0].m_vPosition.y = y - fHeight;		vVertices[1].m_vPosition.x = x + fWidth;		vVertices[1].m_vPosition.y = y - fHeight;		vVertices[2].m_vPosition.x = x + fWidth;		vVertices[2].m_vPosition.y = y;		vVertices[3].m_vPosition.x = x;		vVertices[3].m_vPosition.y = y;		// Set the vertice's		m_pVideoWindow->SetVertices( vVertices );	}}// Get the movie widthDWORD CVMR9Allocator::GetMovieWidth() const{	return m_dwMovieWidth;}// Get the movie heightDWORD CVMR9Allocator::GetMovieHeight() const{	return m_dwMovieHeight;}// Delete surfacesvoid CVMR9Allocator::DeleteSurfaces(){    for ( DWORD i(0); i < m_dwSurfaceNum; ++i ) 		SafeRelease( m_vpSurfaces );	m_vpSurfaces.clear();	m_dwSurfaceNum = 0;}


VMR9.h
	// Class VMR9	class CVMR9	{		public:			CVMR9();			~CVMR9();			// User mutators			bool LoadMedia( HWND hWnd, IDirect3DDevice9* pd3dDevice, const string& strFilePath, const D3DXVECTOR2& vResolution );			void SetVideoWindow( float x, float y, float fWidth, float fHeight );			void OnRender( IDirect3DDevice9* pd3dDevice );			void Play();			void Stop();			// User accessors			bool  IsPlaying();			DWORD GetMovieWidth() const;			DWORD GetMovieHeight() const;		private:			// Support member functions			HRESULT SetAllocatorPresenter( HWND hWnd, IDirect3DDevice9* pd3dDevice, IBaseFilter *pFilter );			bool	CleanUp();			// VMR9 data			IGraphBuilder*	m_pGraph;			IBaseFilter*	m_pFilter;			IMediaControl*	m_pMediaControl;			CVMR9Allocator*	m_pAllocator;	};


VMR9.cpp
// VMR9 class constructorCVMR9::CVMR9():	m_pGraph(NULL),	m_pFilter(NULL),	m_pMediaControl(NULL),	m_pAllocator(NULL){}// VMR9 class destructorCVMR9::~CVMR9(){	CleanUp();}// Load media from filebool CVMR9::LoadMedia( HWND hWnd, IDirect3DDevice9* pd3dDevice, const string& strFilePath, const D3DXVECTOR2& vResolution ){	// Create the graph	if( FAILED( ::CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_ALL, IID_IGraphBuilder, (void**)&m_pGraph ) ) )		return CleanUp();	// Create the VMR9 filter	if( FAILED( ::CoCreateInstance( CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&m_pFilter ) ) )		return CleanUp();	// Create a filter config	IVMRFilterConfig9* pFilterConfig(NULL);	if( FAILED( m_pFilter->QueryInterface( IID_IVMRFilterConfig9, (void**)&pFilterConfig ) ) )		return CleanUp();	// Set VMR9 rendering mode	pFilterConfig->SetRenderingMode( VMR9Mode_Renderless );	pFilterConfig->SetNumberOfStreams( 1 );	SafeRelease( pFilterConfig );	// Set the allocator presenter	if( FAILED( SetAllocatorPresenter( hWnd, pd3dDevice, m_pFilter ) ) )		return CleanUp();	// Add the VMR9 to the graph	if( FAILED( m_pGraph->AddFilter( m_pFilter, L"Video Mixing Renderer 9" ) ) )	  return CleanUp();	// Create the media control	if( FAILED( m_pGraph->QueryInterface( IID_IMediaControl, (void**)&m_pMediaControl ) ) )		return CleanUp();	// Render the file    if( FAILED( m_pGraph->RenderFile( stows( strFilePath ).c_str(), NULL ) ) )		return CleanUp();	return true;}// Set the size of the video windowvoid CVMR9::SetVideoWindow( float x, float y, float fWidth, float fHeight ){	if( m_pAllocator ) m_pAllocator->SetVideoWindow( x, y, fWidth, fHeight );}// Render the filevoid CVMR9::OnRender( IDirect3DDevice9* pd3dDevice ){}// Play the currently loaded filevoid CVMR9::Play(){	if( m_pMediaControl ) m_pMediaControl->Run();}// Stop playing the filevoid CVMR9::Stop(){	if( m_pMediaControl )	{	OAFilterState filterState;		do		{	m_pMediaControl->Stop();			m_pMediaControl->GetState( 0, &filterState );		} while( filterState != State_Stopped );	}}// Check if the file is playingbool CVMR9::IsPlaying(){	if( m_pMediaControl )	{	OAFilterState filterState;		m_pMediaControl->GetState( 0, &filterState );		return filterState != State_Stopped;	}	return false;}// Get the movie widthDWORD CVMR9::GetMovieWidth() const{	if( m_pAllocator ) return m_pAllocator->GetMovieWidth();	return 0;}// Get the movie heightDWORD CVMR9::GetMovieHeight() const{	if( m_pAllocator ) return m_pAllocator->GetMovieHeight();	return 0;}// Set the allocator presenterHRESULT CVMR9::SetAllocatorPresenter( HWND hWnd, IDirect3DDevice9* pd3dDevice, IBaseFilter* pFilter ){	// Create the surface allocator notify	IVMRSurfaceAllocatorNotify9* pIVMRSurfAllocNotify(NULL);	if( FAILED( pFilter->QueryInterface( IID_IVMRSurfaceAllocatorNotify9, (void**)&pIVMRSurfAllocNotify ) ) )		return E_FAIL;	// Establish a communication link with the allocator	m_pAllocator = new CVMR9Allocator;	m_pAllocator->SetDevice( hWnd, pd3dDevice );	if( FAILED( pIVMRSurfAllocNotify->AdviseSurfaceAllocator( 0xACDCACDC, m_pAllocator ) ) )		return E_FAIL;	// Advise the allocator	if( FAILED( m_pAllocator->AdviseNotify( pIVMRSurfAllocNotify ) ) )		return E_FAIL;	return S_OK;}// Clean upbool CVMR9::CleanUp(){	Stop();	SafeRelease( m_pGraph );	SafeRelease( m_pFilter );	SafeRelease( m_pMediaControl );	SafeRelease( m_pAllocator );	return false;}
Headkaze
Headkaze
You should be setting your mixing prefs just before you add your filter to the graph.

// Here you need to SetMixingPrefs (try RenderTargetYUV, NoDecimation, ARAdjustXorY and BiLinearFiltering// Add the VMR9 to the graphif( FAILED( m_pGraph->AddFilter( m_pFilter, L"Video Mixing Renderer 9" ) ) )   return CleanUp();


Quote:
Original post by jesse121
I am trying to play a movie that has both video and sound should I SetNumberOfStreams() to 0, 1, or 2?


Just try setting 1 stream for now

Quote:
Original post by jesse121
I setup the VMR9AllocationInfo with the following flags:
D3DDISPLAYMODE dm; m_pd3dDevice->GetDisplayMode( 0, &dm );
pAllocInfo->dwFlags = VMR9AllocFlag_3DRenderTarget;
pAllocInfo->Format = dm.Format;
pAllocInfo->Pool = D3DPOOL_DEFAULT;

Should I be using a different flag such as VMR9AllocFlag_OffscreenSurface or VMR9AllocFlag_TextureSurface?


You should be using an offscreen surface then in PresentImage() use StretchRectangle to do the pixel format conversion to the surface of your texture.

Sorry I can't be more specific with help as I code in C#.

jesse121
jesse121
I did what you said, and set the IVMRFilterConfig9::SetNumberOfStreams( 1 ) to one.
I set the allocInfo flag to VMR9AllocFlag_OffscreenSurface.
I also placed this code just before adding the VMR9 to the graph:

// Create the mixer control	IVMRMixerControl9* pMixerControl(NULL);	if( FAILED( m_pFilter->QueryInterface( IID_IVMRMixerControl9, (void**)&pMixerControl ) ) )		return CleanUp();	// Set VMR9 mixing preferences	DWORD dwPrefs(0);	dwPrefs |= MixerPref_RenderTargetYUV;	dwPrefs |= MixerPref9_NoDecimation;	dwPrefs |= MixerPref9_BiLinearFiltering;	dwPrefs |= MixerPref9_ARAdjustXorY;	pMixerControl->SetMixingPrefs( dwPrefs );	SafeRelease( pMixerControl );


Now when I run it I get about 10 calls to TerminateDevice(), and once again the video is rendered in a pop up window and not in my main window. I tried different combinations of mixing preferences but got the same result every time.
Any ideas why this isn't working?
Muhammad Haggag
Muhammad Haggag
Apologies for not replying so far. I'll try to test your code later tonight. In the meantime, it'd help if you posted the solution/project as well; I'm really short on time.

Muhammad Haggag
Muhammad Haggag
I still haven't tried your code, but I've noticed there are several VMR samples that come with the platform SDK. Did you check them out? I assume one would cover the renderless mode.

They should be in (Samples\Multimedia\DirectShow\VMR9). If you don't have them in your version of the SDK, I can upload them somewhere.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.