topical media & game development
hush-src-multi-GamePlayer-MultiGraphSession.cpp / cpp
//------------------------------------------------------------------------------
// File: MultiGraphSession.cpp
//
// Desc: DirectShow sample code - MultiVMR9 GamePlayer
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
include <stdafx.h>
include <MultiVMR9.h>
include <VMR9Subgraph.h>
include <MultigraphSession.h>
include <vip.h>
extern HINSTANCE g_hInstance;
const TCHAR g_achVideoWindowClass[] = TEXT("MultiVMR9 Video Window class");
// AE
DWORD_PTR CMultigraphSession::GetCaptureID() {
if (m_capture_on == 1)
return m_capture_id;
else return 0;
}
// AddCapture
****************************Public*Routine******************************\
AddCapture
adds new source to the list, attaches it to the wizard
\*************************************************************************
HRESULT CMultigraphSession::AddCapture(DWORD_PTR& dwID, int num,WCHAR *wcPath)
{
CVMR9Subgraph *pSubgraph = NULL;
HRESULT hr = S_OK;
try
{
if (1 || m_capture_on == 0) {
pSubgraph = new CVMR9Subgraph;
if( !pSubgraph )
{
throw E_OUTOFMEMORY;
}
hr = pSubgraph->CaptureAndRender(/* wcPath,*/ m_pWizard, num );
if( FAILED(hr))
{
throw hr;
}
//remember the ID, add to the list
m_capture_id = dwID = pSubgraph->GetID();
m_sources.push_back( pSubgraph );
m_capture_on +=1;
} else {
dwID = m_capture_id;
}
}
catch( HRESULT hr1 )
{
if( pSubgraph )
{
delete pSubgraph;
}
hr = hr1;
}
return hr;
}
****************************Public*Routine******************************\
CMultigraphSession
constructor
\*************************************************************************
CMultigraphSession::CMultigraphSession()
: m_hwndVideo( NULL )
, m_pWizard( NULL )
, m_pRenderEngine( NULL )
, m_pMixerControl( NULL )
, m_pUILayer( NULL )
{
}
****************************Public*Routine******************************\
~CMultigraphSession
destructor
\*************************************************************************
CMultigraphSession::~CMultigraphSession()
{
Terminate();
RELEASE( m_pWizard );
RELEASE( m_pRenderEngine );
RELEASE( m_pMixerControl );
RELEASE( m_pUILayer );
}
****************************Public*Routine******************************\
AddSource
adds new source to the list, attaches it to the wizard
\*************************************************************************
HRESULT CMultigraphSession::AddSource(WCHAR *wcPath, DWORD_PTR& dwID)
{
CVMR9Subgraph *pSubgraph = NULL;
HRESULT hr = S_OK;
if( !wcPath )
{
return E_POINTER;
}
if( !m_pWizard )
{
return VFW_E_WRONG_STATE;
}
try
{
// commented lines work fine on XP and NT4
/*
if( INVALID_FILE_ATTRIBUTES == ::GetFileAttributesW( wcPath))
{
throw VFW_E_NOT_FOUND;
}*/
// Unicode-related workaround for WindowsMe/98
{
char szPath[MAX_PATH];
DWORD dwGFA = 0L;
DWORD dwErr = 0L;
WideCharToMultiByte(CP_ACP, 0, wcPath, -1, szPath, MAX_PATH, NULL, NULL);
dwGFA = ::GetFileAttributesA( szPath);
if( INVALID_FILE_ATTRIBUTES == dwGFA)
{
dwErr = GetLastError();
throw VFW_E_NOT_FOUND;
}
}
pSubgraph = new CVMR9Subgraph;
if( !pSubgraph )
{
throw E_OUTOFMEMORY;
}
hr = pSubgraph->BuildAndRender( wcPath, m_pWizard );
if( FAILED(hr))
{
throw hr;
}
//remember the ID, add to the list
dwID = pSubgraph->GetID();
m_sources.push_back( pSubgraph );
}
catch( HRESULT hr1 )
{
if( pSubgraph )
{
delete pSubgraph;
}
hr = hr1;
}
return hr;
}
****************************Public*Routine******************************\
DeleteSource
deletes a source from the list, detaches it from the wizard
\*************************************************************************
HRESULT CMultigraphSession::DeleteSource( DWORD_PTR dwID )
{
HRESULT hr = S_OK;
CVMR9Subgraph *pSubgraph = NULL;
try
{
if( !m_pWizard )
{
throw VFW_E_WRONG_STATE;
}
pSubgraph = GetSubgraph( dwID );
if( !pSubgraph )
{
throw VFW_E_NOT_FOUND;
}
hr = pSubgraph->Stop();
if( FAILED(hr))
{
throw hr;
}
hr = m_pWizard->Detach( pSubgraph->GetID());
if( FAILED(hr))
{
throw hr;
}
m_sources.remove( pSubgraph );
delete pSubgraph;
pSubgraph = NULL;
hr = S_OK;
}
catch( HRESULT hr1 )
{
hr = hr1;
}
return hr;
}
****************************Public*Routine******************************\
Terminate
terminates wizard
\*************************************************************************
HRESULT CMultigraphSession::Terminate()
{
HRESULT hr = S_OK;
list<CVMR9Subgraph*>::iterator it;
CVMR9Subgraph* pSubgraph = NULL;
try
{
// 1. Detach all the existing subgraphs
while( false == m_sources.empty())
{
it = m_sources.begin();
pSubgraph = (CVMR9Subgraph*)(*it);
ASSERT( pSubgraph );
hr = DeleteSource( pSubgraph->GetID());
if( FAILED(hr))
throw hr;
}
// 2. Terminate Wizard, if there is any
if( m_pWizard )
{
hr = m_pWizard->Terminate();
if( FAILED(hr))
throw hr;
}
// 3. Destroy video window
if( IsWindow( m_hwndVideo ))
{
::DestroyWindow( m_hwndVideo );
m_hwndVideo = NULL;
}
UnregisterClass( g_achVideoWindowClass, g_hInstance);
}
catch( HRESULT hr1)
{
hr = hr1;
}
return hr;
}
****************************Public*Routine******************************\
GetSubgraph
find subgraph in the list by dwID
\*************************************************************************
CVMR9Subgraph* CMultigraphSession::GetSubgraph( DWORD_PTR dwID )
{
CVMR9Subgraph* pSubgraph = NULL;
list<CVMR9Subgraph*>::iterator start, end, it;
start = m_sources.begin();
end = m_sources.end();
for(it = start; it!= end; it++)
{
if( (*it) && (*it)->GetID() == dwID )
{
pSubgraph = (CVMR9Subgraph*)(*it);
break;
}
}
return pSubgraph;
}
****************************Public*Routine******************************\
GetWizard
\*************************************************************************
IMultiVMR9Wizard* CMultigraphSession::GetWizard( )
{
IMultiVMR9Wizard* pRes = NULL;
if( m_pWizard )
{
pRes = m_pWizard;
pRes->AddRef();
}
return pRes;
}
****************************Public*Routine******************************\
GetRenderEngine
\*************************************************************************
IMultiVMR9RenderEngine* CMultigraphSession::GetRenderEngine( )
{
IMultiVMR9RenderEngine* pRes = NULL;
if( m_pRenderEngine )
{
pRes = m_pRenderEngine;
pRes->AddRef();
}
return pRes;
}
****************************Public*Routine******************************\
GetMixerControl
\*************************************************************************
IMultiVMR9MixerControl* CMultigraphSession::GetMixerControl( )
{
IMultiVMR9MixerControl* pRes = NULL;
if( m_pMixerControl )
{
pRes = m_pMixerControl;
pRes->AddRef();
}
return pRes;
}
****************************Public*Routine******************************\
GetUILayer
\*************************************************************************
IMultiVMR9UILayer* CMultigraphSession::GetUILayer( )
{
IMultiVMR9UILayer* pRes = NULL;
if( m_pUILayer )
{
pRes = m_pUILayer;
pRes->AddRef();
}
return pRes;
}
****************************Public*Routine******************************\
GetFrameRate
\*************************************************************************
int CMultigraphSession::GetFrameRate()
{
int nRes = 0;
if( !m_pRenderEngine )
return 30;
m_pRenderEngine->GetFrameRate( &nRes );
return nRes;
}
****************************Public*Routine******************************\
SetColor
\*************************************************************************
HRESULT CMultigraphSession::SetColor( COLORREF color )
{
HRESULT hr = S_OK;
if( !m_pMixerControl )
return E_FAIL;
hr = m_pMixerControl->SetBackgroundColor( color );
return hr;
}
****************************Public*Routine******************************\
LoopSources
go through the list and reset time to start if movie is close to the end
\*************************************************************************
void CMultigraphSession::LoopSources()
{
CVMR9Subgraph *pSource = NULL;
LONGLONG llCur;
LONGLONG llDur;
list<CVMR9Subgraph*>::iterator start, end, it;
start = m_sources.begin();
end = m_sources.end();
for( it = start; it != end; it++)
{
pSource = (CVMR9Subgraph*)(*it);
if( !pSource )
continue;
pSource->GetTimes( llCur, llDur);
// 100ms
if( llDur - llCur < 1000000L )
{
pSource->SetTime( 0L );
}
}
}
****************************Public*Routine******************************\
CreateVideoWindow_
creates video window
\*************************************************************************
HRESULT CMultigraphSession::CreateVideoWindow_(UINT Width, UINT Height, DWORD dwStyle)
{
HRESULT hr = S_OK;
WNDCLASSEX wcex;
RECT rc;
RECT rcClient;
int dx, dy;
try
{
if( IsWindow( m_hwndVideo ))
throw E_UNEXPECTED;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)CMultigraphSession::VideoWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = g_hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = TEXT("");
wcex.lpszClassName = g_achVideoWindowClass;
wcex.hIconSm = NULL;
RegisterClassEx( &wcex);
m_hwndVideo = CreateWindow( g_achVideoWindowClass,
TEXT("ViP"),
dwStyle,
//100, 100,
0,-25,
//800, 600,
Width, Height,
//1024, 768,
NULL,
NULL,
g_hInstance,
NULL);
if( !IsWindow( m_hwndVideo ))
throw E_FAIL;
::SetWindowLongPtr( m_hwndVideo, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this));
scene::ptr("VP","window",m_hwndVideo);
// resize the window so that client area be 800x600
::GetClientRect( m_hwndVideo, &rcClient);
::GetWindowRect( m_hwndVideo, &rc);
dx = rc.right - rc.left - rcClient.right;
dy = rc.bottom - rc.top - rcClient.bottom;
dx = dy = 0;
::SetWindowPos( m_hwndVideo, HWND_TOP, 0, 0, Width+dx, Height+dy, 0); //SWP_NOMOVE);
}// try
catch( HRESULT hr1 )
{
hr = hr1;
}
return hr;
}
****************************Public*Routine******************************\
VideoWndProc
\*************************************************************************
LRESULT CALLBACK CMultigraphSession::VideoWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
CMultigraphSession* This = NULL;
IMultiVMR9UILayer* pUI = NULL;
LRESULT lRes = 0;
This = reinterpret_cast<CMultigraphSession*>(::GetWindowLongPtr( hwnd, GWL_USERDATA));
if( This )
{
pUI = This->GetUILayer();
}
if( uMsg == WM_CLOSE )
{
HRESULT hr = This->Terminate();
return 0L;
}
lRes = DefWindowProc( hwnd, uMsg, wParam, lParam);
if( pUI )
{
pUI->ProcessMessage( uMsg, (UINT)wParam, (LONG)lParam);
}
RELEASE( pUI );
return lRes;
}
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.