//------------------------------------------------------------------------------ // File: MultiGraphSession.cpp // // Desc: DirectShow sample code - MultiVMR9 MultiPlayer sample // // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #include "stdafx.h" #include "MultiVMR9.h" #include "VMR9Subgraph.h" #include "MultigraphSession.h" extern HINSTANCE g_hInstance; const TCHAR g_achVideoWindowClass[] = TEXT("MultiVMR9 Video Window class"); /******************************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::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::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::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("VMR9 Custom Allocator-Presenter"), dwStyle, 100, 100, 800, 600, NULL, NULL, g_hInstance, NULL); if( !IsWindow( m_hwndVideo )) throw E_FAIL; ::SetWindowLong( m_hwndVideo, GWL_USERDATA, (LONG)this); // 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; ::SetWindowPos( m_hwndVideo, HWND_TOP, 0, 0, Width+dx, Height+dy, 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 = (CMultigraphSession*)::GetWindowLong( hwnd, GWL_USERDATA); if( This ) { pUI = This->GetUILayer(); } lRes = DefWindowProc( hwnd, uMsg, wParam, lParam); if( pUI ) { pUI->ProcessMessage( uMsg, (UINT)wParam, (LONG)lParam); } RELEASE( pUI ); return lRes; }