// CHDPlayerCore.h
#ifndef __CHDPlayerCore_h__
#define __CHDPlayerCore_h__
#include <DShow.h>
#include <D3D9.h>
#include <vmr9.h>
#include "dshowutil.h"
// Filter graph notification to the specified window
#define WM_GRAPHNOTIFY (WM_USER+20)
class CHDPlayerCore
{
public:
CHDPlayerCore(void);
virtual ~CHDPlayerCore(void);
public:
HRESULT CreateGraph(HWND hWnd);
HRESULT RenderMovieFile(const wchar_t * file, bool bRenderAudio);
bool RunMovies(void);
bool StopMovies(void);
bool PauseMovies(void);
HRESULT GetNativeMovieSize(CRect & pos);
HRESULT SetMoviePosition(CRect & pos);
HRESULT GetMoviePosotion(CRect & pos);
// IMediaSeeking
HRESULT GetCurrentPosition(double * outPosition);
HRESULT GetStopPosition(double * outPosition);
HRESULT SetCurrentPosition(double inPosition);
HRESULT SetStartStopPosition(double inStart, double inStop);
HRESULT GetDuration(double * outDuration);
HRESULT SetPlaybackRate(double inRate);
HRESULT SetNotifyWindow(HWND inWindows);
void HandleEvent(WPARAM wParam, LPARAM lParam);
IMediaEventEx * GetEventHandle() const;
OAFilterState GetCurrentState();
private:
inline void SafeRelease(IUnknown * filter)
{
if (NULL != filter)
{
filter->Release();
filter = NULL;
}
}
HRESULT GetInterface();
HRESULT UsedVideoMixingRenderer9();
BOOL IsWindowsMediaFile(const WCHAR *lpszFile);
HRESULT GetUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin);
HRESULT RenderMoivesToVMR9(IGraphBuilder * pGB, const WCHAR * wFileName, BOOL bRenderAudio);
HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister);
void RemoveFromRot(DWORD pdwRegister);
void ShowMsg(TCHAR *szFormat, ...);
IBaseFilter* CreateEncodec(CString inFriendlyName);
HRESULT CreateFilter(REFCLSID clsid, IBaseFilter **ppFilter);
private:
IGraphBuilder * pGraphBuilder;
IMediaControl * pMediaControl;
IMediaSeeking * pMediaSeeking;
IMediaEventEx * pMediaEventEx;
IBaseFilter * pVMR9;
IVMRWindowlessControl9 * pVMR9Control;
DWORD dwRegister;
HWND mPlayerHandle;
};
#endif // __CHDPlayerCore_h__
//
// CHDPlayerCore.cpp
#include "StdAfx.h"
#include "HDPlayerCore.h"
CHDPlayerCore::CHDPlayerCore(void)
{
pGraphBuilder = NULL;
pMediaControl = NULL;
pMediaSeeking = NULL;
pVMR9Control = NULL;
pMediaEventEx = NULL;
pVMR9 = NULL;
}
CHDPlayerCore::~CHDPlayerCore(void)
{
#ifdef _DEBUG
RemoveFromRot(dwRegister);
#endif
SafeRelease(pMediaSeeking);
SafeRelease(pMediaControl);
SafeRelease(pVMR9Control);
SafeRelease(pMediaEventEx);
SafeRelease(pVMR9);
SafeRelease(pGraphBuilder);
CoUninitialize();
}
HRESULT CHDPlayerCore::CreateGraph(HWND hWnd)
{
HRESULT hr = NOERROR;
mPlayerHandle = hWnd;
if(S_OK != CoInitializeEx(NULL,COINIT_APARTMENTTHREADED))
{
return E_FAIL;
}
if (NULL == pGraphBuilder)
{
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraphBuilder);
if (SUCCEEDED(hr))
{
hr |= pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
hr |= pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&pMediaSeeking);
hr |= pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&pMediaEventEx);
if (FAILED(hr))
{
return hr;
}
}
}
UsedVideoMixingRenderer9();
return hr;
}
HRESULT CHDPlayerCore::RenderMovieFile(const wchar_t * file, bool bRenderAudio)
{
if (NULL != file)
{
if (NULL == pGraphBuilder)
{
MessageBox(NULL, L"The IGraphBuilder is NULL", L"Error Information", S_OK);
}
HRESULT hr = RenderMoivesToVMR9(pGraphBuilder, file, bRenderAudio);
CRect rc;
SetRect(&rc, 0, 0, 0, 0);
hr |= GetNativeMovieSize(rc);
hr |= SetMoviePosition(rc);
if (SUCCEEDED(hr))
{
return hr;
}
}
#ifdef _DEBUG
AddToRot(pGraphBuilder, &dwRegister);
#endif
return E_FAIL;
}
bool CHDPlayerCore::RunMovies()
{
if (NULL != pGraphBuilder && NULL != pMediaControl)
{
if (State_Paused == GetCurrentState() || State_Stopped == GetCurrentState())
{
if (SUCCEEDED(pMediaControl->Run()))
{
return true;
}
else
{
return false;
}
}
}
return false;
}
bool CHDPlayerCore::StopMovies()
{
if (NULL != pGraphBuilder && NULL != pMediaControl)
{
if (State_Running == GetCurrentState())
{
if (SUCCEEDED(pMediaControl->Stop()))
{
return true;
}
else
{
return false;
}
}
}
return false;
}
bool CHDPlayerCore::PauseMovies()
{
if (NULL != pGraphBuilder && NULL != pMediaControl)
{
if (State_Running == GetCurrentState())
{
if (SUCCEEDED(pMediaControl->Pause()))
{
return true;
}
else
{
return false;
}
}
}
return false;
}
HRESULT CHDPlayerCore::GetNativeMovieSize(CRect & pos)
{
HRESULT hr = NOERROR;
if (NULL != pVMR9Control)
{
hr = pVMR9Control->GetNativeVideoSize(&pos.right, &pos.bottom, NULL, NULL);
if (SUCCEEDED(hr))
{
return hr;
}
SetRect(&pos, 0, 0, 0, 0);
}
return E_FAIL;
}
HRESULT CHDPlayerCore::GetMoviePosotion(CRect & pos)
{
HRESULT hr = NOERROR;
CRect src;
if (NULL != pVMR9Control)
{
hr = pVMR9Control->GetVideoPosition(&src, &pos);
if (SUCCEEDED(hr))
{
return hr;
}
SetRect(&pos, 0, 0, 0, 0);
}
return E_FAIL;
}
HRESULT CHDPlayerCore::SetMoviePosition(CRect & pos)
{
HRESULT hr = NOERROR;
if (NULL != pVMR9Control)
{
hr = pVMR9Control->SetVideoPosition(NULL, &pos);
if (SUCCEEDED(hr))
{
return hr;
}
}
return E_FAIL;
}
HRESULT CHDPlayerCore::GetCurrentPosition(double * outPosition)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
__int64 position = (__int64)0.0;
hr = pMediaSeeking->GetCurrentPosition(&position);
if (SUCCEEDED(hr))
{
*outPosition = ((double)position) / 10000000.0;
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::GetStopPosition(double *outPosition)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
__int64 position = (__int64)0.0;
hr = pMediaSeeking->GetStopPosition(&position);
if (SUCCEEDED(hr))
{
*outPosition = ((double)position) / 10000000.0;
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::SetCurrentPosition(double inPosition)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
__int64 position = (__int64)(10000000 * inPosition);
hr = pMediaSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning |
AM_SEEKING_SeekToKeyFrame, 0, AM_SEEKING_NoPositioning);
if (SUCCEEDED(hr))
{
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::SetStartStopPosition(double inStart, double inStop)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
__int64 start = (__int64)(10000000 * inStart);
__int64 stop = (__int64)(10000000 * inStop);
hr = pMediaSeeking->SetPositions(&start, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame,
&stop, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame);
if (SUCCEEDED(hr))
{
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::GetDuration(double * outDuration)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
__int64 length = (__int64)0.0;
hr = pMediaSeeking->GetDuration(&length);
if (SUCCEEDED(hr))
{
*outDuration = ((double)length / 10000000.0);
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::SetPlaybackRate(double inRate)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaSeeking)
{
hr = pMediaSeeking->SetRate(inRate);
if (SUCCEEDED(hr))
{
return hr;
}
}
return hr;
}
HRESULT CHDPlayerCore::SetNotifyWindow(HWND inWindows)
{
HRESULT hr = E_FAIL;
if (NULL != pMediaEventEx)
{
hr = pMediaEventEx->SetNotifyWindow((OAHWND)inWindows, WM_GRAPHNOTIFY, 0);
if (SUCCEEDED(hr))
{
return hr;
}
}
return hr;
}
void CHDPlayerCore::HandleEvent(WPARAM wParam, LPARAM lParam)
{
if (NULL != pMediaEventEx)
{
LONG eventCode = 0;
LONG_PTR eventParam1 = 0;
LONG_PTR eventParam2 = 0;
while(SUCCEEDED(pMediaEventEx->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
{
pMediaEventEx->FreeEventParams(eventCode, eventParam1, eventParam2);
switch (eventCode)
{
case EC_COMPLETE:
break;
case EC_USERABORT:
case EC_ERRORABORT:
break;
default:
break;
}
}
}
}
IMediaEventEx * CHDPlayerCore::GetEventHandle() const
{
if (NULL != pMediaEventEx)
{
return pMediaEventEx;
}
return NULL;
}
HRESULT CHDPlayerCore::UsedVideoMixingRenderer9()
{
HRESULT hr = NOERROR;
hr |= CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void **)&pVMR9);
if (SUCCEEDED(hr))
{
hr |= pGraphBuilder->AddFilter(pVMR9, L"Video Mixing Render 9");
if (SUCCEEDED(hr))
{
IVMRFilterConfig9 * pConfig9 = NULL;
hr |= pVMR9->QueryInterface(IID_IVMRFilterConfig9, (void **)&pConfig9);
if (SUCCEEDED(hr))
{
hr |= pConfig9->SetNumberOfStreams(2);
hr |= pConfig9->SetRenderingMode(VMR9Mode_Windowless);
hr |= pConfig9->SetRenderingPrefs(RenderPrefs_AllowOverlays);
pConfig9->Release();
}
pConfig9 = NULL;
IVMRMonitorConfig9 * pMonitorConfig = NULL;
hr |= pVMR9->QueryInterface(IID_IVMRMonitorConfig9, (void **)&pMonitorConfig);
if(SUCCEEDED(hr))
{
UINT iCurrentMonitor;
hr |= pMonitorConfig->GetMonitor(&iCurrentMonitor);
pMonitorConfig->Release();
}
pMonitorConfig = NULL;
hr |= pVMR9->QueryInterface(IID_IVMRWindowlessControl9, (void **)&pVMR9Control);
}
}
SafeRelease(pVMR9);
if (SUCCEEDED(hr))
{
hr |= pVMR9Control->SetVideoClippingWindow(mPlayerHandle);
hr |= pVMR9Control->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX);
}
else
{
SafeRelease(pVMR9Control);
}
return hr;
}
HRESULT CHDPlayerCore::RenderMoivesToVMR9(IGraphBuilder * pGB, const WCHAR * wFileName, BOOL bRenderAudio = TRUE)
{
HRESULT hr = NOERROR;
CComPtr <IPin> pOutputPin;
CComPtr <IPin> pInputPin;
CComPtr <IBaseFilter> pSource;
CComPtr <IBaseFilter> pAudioRenderer;
CComPtr <IFilterGraph2> pFG;
CComPtr <IFileSourceFilter> pFileSource;
// Render audio if requested (defaults to TRUE)
if (bRenderAudio)
{
// Because we will be rendering with the RENDERTOEXISTINGRENDERERS flag,
// we need to create an audio renderer and add it to the graph.
// Create an instance of the DirectSound renderer (for each media file).
//
// Note that if the system has no sound card (or if the card is disabled),
// then creating the DirectShow renderer will fail. In that case,
// handle the failure quietly.
if (SUCCEEDED(CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)&pAudioRenderer)))
{
// The audio renderer was successfully created, so add it to the graph
hr |= pGB->AddFilter(pAudioRenderer, L"Audio Renderer");
if (FAILED(hr))
{
return hr;
}
}
}
// Add a file source filter for this media file
if (!IsWindowsMediaFile(wFileName))
{
// Add the source filter to the graph
if (FAILED(hr |= pGB->AddSourceFilter(wFileName, L"SOURCE", &pSource)))
{
USES_CONVERSION;
WCHAR szMsg[MAX_PATH + 128] = {0};
hr = StringCchPrintf(szMsg, NUMELMS(szMsg), TEXT("Failed to add the source filter to the graph! hr=0x%x/r/n/r/n")
TEXT("Filename: %s/0"), hr, wFileName);
MessageBox(NULL, szMsg, TEXT("Failed to render file to VMR9"), MB_OK | MB_ICONERROR);
return hr;
}
hr |= GetUnconnectedPin(pSource, PINDIR_OUTPUT, &pOutputPin);
if (FAILED(hr))
{
return hr;
}
// Get an IFilterGraph2 interface to assist in building the
// multifile graph with the non-default VMR9 renderer
hr |= pGB->QueryInterface(IID_IFilterGraph2, (void **)&pFG);
if (FAILED(hr))
{
return hr;
}
// Render the output pin, using the VMR9 as the specified renderer. This is
// necessary in case the GraphBuilder needs to insert a Color Space convertor,
// or if multiple filters insist on using multiple allocators.
// The audio renderer will also be used, if the media file contains audio.
hr |= pFG->RenderEx(pOutputPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr))
{
return hr;
}
// If this media file does not contain an audio stream, then the
// audio renderer that we created will be unconnected. If left in the
// graph, it could interfere with rate changes and timing.
// Therefore, if the audio renderer is unconnected, remove it from the graph.
if (pAudioRenderer != NULL)
{
IPin *pUnconnectedPin=0;
// Is the audio renderer's input pin connected?
HRESULT hrPin = GetUnconnectedPin(pAudioRenderer, PINDIR_INPUT, &pUnconnectedPin);
// If there is an unconnected pin, then remove the unused filter
if (SUCCEEDED(hrPin) && (pUnconnectedPin != NULL))
{
// Release the returned IPin interface
pUnconnectedPin->Release();
// Remove the audio renderer from the graph
hrPin = pGB->RemoveFilter(pAudioRenderer);
}
}
}
else
{
// Load the improved ASF reader filter by CLSID
hr |= CreateFilter(CLSID_WMAsfReader, &pSource);
if(FAILED(hr))
{
ShowMsg(TEXT("Failed to create WMAsfWriter filter! hr=0x%x/0"), hr);
return hr;
}
// Add the ASF reader filter to the graph. For ASF/WMV/WMA content,
// this filter is NOT the default and must be added explicitly.
hr |= pGB->AddFilter(pSource, L"WMV ASF Reader");
if(FAILED(hr))
{
ShowMsg(TEXT("Failed to add ASF reader filter to graph! hr=0x%x/0"), hr);
return hr;
}
// Set its source filename
hr |= pSource->QueryInterface(IID_IFileSourceFilter, (void **) &pFileSource);
// Attempt to load this file
hr |= pFileSource->Load(wFileName, NULL);
if (FAILED(hr))
{
ShowMsg(TEXT("Failed to load file in source filter (pFileSource->Load())! hr=0x%x/0"), hr);
return hr;
}
ULONG count = 0;
CountTotalFilterPins(pSource, &count);
for (ULONG i = 0; i < count; i ++)
{
pOutputPin = GetOutPin(pSource, i);
PIN_INFO info;
pOutputPin->QueryPinInfo(&info);
CComPtr<IBaseFilter> Codec;
if (_tcsstr(info.achName, TEXT("Video")))
{
Codec = CreateEncodec(_T("WMVideo Decoder DMO"));
if (NULL != pGraphBuilder)
{
pGraphBuilder->AddFilter(Codec, _T("WMVideo Decoder DMO"));
pInputPin = GetInPin(Codec, 0);
hr |= pGraphBuilder->Connect(pOutputPin, pInputPin);
if (FAILED(hr))
{
ShowMsg(_T("Video Connected Failed. hr=0x%x/0"), hr);
return hr;
}
pOutputPin = GetOutPin(Codec, 0);
pInputPin = GetInPin(pVMR9, 0);
hr |= pGraphBuilder->Connect(pOutputPin, pInputPin);
if (FAILED(hr))
{
ShowMsg(_T("Video Connected Failed. hr=0x%x/0"), hr);
return hr;
}
}
}
else if (_tcsstr(info.achName, TEXT("Audio")))
{
Codec = CreateEncodec(_T("WMAudio Decoder DMO"));
if (NULL != pGraphBuilder)
{
pGraphBuilder->AddFilter(Codec, _T("WMAudio Decoder DMO"));
pInputPin = GetInPin(Codec, 0);
hr |= pGraphBuilder->Connect(pOutputPin, pInputPin);
if (FAILED(hr))
{
ShowMsg(_T("Audio Connected Failed. hr=0x%x/0"), hr);
return hr;
}
pOutputPin = GetOutPin(Codec, 0);
if (NULL == pAudioRenderer)
{
if (SUCCEEDED(CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)&pAudioRenderer)))
{
// The audio renderer was successfully created, so add it to the graph
hr |= pGB->AddFilter(pAudioRenderer, L"Audio Renderer");
if (FAILED(hr))
{
return hr;
}
}
}
pInputPin = GetInPin(pAudioRenderer, 0);
hr |= pGraphBuilder->Connect(pOutputPin, pInputPin);
if (FAILED(hr))
{
ShowMsg(_T("Audio Connected Failed. hr=0x%x/0"), hr);
return hr;
}
}
}
}
}
return hr;
}
BOOL CHDPlayerCore::IsWindowsMediaFile(const WCHAR *lpszFile)
{
USES_CONVERSION;
WCHAR szFilename[MAX_PATH] = {0};
// Copy the file name to a local string and convert to lowercase
(void)StringCchCopy(szFilename,NUMELMS(szFilename), lpszFile);
szFilename[MAX_PATH-1] = 0;
_tcslwr_s(szFilename, 260);
if (_tcsstr(szFilename, TEXT(".asf")) ||
_tcsstr(szFilename, TEXT(".wma")) ||
_tcsstr(szFilename, TEXT(".wmv")))
{
return TRUE;
}
else
{
return FALSE;
}
}
OAFilterState CHDPlayerCore::GetCurrentState()
{
OAFilterState states = 0;
if (NULL != pGraphBuilder && NULL != pMediaControl)
{
pMediaControl->GetState(INFINITE, &states);
}
return states;
}
//Register the filter graph to Rot
HRESULT CHDPlayerCore::AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
HRESULT hr = NOERROR;
IMoniker * pMoniker = NULL;
IRunningObjectTable * pROT = NULL;
if(FAILED(GetRunningObjectTable(0,&pROT)))
{
return E_FAIL;
}
WCHAR wsz[256];
::memset(wsz,0,256);
hr = StringCchPrintfW(wsz, NUMELMS(wsz), L"FilterGraph %08x pid %08x",
(DWORD_PTR)pUnkGraph,GetCurrentProcessId());
hr = CreateItemMoniker(L"!",wsz,&pMoniker);
if(SUCCEEDED(hr))
{
hr = pROT->Register(0,pUnkGraph,pMoniker,pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}
void CHDPlayerCore::RemoveFromRot(DWORD pdwRegister)
{
IRunningObjectTable *pROT = NULL;
if(SUCCEEDED(GetRunningObjectTable(0,&pROT)))
{
pROT->Revoke(pdwRegister);
pROT->Release();
}
}
HRESULT CHDPlayerCore::GetUnconnectedPin(
IBaseFilter *pFilter, // Pointer to the filter.
PIN_DIRECTION PinDir, // Direction of the pin to find.
IPin **ppPin) // Receives a pointer to the pin.
{
IEnumPins *pEnum = 0;
IPin *pPin = 0;
if (!ppPin)
return E_POINTER;
*ppPin = 0;
// Get a pin enumerator
HRESULT hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
return hr;
// Look for the first unconnected pin
while (pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if (ThisPinDir == PinDir)
{
IPin *pTmp = 0;
hr = pPin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr)) // Already connected, not the pin we want.
{
pTmp->Release();
}
else // Unconnected, this is the pin we want.
{
pEnum->Release();
*ppPin = pPin;
return S_OK;
}
}
pPin->Release();
}
// Release the enumerator
pEnum->Release();
// Did not find a matching pin
return E_FAIL;
}
IBaseFilter* CHDPlayerCore::CreateEncodec(CString inFriendlyName)
{
HRESULT hr = NOERROR;
ICreateDevEnum * enumHardware =NULL;
IBaseFilter * hardwareFilter = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,(void **)&enumHardware);
if(FAILED(hr))
{
return NULL;
}
IEnumMoniker * enumMoniker = NULL;
hr = enumHardware->CreateClassEnumerator(CLSID_LegacyAmFilterCategory, &enumMoniker,0);
if(FAILED(hr))
{
return NULL;
}
if(enumMoniker)
{
enumMoniker->Reset();
IMoniker * moniker = NULL;
char friendlyName[256];
ZeroMemory(friendlyName,256);
while(S_OK == enumMoniker->Next(1,&moniker,0))
{
if(moniker)
{
IPropertyBag * proBag = NULL;
VARIANT name;
hr = moniker->BindToStorage(NULL,NULL,IID_IPropertyBag,(void **)&proBag);
if(SUCCEEDED(hr))
{
name.vt = VT_BSTR;
proBag->Read(L"FriendlyName",&name,NULL);
}
if(SUCCEEDED(hr))
{
WideCharToMultiByte(CP_ACP, 0, name.bstrVal, -1,friendlyName, 256,
NULL, NULL);
CString str = (CString)friendlyName;
if(inFriendlyName == str)
{
moniker->BindToObject(NULL,NULL,IID_IBaseFilter,
(void **)&hardwareFilter);
}
}
if(proBag)
{
proBag->Release();
proBag = NULL;
}
moniker->Release();
}
}
enumMoniker->Release();
}
enumHardware->Release();
return hardwareFilter;
}
HRESULT CHDPlayerCore::CreateFilter(REFCLSID clsid, IBaseFilter **ppFilter)
{
HRESULT hr;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void **) ppFilter);
if(FAILED(hr))
{
//MessageBox(TEXT("CreateFilter: Failed to create filter! hr=0x%x/n"));
if (ppFilter)
*ppFilter = NULL;
return hr;
}
return S_OK;
}
void CHDPlayerCore::ShowMsg(TCHAR *szFormat, ...)
{
TCHAR szBuffer[1024]; // Large buffer for long filenames or URLs
const size_t NUMCHARS = sizeof(szBuffer) / sizeof(szBuffer[0]);
const int LASTCHAR = NUMCHARS - 1;
// Format the input string
va_list pArgs;
va_start(pArgs, szFormat);
// Use a bounded buffer size to prevent buffer overruns. Limit count to
// character size minus one to allow for a NULL terminating character.
(void)StringCchVPrintf(szBuffer, NUMCHARS - 1, szFormat, pArgs);
va_end(pArgs);
// Ensure that the formatted string is NULL-terminated
szBuffer[LASTCHAR] = TEXT('/0');
// Display a message box with the formatted string
MessageBox(NULL, szBuffer, TEXT("Porsche HD Player"), MB_OK);
}
if (NULL == this->player)
{
this->player = new CHDPlayerCore();
}
this->player->CreateGraph(this->playerDlg->GetSafeHwnd());
this->player->RenderMovieFile(filePaths, true);
this->player->SetNotifyWindow(this->GetSafeHwnd());
this->player->SetStartStopPosition(0, 117.006);
this->player->RunMovies();