www.pudn.com > fastplayer-0.1.zip > FastPlayerDoc.cpp
// 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();
}