www.pudn.com > fastplayer-0.1.zip > FastPlayerDoc.cpp, change:2002-01-08,size:17362b


// FastPlayerDoc.cpp : implementation of the CFastPlayerDoc class 
// 
 
#include "stdafx.h" 
#include "FastPlayer.h" 
 
#include "FastPlayerDoc.h" 
#include "OptionsDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CFastPlayerDoc 
 
IMPLEMENT_DYNCREATE(CFastPlayerDoc, CDocument) 
 
BEGIN_MESSAGE_MAP(CFastPlayerDoc, CDocument) 
	//{{AFX_MSG_MAP(CFastPlayerDoc) 
		// NOTE - the ClassWizard will add and remove mapping macros here. 
		//    DO NOT EDIT what you see in these blocks of generated code! 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFastPlayerDoc construction/destruction 
 
CFastPlayerDoc::CFastPlayerDoc() 
{ 
	m_pGraphBuilder = NULL; 
	m_pMediaControl = NULL; 
	m_pMediaEventEx = NULL; 
	m_pMediaSeeking = NULL; 
	m_pVideoWindow = NULL; 
	m_pBasicVideo = NULL; 
	m_pBasicAudio = NULL; 
 
	m_currentStatus = statusEmpty; 
 
	m_dwGraphRegister = 0; 
	m_bFixAC3 = FALSE; 
	m_bUseWaveOut = FALSE; 
 
	m_nVolume = 100; 
 
	m_pFilters = NULL; 
} 
 
CFastPlayerDoc::~CFastPlayerDoc() 
{ 
} 
 
BOOL CFastPlayerDoc::OnNewDocument() 
{ 
	if (!CDocument::OnNewDocument()) 
		return FALSE; 
 
	LoadDefaultSettings(); 
 
	return TRUE; 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CFastPlayerDoc serialization 
 
void CFastPlayerDoc::Serialize(CArchive& ar) 
{ 
	if (ar.IsStoring()) 
	{ 
		// TODO: add storing code here 
	} 
	else 
	{ 
		// TODO: add loading code here 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CFastPlayerDoc diagnostics 
 
#ifdef _DEBUG 
void CFastPlayerDoc::AssertValid() const 
{ 
	CDocument::AssertValid(); 
} 
 
void CFastPlayerDoc::Dump(CDumpContext& dc) const 
{ 
	CDocument::Dump(dc); 
} 
#endif //_DEBUG 
 
///////////////////////////////////////////////////////////////////////////// 
// CFastPlayerDoc commands 
 
void CFastPlayerDoc::ReleaseMediaInterfaces() 
{ 
	// Release the graph registration 
    if (m_dwGraphRegister) 
    { 
        RemoveGraphFromRot(m_dwGraphRegister); 
        m_dwGraphRegister = 0; 
    } 
 
	// Release all COM interfaces to DirectShow 
	if (m_pMediaControl) 
		m_pMediaControl->Release(); 
	m_pMediaControl = NULL; 
	if (m_pMediaEventEx) 
		m_pMediaEventEx->Release(); 
	m_pMediaEventEx = NULL; 
	if (m_pMediaSeeking) 
		m_pMediaSeeking->Release(); 
	m_pMediaSeeking = NULL; 
	if (m_pVideoWindow) 
		m_pVideoWindow->Release(); 
	m_pVideoWindow = NULL; 
	if (m_pBasicVideo) 
		m_pBasicVideo->Release(); 
	m_pBasicVideo = NULL; 
	if (m_pBasicAudio) 
		m_pBasicAudio->Release(); 
	m_pBasicAudio = NULL; 
 
	if (m_pGraphBuilder) 
		m_pGraphBuilder->Release(); 
	m_pGraphBuilder = NULL; 
} 
 
HRESULT CFastPlayerDoc::AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)  
{ 
    IMoniker * pMoniker; 
    IRunningObjectTable *pROT; 
    if (FAILED(GetRunningObjectTable(0, &pROT))) { 
        return E_FAIL; 
    } 
    WCHAR wsz[128]; 
    wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId()); 
    HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker); 
    if (SUCCEEDED(hr)) { 
        hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister); 
        pMoniker->Release(); 
    } 
    pROT->Release(); 
    return hr; 
} 
 
void CFastPlayerDoc::RemoveGraphFromRot(DWORD pdwRegister) 
{ 
    IRunningObjectTable *pROT; 
    if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) { 
        pROT->Revoke(pdwRegister); 
        pROT->Release(); 
    } 
} 
 
HRESULT CFastPlayerDoc::Play() 
{ 
	// In order to play, the video must be either stopped or paused 
	ASSERT(m_currentStatus == statusStopped || m_currentStatus == statusPaused); 
	HRESULT hr; 
 
	// If the video is paused, resume must stop, seek and run, not unpause 
	if (m_currentStatus == statusPaused && 
		/*IsAC3AudioPresent() &&*/ 
		m_bFixAC3) 
	{ 
		hr = m_pMediaControl->StopWhenReady(); 
		if (SUCCEEDED(hr)) 
		{ 
			// Wait until stop is final 
			FILTER_STATE fs; 
			fs = State_Paused; 
			while (SUCCEEDED(hr) && fs == State_Paused) 
			{ 
				hr = m_pMediaControl->GetState(1000, (OAFilterState*)&fs); 
			} 
			if (FAILED(hr) || fs != State_Stopped) 
			{ 
				TRACE0("Failed to stop playback\n"); 
				return hr; 
			} 
			// Graph should be fully stopped now 
		} 
		hr = m_pMediaControl->Run(); 
	} 
	else 
	{ 
		hr = m_pMediaControl->Run(); 
	} 
	if (SUCCEEDED(hr)) 
	{ 
		m_currentStatus = statusRunning; 
		UpdateAllViews(NULL); 
	} 
	return hr; 
} 
 
HRESULT CFastPlayerDoc::Stop() 
{ 
	ASSERT(m_currentStatus == statusRunning || 
		   m_currentStatus == statusPaused); 
 
	HRESULT hr; 
	 
	m_currentStatus = statusStopped; 
	hr = m_pMediaControl->StopWhenReady(); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to stop the video\n"); 
		return hr; 
	} 
	// Reset to the begining 
    LONGLONG pos = 0; 
	hr = m_pMediaSeeking->SetPositions(&pos,  
									   AM_SEEKING_AbsolutePositioning, 
									   NULL, 
									   AM_SEEKING_NoPositioning); 
	if (SUCCEEDED(hr)) 
	{ 
		UpdateAllViews(NULL); 
	} 
	return hr; 
} 
 
HRESULT CFastPlayerDoc::Pause() 
{ 
	ASSERT(m_currentStatus != statusEmpty); 
	HRESULT hr; 
 
	if (m_currentStatus == statusRunning) 
	{ 
		m_currentStatus = statusPaused; 
		hr = m_pMediaControl->Pause(); 
		if (SUCCEEDED(hr)) 
		{ 
			UpdateAllViews(NULL); 
		} 
	} 
	else  
	{ 
		hr = Play(); 
	} 
	return hr; 
} 
 
void CFastPlayerDoc::Close() 
{ 
	ASSERT(m_currentStatus != statusEmpty); 
 
	// If the video is running, stop it 
	if (m_currentStatus == statusRunning || 
		m_currentStatus == statusPaused) 
		m_pMediaControl->Stop(); 
 
	m_currentStatus = statusStopped; 
 
	// If the filters dialog has been created, destroy it 
	if (m_pFilters) 
	{ 
		m_pFilters->SendMessage(WM_CLOSE); 
		delete m_pFilters; 
		m_pFilters = NULL; 
	} 
 
#ifdef REGISTER_FILTERGRAPH 
	if (m_dwGraphRegister) 
		RemoveGraphFromRot(m_dwGraphRegister); 
#endif 
	// Release all interfaces, thereby closing the file 
	ReleaseMediaInterfaces(); 
	m_currentStatus = statusEmpty; 
 
	WriteDefaultSettings(); 
 
	UpdateAllViews(NULL); 
} 
 
BOOL CFastPlayerDoc::IsAC3AudioPresent() 
{ 
	HRESULT hr; 
	 
	// Find if AC3 audio is present 
	// 1. Find Intervideo Audio Decoder filter 
	IBaseFilter *pIntervideo = NULL; 
    WCHAR wFilterName[MAX_PATH]; 
    MultiByteToWideChar(CP_ACP, 0, "InterVideo Audio Decoder", -1, wFilterName, MAX_PATH); 
	hr = m_pGraphBuilder->FindFilterByName(wFilterName, &pIntervideo); 
	if (SUCCEEDED(hr) && pIntervideo) 
	{ 
		pIntervideo->Release(); 
		return TRUE; 
	} 
	// 2. TODO: Other detection methods 
	return FALSE; 
 
} 
 
HRESULT CFastPlayerDoc::Open(const CString &strFile) 
{ 
	// Open the file and play it 
	HRESULT hr; 
 
	// If there is a file opened already, close it 
	if (m_currentStatus == statusPaused || m_currentStatus == statusRunning) 
		Stop(); 
	if (m_currentStatus != statusEmpty) 
		Close(); 
 
	hr = RenderFile(strFile); 
	if (FAILED(hr)) 
	{ 
		AfxMessageBox("The file cannot be opened"); 
		return hr; 
	} 
 
	m_pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); 
	ChangeAudioVolume(m_nVolume); 
 
	// Play the file 
	return Play(); 
} 
 
HRESULT CFastPlayerDoc::RenderFile(const CString &strFile) 
{ 
	// Build the DirectShow graph needed to play the file 
	// TODO: Support for AC3 files 
 
	m_currentStatus = statusEmpty; 
 
	// Translate the filename to unicode 
    WCHAR wFile[MAX_PATH]; 
    MultiByteToWideChar(CP_ACP, 0, strFile, -1, wFile, MAX_PATH); 
	 
 
	HRESULT hr; 
	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_pGraphBuilder); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to create an instance of FilterGraph\n"); 
		return hr; 
	} 
 
	// Insert Default Wave Out filter 
	if (m_bUseWaveOut) 
	{ 
		IBaseFilter *pAudioRender = NULL; 
		hr = CoCreateInstance(CLSID_AudioRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pAudioRender); 
		if (SUCCEEDED(hr)) 
		{ 
			hr = m_pGraphBuilder->AddFilter(pAudioRender, L"Default WaveOut Device"); 
			if (SUCCEEDED(hr)) 
			{ 
				TRACE0("Default Audio Renderer inserted in graph\n"); 
			} 
			pAudioRender->Release(); 
		} 
	} 
 
	// Currently the graph is rendered automatically 
	hr = m_pGraphBuilder->RenderFile(wFile, NULL); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to render the file\n"); 
		ReleaseMediaInterfaces(); 
		return hr; 
	} 
 
	// Query DirectShow interfaces 
	if (FAILED(m_pGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&m_pMediaControl)) || 
		FAILED(m_pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void**)&m_pMediaEventEx)) || 
		FAILED(m_pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void**)&m_pMediaSeeking)) || 
		FAILED(m_pGraphBuilder->QueryInterface(IID_IBasicVideo, (void**)&m_pBasicVideo)) || 
		FAILED(m_pGraphBuilder->QueryInterface(IID_IBasicAudio, (void**)&m_pBasicAudio)) || 
		FAILED(m_pGraphBuilder->QueryInterface(IID_IVideoWindow, (void**)&m_pVideoWindow))) 
	{ 
		TRACE0("Failed to obtain at least one DirectShow interface\n"); 
		ReleaseMediaInterfaces(); 
		return hr; 
	} 
 
	m_currentStatus = statusStopped; 
 
	// Verify that the media file has at least video 
	long lVisible; 
	hr = m_pVideoWindow->get_Visible(&lVisible); 
	if (FAILED(hr)) 
	{ 
		TRACE0("The Media file does not contain video, or the video stream cannot be played\n"); 
		Close(); 
		return hr; 
	} 
 
	// Determine if audio is available 
	long lVolume; 
	if (FAILED(m_pBasicAudio->get_Volume(&lVolume))) 
	{ 
		TRACE0("The Media file does not contain audio"); 
		m_pBasicAudio->Release(); 
		m_pBasicAudio = NULL; 
	} 
 
	if (m_pBasicAudio) 
		m_pBasicAudio->put_Volume(m_nVolume); 
 
	// Set the message drain to the main window 
	if (FAILED(m_pVideoWindow->put_MessageDrain((OAHWND)AfxGetMainWnd()->GetSafeHwnd()))) 
		TRACE0("Failed to set the message drain\n"); 
 
#ifdef REGISTER_FILTERGRAPH 
    hr = AddGraphToRot(m_pGraphBuilder, &m_dwGraphRegister); 
    if (FAILED(hr)) 
    { 
        TRACE("Failed to register filter graph with ROT!  hr=0x%x", hr); 
        m_dwGraphRegister = 0; 
    } 
#endif 
 
	return S_OK; 
} 
 
BOOL CFastPlayerDoc::OnOpenDocument(LPCTSTR lpszPathName)  
{ 
	if (!CDocument::OnOpenDocument(lpszPathName)) 
		return FALSE; 
	 
	// If there is a file opened already, close it 
	if (m_currentStatus == statusPaused || m_currentStatus == statusRunning) 
		Stop(); 
	if (m_currentStatus != statusEmpty) 
		Close(); 
 
	LoadDefaultSettings(); 
 
	CString strFile = lpszPathName; 
	if (SUCCEEDED(Open(strFile))) 
		return TRUE; 
	return FALSE; 
} 
 
void CFastPlayerDoc::OnCloseDocument()  
{ 
	if (m_pFilters) 
	{ 
		m_pFilters->SendMessage(WM_CLOSE); 
		delete m_pFilters; 
		m_pFilters = NULL; 
	} 
 
	if (m_currentStatus != statusEmpty) 
		Close(); 
 
	CDocument::OnCloseDocument(); 
} 
 
UINT CFastPlayerDoc::GetPlaybackPosition() 
{ 
	ASSERT(m_currentStatus != statusEmpty); 
 
	// Get video lenght 
	HRESULT hr; 
	LONGLONG llDuration; 
	hr = m_pMediaSeeking->GetDuration(&llDuration); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to obtain video duration\n"); 
		return 0; 
	} 
 
	// Get current playback position 
	LONGLONG llPlayback; 
	LONGLONG llStop; 
	hr = m_pMediaSeeking->GetPositions(&llPlayback, &llStop); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to obtain video position\n"); 
		return 0; 
	} 
 
	UINT nPos = (UINT)(llPlayback * 1000 / llDuration); 
	return nPos;	 
} 
 
void CFastPlayerDoc::ChangePlaybackPosition(UINT nPosition) 
{ 
	ASSERT(m_currentStatus != statusEmpty); 
	ASSERT(nPosition >= 0 && nPosition <= 1000); 
 
	// Get video length 
	HRESULT hr; 
	LONGLONG llDuration; 
	hr = m_pMediaSeeking->GetDuration(&llDuration); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to obtain video duration\n"); 
		return; 
	} 
 
	// For AC3 audio, stop the playback and continue 
	if (/*IsAC3AudioPresent() && */m_bFixAC3 && m_currentStatus == statusRunning) 
	{ 
		m_pMediaControl->Stop(); 
	} 
 
 
	LONGLONG llDesiredPosition = llDuration * nPosition / 1000; 
	hr = m_pMediaSeeking->SetPositions(&llDesiredPosition, 
									   AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
									   NULL, 
									   AM_SEEKING_NoPositioning); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to set current position\n"); 
		return; 
	} 
 
	if (/*IsAC3AudioPresent() && */m_bFixAC3 && m_currentStatus == statusRunning) 
	{ 
		m_pMediaControl->Run(); 
	} 
 
	UpdateAllViews(NULL); 
} 
 
 
int CFastPlayerDoc::GetAudioVolume() 
{ 
	if (!m_pBasicAudio) 
		return 0; 
 
	return m_nVolume; 
} 
 
void CFastPlayerDoc::ChangeAudioVolume(int nVolume) 
{ 
	ASSERT(nVolume >= 0 && nVolume <= 100 && m_currentStatus != statusEmpty); 
 
	m_nVolume = nVolume; 
 
	if (!m_pBasicAudio) 
		return; 
 
	long lVolume = (nVolume - 100) * 100; 
	m_pBasicAudio->put_Volume(lVolume); 
} 
 
void CFastPlayerDoc::Mute() 
{ 
	if (!m_pBasicAudio) 
		return; 
 
	m_pBasicAudio->put_Volume(-10000); 
} 
 
void CFastPlayerDoc::UnMute() 
{ 
	if (!m_pBasicAudio) 
		return; 
 
	long lVolume = (m_nVolume - 100) * 100; 
	m_pBasicAudio->put_Volume(lVolume); 
} 
 
void CFastPlayerDoc::SetFullScreen(BOOL bFullScreen) 
{ 
	if (m_currentStatus == statusEmpty) 
		return; 
 
	HRESULT hr; 
 
	hr = m_pVideoWindow->put_FullScreenMode((bFullScreen) ? OATRUE : OAFALSE); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to switch to full screen mode\n"); 
	}	 
} 
 
BOOL CFastPlayerDoc::IsInFullScreenMode() 
{ 
	if (m_currentStatus == statusEmpty) 
		return FALSE; 
 
	HRESULT hr; 
 
	long lFullScreenMode = OAFALSE; 
	hr = m_pVideoWindow->get_FullScreenMode(&lFullScreenMode); 
	if (FAILED(hr) || lFullScreenMode == OAFALSE) 
		return FALSE; 
	return TRUE; 
} 
 
BOOL CFastPlayerDoc::IsAudioMuted() 
{ 
	HRESULT hr; 
 
	if (!m_pBasicAudio) 
		return FALSE; 
 
	long lVolume = -10000; 
	hr = m_pBasicAudio->get_Volume(&lVolume); 
	if (FAILED(hr) || lVolume < -5000) 
		return TRUE; 
	return FALSE; 
} 
 
void CFastPlayerDoc::LoadDefaultSettings() 
{ 
	CWinApp *pApp = AfxGetApp(); 
	m_bFixAC3 = pApp->GetProfileInt("Settings", "Fix AC3 Sync", 0); 
	m_bUseWaveOut = pApp->GetProfileInt("Settings", "Use WaveOut", 0); 
	m_nVolume = pApp->GetProfileInt("Settings", "Default Volume Level", 0); 
} 
 
void CFastPlayerDoc::WriteDefaultSettings() 
{ 
	CWinApp *pApp = AfxGetApp(); 
	pApp->WriteProfileInt("Settings", "Fix AC3 Sync", m_bFixAC3); 
	pApp->WriteProfileInt("Settings", "Use WaveOut", m_bUseWaveOut); 
	pApp->WriteProfileInt("Settings", "Default Volume Level", m_nVolume); 
} 
 
void CFastPlayerDoc::ShowOptionsDialog() 
{ 
	COptionsDlg dlg; 
	dlg.m_bFixAC3 = m_bFixAC3; 
	dlg.m_bUseWaveOut = m_bUseWaveOut; 
 
	if (dlg.DoModal() == IDOK) 
	{ 
		if (dlg.m_bFixAC3 != m_bFixAC3 ||  
			dlg.m_bUseWaveOut != m_bUseWaveOut) 
		{ 
			m_bFixAC3 = dlg.m_bFixAC3; 
			m_bUseWaveOut = dlg.m_bUseWaveOut; 
			if (m_currentStatus != statusEmpty) 
				AfxMessageBox("In order to apply changes you will need to reload the video file", MB_ICONINFORMATION); 
			WriteDefaultSettings(); 
		} 
 
	} 
} 
 
void CFastPlayerDoc::ShowFilters() 
{ 
	HRESULT hr; 
 
	if (!m_pFilters) 
	{ 
		m_pFilters = new CFiltersDlg; 
		m_pFilters->Create(CFiltersDlg::IDD); 
		m_pFilters->m_pDocument = this; 
	} 
 
		// Delete all filters in the list 
	m_pFilters->m_lstFilters.ResetContent(); 
	 
	// Enumerate the graph filters 
	IEnumFilters *pEnum = NULL; 
	hr = m_pGraphBuilder->EnumFilters(&pEnum); 
	if (FAILED(hr)) 
		return; 
	 
	pEnum->Reset(); 
	ULONG cFilters = 1; 
	ULONG cFetched = 1; 
	hr = S_OK; 
	while (SUCCEEDED(hr) && cFetched) 
	{ 
		IBaseFilter *pFilter = NULL; 
		hr = pEnum->Next(cFilters, &pFilter, &cFetched); 
		if (SUCCEEDED(hr) && cFetched) 
		{ 
			// Verify if the filter has a property page 
			ISpecifyPropertyPages *pSpecify; 
			hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify); 
			if (SUCCEEDED(hr)) 
			{ 
				FILTER_INFO info; 
				pFilter->QueryFilterInfo(&info); 
				CString strName = info.achName; 
				// Insert the filter name into the dialog list 
				m_pFilters->m_lstFilters.AddString(strName); 
				pSpecify->Release(); 
			} 
 
 
			pFilter->Release(); 
		} 
	} 
	pEnum->Release(); 
 
	m_pFilters->ShowWindow(SW_SHOW); 
	 
} 
 
void CFastPlayerDoc::ShowFilterProperties(const CString &strFilterName) 
{ 
	HRESULT hr; 
 
	// Find the filter in the graph 
	IBaseFilter *pFilter = NULL; 
    WCHAR wFilter[MAX_PATH]; 
    MultiByteToWideChar(CP_ACP, 0, strFilterName, -1, wFilter, MAX_PATH); 
	 
 
	hr = m_pGraphBuilder->FindFilterByName(wFilter, &pFilter); 
	if (FAILED(hr)) 
	{ 
		TRACE0("Failed to locate the filter in the graph\n"); 
		return; 
	} 
 
    // Show the page.  
	ISpecifyPropertyPages *pSpecify; 
	hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify); 
	if (FAILED(hr))  
	{ 
		TRACE0("The filter does not have properties\n"); 
		pFilter->Release(); 
		return; 
	} 
 
	// Ask for the property pages 
	CAUUID caGUID; 
	pSpecify->GetPages(&caGUID); 
	pSpecify->Release(); 
 
	OleCreatePropertyFrame(NULL,  
						   0, 
						   0, 
						   strFilterName.AllocSysString(), 
						   1, 
						   (IUnknown **)&pFilter, 
						   caGUID.cElems, 
						   caGUID.pElems, 
						   0, 
						   0, 
						   NULL); 
	pSpecify->Release(); 
	pFilter->Release(); 
 
}