Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1118 lines
33 KiB
C++
1118 lines
33 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: VidPlay.cpp
|
|
//
|
|
// Desc: DirectShow sample code - video (DVD and file) playback class.
|
|
//
|
|
// Copyright (c) 1993-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
#include <streams.h>
|
|
#include <windows.h>
|
|
|
|
#include "mpconfig.h"
|
|
#include "VidPlay.h"
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer constructor
|
|
//
|
|
CBaseVideoPlayer::CBaseVideoPlayer()
|
|
{
|
|
m_eState = Uninitialized ;
|
|
ZeroMemory(m_achFileName, sizeof(m_achFileName)) ;
|
|
|
|
m_pGraph = NULL ;
|
|
m_pMC = NULL ;
|
|
m_pME = NULL ;
|
|
|
|
m_dwColorKey = 253 ; // magenta by default
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer destructor
|
|
//
|
|
CBaseVideoPlayer::~CBaseVideoPlayer()
|
|
{
|
|
ReleaseInterfaces() ;
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::GetInterfaces(): Gets the standard interfaces required for
|
|
// playing back through a filter graph
|
|
//
|
|
HRESULT CBaseVideoPlayer::GetInterfaces(HWND hWndApp)
|
|
{
|
|
HRESULT hr ;
|
|
hr = m_pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&m_pMC) ;
|
|
ASSERT(SUCCEEDED(hr) && m_pMC) ;
|
|
|
|
hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (LPVOID *)&m_pME) ;
|
|
ASSERT(SUCCEEDED(hr) && m_pME) ;
|
|
|
|
//
|
|
// Also set up the event notification so that the main window gets
|
|
// informed about all that we care about during playback.
|
|
//
|
|
hr = m_pME->SetNotifyWindow((OAHWND) hWndApp, WM_PLAY_EVENT, (LONG_PTR) m_pME) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
|
|
m_eState = Stopped ; // graph has been built
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::ReleaseInterfaces(): Let go of the standard interfaces taken for playback.
|
|
//
|
|
void CBaseVideoPlayer::ReleaseInterfaces(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::ReleaseInterfaces() entered"))) ;
|
|
|
|
if (m_pMC) {
|
|
m_pMC->Release() ;
|
|
m_pMC = NULL ;
|
|
}
|
|
if (m_pME) {
|
|
// clear any already set notification arrangement
|
|
m_pME->SetNotifyWindow(NULL, WM_PLAY_EVENT, (LONG_PTR) m_pME) ;
|
|
m_pME->Release() ;
|
|
m_pME = NULL ;
|
|
}
|
|
|
|
m_eState = Uninitialized ; // no graph available
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::WaitForState(): Wait for the state to change to the given one.
|
|
//
|
|
void CBaseVideoPlayer::WaitForState(FILTER_STATE State)
|
|
{
|
|
// Make sure we have switched to the required state
|
|
LONG lfs ;
|
|
do
|
|
{
|
|
m_pMC->GetState(10, &lfs) ;
|
|
} while (State != lfs) ;
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::Play(): Plays the filter graph (and waits to really start playing)
|
|
//
|
|
BOOL CBaseVideoPlayer::Play(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Play() entered"))) ;
|
|
|
|
if (! IsGraphReady() )
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
|
|
return FALSE ;
|
|
}
|
|
HRESULT hr = m_pMC->Run() ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Run() failed (Error 0x%lx)"), hr)) ;
|
|
return FALSE ;
|
|
}
|
|
WaitForState(State_Running) ;
|
|
|
|
// Some state changes now
|
|
m_eState = Playing ;
|
|
|
|
return TRUE ; // success
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::Pause(): Pauses/Cues the filter graph (and waits to really pause)
|
|
//
|
|
BOOL CBaseVideoPlayer::Pause(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Pause() entered"))) ;
|
|
|
|
if (! IsGraphReady() )
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
|
|
return FALSE ;
|
|
}
|
|
HRESULT hr = m_pMC->Pause() ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Pause() failed (Error 0x%lx)"), hr)) ;
|
|
return FALSE ;
|
|
}
|
|
WaitForState(State_Paused) ;
|
|
|
|
// Some state changes now
|
|
m_eState = Paused ;
|
|
|
|
return TRUE ; // success
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::Stop(): Stops the filter graph (and waits to really stop)
|
|
//
|
|
BOOL CBaseVideoPlayer::Stop(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::Stop() entered"))) ;
|
|
|
|
if (! IsGraphReady() )
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("DVD-Video playback graph hasn't been built yet"))) ;
|
|
return FALSE ;
|
|
}
|
|
HRESULT hr = m_pMC->Stop() ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Stop() failed (Error 0x%lx)"), hr)) ;
|
|
return FALSE ;
|
|
}
|
|
WaitForState(State_Stopped) ;
|
|
|
|
// Some state changes now
|
|
m_eState = Stopped ;
|
|
|
|
return TRUE ; // success
|
|
}
|
|
|
|
|
|
//
|
|
// CBaseVideoPlayer::GetColorKey(): Returns color key to the app so that other
|
|
// components (here the DDraw object) can be told about it.
|
|
//
|
|
HRESULT CBaseVideoPlayer::GetColorKey(DWORD *pdwColorKey)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CBaseVideoPlayer::GetColorKey() entered"))) ;
|
|
|
|
if (! IsGraphReady() )
|
|
return E_UNEXPECTED ;
|
|
|
|
*pdwColorKey = m_dwColorKey ; // use the cached color key info
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CDVDPlayer constructor
|
|
//
|
|
CDVDPlayer::CDVDPlayer()
|
|
{
|
|
DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer c-tor entered"))) ;
|
|
|
|
m_pDvdGB = NULL ;
|
|
m_pDvdC = NULL ;
|
|
m_pDvdI = NULL ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer destructor
|
|
//
|
|
CDVDPlayer::~CDVDPlayer()
|
|
{
|
|
DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer d-tor entered"))) ;
|
|
|
|
ReleaseInterfaces() ;
|
|
|
|
if (m_pDvdGB)
|
|
m_pDvdGB->Release() ;
|
|
|
|
DbgLog((LOG_TRACE, 3, TEXT("CDVDPlayer d-tor exiting..."))) ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::Initialize(): Creates a DVD graph builder object for later building
|
|
// a filter graph.
|
|
//
|
|
BOOL CDVDPlayer::Initialize(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::Initialize() entered"))) ;
|
|
|
|
//
|
|
// Now instantiate the DVD Graph Builder object and start working
|
|
//
|
|
HRESULT hr = CoCreateInstance(CLSID_DvdGraphBuilder, NULL, CLSCTX_INPROC,
|
|
IID_IDvdGraphBuilder, (LPVOID *)&m_pDvdGB) ;
|
|
if (FAILED(hr) || NULL == m_pDvdGB)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: DirectShow DVD software not installed properly (Error 0x%lx)"), hr)) ;
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::BuildGraph(): Builds a filter graph for playing back the specified
|
|
// DVD title/file. Also gets some interfaces that are required for controlling
|
|
// playback.
|
|
//
|
|
HRESULT CDVDPlayer::BuildGraph(HWND hWndApp, LPDIRECTDRAW pDDObj, LPDIRECTDRAWSURFACE pDDPrimary)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::BuildGraph() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
|
|
// First release any existing interface pointer(s)
|
|
ReleaseInterfaces() ;
|
|
SetColorKey(253) ; // default magenta for 8bpp
|
|
|
|
// Check if a DVD-Video volume name has been specified; if so, use that
|
|
WCHAR achwFileName[MAX_PATH] ;
|
|
LPCWSTR lpszwFileName = NULL ; // by default
|
|
if (lstrlen(GetFileName()) > 0) // if something was specified before
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(achwFileName, GetFileName()) ;
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, GetFileName(), -1, achwFileName, MAX_PATH) ;
|
|
#endif // UNICODE
|
|
|
|
lpszwFileName = achwFileName ;
|
|
}
|
|
DbgLog((LOG_TRACE, 5, TEXT("DVD file <%s> will be played"), GetFileName())) ;
|
|
|
|
// Set DDraw object and surface on DVD graph builder before starting to build graph
|
|
IDDrawExclModeVideo *pDDXMV ;
|
|
hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
|
|
if (FAILED(hr) || NULL == pDDXMV)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
|
|
return hr ;
|
|
}
|
|
hr = pDDXMV->SetDDrawObject(pDDObj) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetDDrawObject() failed (Error 0x%lx)"), hr)) ;
|
|
pDDXMV->Release() ; // release before returning
|
|
return hr ;
|
|
}
|
|
hr = pDDXMV->SetDDrawSurface(pDDPrimary) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetDDrawSurface() failed (Error 0x%lx)"), hr)) ;
|
|
pDDXMV->SetDDrawObject(NULL) ; // to reset
|
|
pDDXMV->Release() ; // release before returning
|
|
return hr ;
|
|
}
|
|
pDDXMV->Release() ; // done with the interface
|
|
|
|
// Build the graph
|
|
AM_DVD_RENDERSTATUS Status ;
|
|
TCHAR achBuffer[1000] ;
|
|
hr = m_pDvdGB->RenderDvdVideoVolume(lpszwFileName,
|
|
AM_DVD_HWDEC_PREFER, &Status) ;
|
|
if (FAILED(hr))
|
|
{
|
|
AMGetErrorText(hr, achBuffer, sizeof(achBuffer)/sizeof(achBuffer[0])) ;
|
|
MessageBox(hWndApp, achBuffer, TEXT("Error"), MB_OK) ;
|
|
return hr ;
|
|
}
|
|
if (S_FALSE == hr) // if partial success
|
|
{
|
|
if (0 == GetStatusText(&Status, achBuffer, sizeof(achBuffer)))
|
|
{
|
|
lstrcpy(achBuffer, TEXT("An unknown error has occurred")) ;
|
|
}
|
|
lstrcat(achBuffer, TEXT("\n\nDo you still want to continue?")) ;
|
|
if (IDNO == MessageBox(hWndApp, achBuffer, TEXT("Warning"), MB_YESNO))
|
|
{
|
|
return E_FAIL ;
|
|
}
|
|
}
|
|
|
|
GetInterfaces(hWndApp) ;
|
|
|
|
hr = GetColorKeyInternal() ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::GetInterfaces(): Gets some interfaces useful for DVD title playback
|
|
//
|
|
HRESULT CDVDPlayer::GetInterfaces(HWND hWndApp)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetInterfaces() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
hr = m_pDvdGB->GetFiltergraph(&m_pGraph) ;
|
|
ASSERT(SUCCEEDED(hr) && m_pGraph) ;
|
|
|
|
// Now get the DVD-specific interfaces (though we don't use them in this app).
|
|
hr = m_pDvdGB->GetDvdInterface(IID_IDvdControl2, (LPVOID *)&m_pDvdC) ;
|
|
ASSERT(SUCCEEDED(hr) && m_pDvdC) ;
|
|
|
|
hr = m_pDvdGB->GetDvdInterface(IID_IDvdInfo2, (LPVOID *)&m_pDvdI) ;
|
|
ASSERT(SUCCEEDED(hr) && m_pDvdI) ;
|
|
|
|
return CBaseVideoPlayer::GetInterfaces(hWndApp) ; // get the standard interfaces
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::ClearGraph(): Tears down the filter graph created by BuildGraph()
|
|
// and also releases the DVD graph builder object.
|
|
//
|
|
HRESULT CDVDPlayer::ClearGraph()
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::ClearGraph() entered"))) ;
|
|
|
|
ReleaseInterfaces() ; // let go of the other interfaces
|
|
if (m_pDvdGB)
|
|
{
|
|
m_pDvdGB->Release() ;
|
|
m_pDvdGB = NULL ;
|
|
}
|
|
|
|
return S_OK ;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::GetColorKeyInternal(): Retrieves color key and stores it for later
|
|
// queries from the app.
|
|
//
|
|
HRESULT CDVDPlayer::GetColorKeyInternal(IBaseFilter *pOvM /* = NULL */)
|
|
{
|
|
ASSERT(NULL == pOvM) ; // we don't need pOvM passed in
|
|
|
|
// Get color key from MixerPinConfig interface via IDvdGraphBuilder
|
|
IMixerPinConfig2 *pMPC ;
|
|
DWORD dwColorKey ;
|
|
HRESULT hr = m_pDvdGB->GetDvdInterface(IID_IMixerPinConfig2, (LPVOID *) &pMPC) ;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pMPC->GetColorKey(NULL, &dwColorKey) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
SetColorKey(dwColorKey) ;
|
|
|
|
// Set mode to stretch - that way we don't fight the overlay
|
|
// mixer about the exact way to fix the aspect ratio
|
|
pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED);
|
|
pMPC->Release() ;
|
|
}
|
|
else
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("WARNING: IDvdGraphBuilder::GetDvdInterface(IID_IMixerPinConfig2) failed (Error 0x%lx)"), hr)) ;
|
|
return hr ;
|
|
}
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::GetNativeVideoData(): Retrieves the original video size from OverlayMixer's
|
|
// IDDrawExclModeVideo interface.
|
|
//
|
|
HRESULT CDVDPlayer::GetNativeVideoData(DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwARX, DWORD *pdwARY)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetNativeVideoData() entered"))) ;
|
|
|
|
IDDrawExclModeVideo *pDDXMV ;
|
|
HRESULT hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
|
|
if (FAILED(hr) || NULL == pDDXMV)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
|
|
return hr ;
|
|
}
|
|
hr = pDDXMV->GetNativeVideoProps(pdwWidth, pdwHeight, pdwARX, pdwARY) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_TRACE, 1,
|
|
TEXT("WARNING: IDDrawExclModeVideo::GetNativeVideoProps() failed (Error 0x%lx)"), hr)) ;
|
|
}
|
|
|
|
pDDXMV->Release() ; // release before returning
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::SetVideoPosition(): Sets the source and destination rects on the
|
|
// OverlayMixer's IDDrawExclModeVideo interface .
|
|
//
|
|
HRESULT CDVDPlayer::SetVideoPosition(DWORD dwLeft, DWORD dwTop, DWORD dwWidth, DWORD dwHeight)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::SetVideoPosition() entered"))) ;
|
|
|
|
IDDrawExclModeVideo *pDDXMV ;
|
|
HRESULT hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
|
|
if (FAILED(hr) || NULL == pDDXMV)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
|
|
return hr ;
|
|
}
|
|
|
|
RECT rectDest ;
|
|
SetRect(&rectDest, dwLeft, dwTop, dwLeft + dwWidth, dwTop + dwHeight) ;
|
|
// NULL or (0, 0, 10000, 10000) for full video
|
|
hr = pDDXMV->SetDrawParameters(NULL, &rectDest) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_TRACE, 1,
|
|
TEXT("WARNING: IDDrawExclModeVideo::SetDrawParameters() failed (Error 0x%lx)"), hr)) ;
|
|
}
|
|
|
|
pDDXMV->Release() ; // release before returning
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::SetOverlayCallback(): Specify the pointer to the overlay notification
|
|
// callback object which the OverlayMixer will call during playback.
|
|
//
|
|
HRESULT CDVDPlayer::SetOverlayCallback(IDDrawExclModeVideoCallback *pCallback)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::SetOverlayCallback() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
IDDrawExclModeVideo *pDDXMV ;
|
|
hr = m_pDvdGB->GetDvdInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXMV) ;
|
|
if (FAILED(hr) || NULL == pDDXMV)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: IDvdGB::GetDvdInterface(IDDrawExclModeVideo) failed (Error 0x%lx)"), hr)) ;
|
|
return hr ;
|
|
}
|
|
hr = pDDXMV->SetCallbackInterface(pCallback, 0) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetCallbackInterface() failed (Error 0x%lx)"), hr)) ;
|
|
}
|
|
pDDXMV->Release() ; // done with the interface
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::ReleaseInterfaces(): Let go of the interfaces taken in BuildGraph()
|
|
//
|
|
void CDVDPlayer::ReleaseInterfaces(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::ReleaseInterfaces() entered"))) ;
|
|
|
|
if (m_pDvdC) {
|
|
m_pDvdC->Release() ;
|
|
m_pDvdC = NULL ;
|
|
}
|
|
if (m_pDvdI) {
|
|
m_pDvdI->Release() ;
|
|
m_pDvdI = NULL ;
|
|
}
|
|
if (m_pGraph) {
|
|
m_pGraph->Release() ;
|
|
m_pGraph = NULL ;
|
|
}
|
|
CBaseVideoPlayer::ReleaseInterfaces() ; // release stanadrd interfaces
|
|
}
|
|
|
|
|
|
//
|
|
// CDVDPlayer::GetStatusText(): Composes a status message on failure to build DVD graph.
|
|
//
|
|
DWORD CDVDPlayer::GetStatusText(AM_DVD_RENDERSTATUS *pStatus,
|
|
LPTSTR lpszStatusText,
|
|
DWORD dwMaxText)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CDVDPlayer::GetStatusText() entered"))) ;
|
|
|
|
TCHAR achBuffer[1000] ;
|
|
|
|
if (IsBadWritePtr(lpszStatusText, sizeof(*lpszStatusText) * dwMaxText))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("GetStatusText(): bad text buffer param"))) ;
|
|
return 0 ;
|
|
}
|
|
|
|
int iChars ;
|
|
LPTSTR lpszBuff = achBuffer ;
|
|
ZeroMemory(achBuffer, sizeof(TCHAR) * 1000) ;
|
|
if (pStatus->iNumStreamsFailed > 0)
|
|
{
|
|
iChars = wsprintf(lpszBuff,
|
|
TEXT("* %d out of %d DVD-Video streams failed to render properly\n"),
|
|
pStatus->iNumStreamsFailed, pStatus->iNumStreams) ;
|
|
lpszBuff += iChars ;
|
|
|
|
if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_VIDEO)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT(" - video stream\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_AUDIO)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT(" - audio stream\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_SUBPIC)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT(" - subpicture stream\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
}
|
|
|
|
if (FAILED(pStatus->hrVPEStatus))
|
|
{
|
|
lstrcat(lpszBuff, TEXT("* ")) ;
|
|
lpszBuff += lstrlen(TEXT("* ")) ;
|
|
iChars = AMGetErrorText(pStatus->hrVPEStatus, lpszBuff, 200) ;
|
|
lpszBuff += iChars ;
|
|
lstrcat(lpszBuff, TEXT("\n")) ;
|
|
lpszBuff += lstrlen(TEXT("\n")) ;
|
|
}
|
|
|
|
if (pStatus->bDvdVolInvalid)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT("* Specified DVD-Video volume was invalid\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
else if (pStatus->bDvdVolUnknown)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT("* No valid DVD-Video volume could be located\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
|
|
if (pStatus->bNoLine21In)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT("* The video decoder doesn't produce closed caption data\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
if (pStatus->bNoLine21Out)
|
|
{
|
|
iChars = wsprintf(lpszBuff, TEXT("* Decoded closed caption data not rendered properly\n")) ;
|
|
lpszBuff += iChars ;
|
|
}
|
|
|
|
DWORD dwLength = (lpszBuff - achBuffer) * sizeof(*lpszBuff) ;
|
|
dwLength = min(dwLength, dwMaxText) ;
|
|
lstrcpyn(lpszStatusText, achBuffer, dwLength) ;
|
|
|
|
return dwLength ;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CFilePlayer constructor
|
|
//
|
|
CFilePlayer::CFilePlayer(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer c-tor entered"))) ;
|
|
|
|
m_pDDXM = NULL ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer destructor
|
|
//
|
|
CFilePlayer::~CFilePlayer(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer d-tor entered"))) ;
|
|
|
|
ReleaseInterfaces() ;
|
|
|
|
DbgLog((LOG_TRACE, 3, TEXT("CFilePlayer d-tor exiting..."))) ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::ReleaseInterfaces(): Let go of the interfaces taken in BuildGraph()
|
|
//
|
|
void CFilePlayer::ReleaseInterfaces(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::ReleaseInterfaces() entered"))) ;
|
|
|
|
if (m_pDDXM) {
|
|
m_pDDXM->Release() ;
|
|
m_pDDXM = NULL ;
|
|
}
|
|
CBaseVideoPlayer::ReleaseInterfaces() ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::Initialize(): Creates an empty filter graph object.
|
|
//
|
|
BOOL CFilePlayer::Initialize(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::Initialize() entered"))) ;
|
|
|
|
//
|
|
// Just instantiate the Filter Graph object
|
|
//
|
|
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
|
|
IID_IGraphBuilder, (LPVOID *)&m_pGraph) ;
|
|
if (FAILED(hr) || NULL == m_pGraph)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("ERROR: DirectShow is not installed properly (Error 0x%lx)"), hr)) ;
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::IsOvMConnected(): Private method to detect if the video stream
|
|
// is passing through the Overlay Mixer (i.e, is it connected?).
|
|
//
|
|
BOOL CFilePlayer::IsOvMConnected(IBaseFilter *pOvM)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::IsOvMConnected() entered"))) ;
|
|
|
|
IEnumPins *pEnumPins ;
|
|
IPin *pPin ;
|
|
IPin *pPin2 ;
|
|
ULONG ul ;
|
|
HRESULT hr ;
|
|
BOOL bConnected = FALSE ;
|
|
|
|
pOvM->EnumPins(&pEnumPins) ;
|
|
while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
|
|
{
|
|
hr = pPin->ConnectedTo(&pPin2) ;
|
|
if (SUCCEEDED(hr) && pPin2)
|
|
{
|
|
DbgLog((LOG_TRACE, 3, TEXT("Found pin %s connected to pin %s"),
|
|
(LPCTSTR)CDisp(pPin), (LPCTSTR)CDisp(pPin2))) ;
|
|
bConnected = TRUE ;
|
|
pPin2->Release() ;
|
|
}
|
|
pPin->Release() ;
|
|
}
|
|
pEnumPins->Release() ;
|
|
|
|
return bConnected ;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CFilePlayer::GetVideoRendererInterface(): Private method to get the interface
|
|
// to the Video Rendererer filter. It also tells us if a file has any video stream.
|
|
//
|
|
HRESULT CFilePlayer::GetVideoRendererInterface(IBaseFilter **ppVR)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::IsVideoStreamPresent() entered"))) ;
|
|
|
|
// Get Video Renderer filter pointer from the graph
|
|
return m_pGraph->FindFilterByName(L"Video Renderer", ppVR) ;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CFilePlayer::AddOvMToGraph(): Private method to instantiate OverlayMixer,
|
|
// add it to the filter graph and set the DDraw parameters specified by the
|
|
// app..
|
|
//
|
|
HRESULT CFilePlayer::AddOvMToGraph(IBaseFilter **ppOvM, LPDIRECTDRAW pDDObj,
|
|
LPDIRECTDRAWSURFACE pDDPrimary)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::AddOvMToGraph() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
|
|
hr = CoCreateInstance(CLSID_OverlayMixer, NULL, CLSCTX_INPROC, IID_IBaseFilter, (LPVOID *)ppOvM) ;
|
|
if (FAILED(hr) || NULL == *ppOvM)
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("Can't instantiate Overlay Mixer (Error 0x%lx)"), hr)) ;
|
|
return E_FAIL ;
|
|
}
|
|
hr = m_pGraph->AddFilter(*ppOvM, L"Overlay Mixer") ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("Can't add Overlay Mixer to the graph (Error 0x%lx)"), hr)) ;
|
|
(*ppOvM)->Release() ;
|
|
*ppOvM = NULL ;
|
|
return E_FAIL ;
|
|
}
|
|
|
|
// Set the DDraw params now
|
|
hr = SetDDrawParams(*ppOvM, pDDObj, pDDPrimary) ;
|
|
if (FAILED(hr))
|
|
{
|
|
m_pGraph->RemoveFilter(*ppOvM) ; // remove from graph
|
|
(*ppOvM)->Release() ;
|
|
*ppOvM = NULL ;
|
|
return hr ;
|
|
}
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::SetDDrawParams(): Private method to set DDraw objeact and primary
|
|
// surface on the OverlayMixer via the IDDrawExclModeVideo interface.
|
|
//
|
|
HRESULT CFilePlayer::SetDDrawParams(IBaseFilter *pOvM, LPDIRECTDRAW pDDObj,
|
|
LPDIRECTDRAWSURFACE pDDPrimary)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetDDrawParams() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
IDDrawExclModeVideo *pDDXM ;
|
|
|
|
hr = pOvM->QueryInterface(IID_IDDrawExclModeVideo, (LPVOID *)&pDDXM) ;
|
|
if (FAILED(hr) || NULL == pDDXM)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("Can't get IDDrawExclusiveMode interface from Overlay Mixer (Error 0x%lx)"), hr)) ;
|
|
return E_FAIL ;
|
|
}
|
|
hr = pDDXM->SetDDrawObject(pDDObj) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("SetDDrawObject(0x%lx) failed (Error 0x%lx)"), pDDObj, hr)) ;
|
|
pDDXM->Release() ; // release interface
|
|
return E_FAIL ;
|
|
}
|
|
hr = pDDXM->SetDDrawSurface(pDDPrimary) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("SetDDrawSurface(0x%lx) failed (Error 0x%lx)"), pDDPrimary, hr)) ;
|
|
pDDXM->SetDDrawObject(NULL) ; // get back to original DDraw object
|
|
pDDXM->Release() ; // release interface
|
|
return E_FAIL ;
|
|
}
|
|
|
|
pDDXM->Release() ; // release interface
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::PutVideoThroughOvM(): Private method to connect the decoded video
|
|
// stream through the OverlayMixer.
|
|
//
|
|
HRESULT CFilePlayer::PutVideoThroughOvM(IBaseFilter *pOvM, IBaseFilter *pVR)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::PutVideoThroughOvM() entered"))) ;
|
|
|
|
IEnumPins *pEnumPins ;
|
|
IPin *pPinVR ;
|
|
IPin *pPinConnectedTo ;
|
|
IPin *pPinOvM ;
|
|
ULONG ul ;
|
|
PIN_DIRECTION pd ;
|
|
HRESULT hr ;
|
|
|
|
// Get the video renderer's (only) in pin
|
|
hr = pVR->EnumPins(&pEnumPins) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
hr = pEnumPins->Next(1, &pPinVR, &ul) ;
|
|
ASSERT(S_OK == hr && 1 == ul) ;
|
|
pPinVR->QueryDirection(&pd) ;
|
|
ASSERT(PINDIR_INPUT == pd) ;
|
|
pEnumPins->Release() ;
|
|
|
|
// Disconnect VR from upstream filter and put OvMixer in between them
|
|
hr = pPinVR->ConnectedTo(&pPinConnectedTo) ;
|
|
ASSERT(SUCCEEDED(hr) && pPinConnectedTo) ;
|
|
hr = m_pGraph->Disconnect(pPinVR) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
hr = m_pGraph->Disconnect(pPinConnectedTo) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
|
|
// Now connect the upstream filter's out pin to OvM's in pin
|
|
// (and remove Video Renderer from the graph).
|
|
hr = pOvM->EnumPins(&pEnumPins) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
int iInConns = 0 ;
|
|
while (iInConns == 0 && // input pin not connected yet
|
|
S_OK == pEnumPins->Next(1, &pPinOvM, &ul) && 1 == ul) // pin left to try
|
|
{
|
|
pPinOvM->QueryDirection(&pd) ;
|
|
if (PINDIR_INPUT == pd) // OvM's in pin <- Upstream filter's pin
|
|
{
|
|
if (0 == iInConns) // We want to connect only one input pin
|
|
{
|
|
hr = m_pGraph->Connect(pPinConnectedTo, pPinOvM) ; // , NULL) ; // direct??
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
if (FAILED(hr))
|
|
DbgLog((LOG_ERROR, 0, TEXT("ERROR: m_pGraph->Connect() failed (Error 0x%lx)"), hr)) ;
|
|
else
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("Pin %s connected to pin %s"),
|
|
(LPCTSTR) CDisp(pPinConnectedTo), (LPCTSTR) CDisp(pPinOvM))) ;
|
|
iInConns++ ;
|
|
}
|
|
}
|
|
// else ignore
|
|
}
|
|
else
|
|
DbgLog((LOG_ERROR, 1, TEXT("OVMixer still has an out pin!!!"))) ;
|
|
|
|
pPinOvM->Release() ;
|
|
}
|
|
pEnumPins->Release() ;
|
|
|
|
pPinConnectedTo->Release() ; // done with upstream pin
|
|
pPinVR->Release() ; // done with VR pin
|
|
m_pGraph->RemoveFilter(pVR) ; // by force remove the VR from graph
|
|
|
|
// Just to check...
|
|
if (0 == iInConns) // input pin not connected!!
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't connect any out pin to OvMixer's 1st in pin"))) ;
|
|
return E_FAIL ; // failure
|
|
}
|
|
|
|
return S_OK ; // success!!
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::BuildGraph(): Builds a AVI/MPEG/.. playback graph rendering via
|
|
// OverlayMixer which uses app's given DDraw params.
|
|
//
|
|
HRESULT CFilePlayer::BuildGraph(HWND hWndApp, LPDIRECTDRAW pDDObj, LPDIRECTDRAWSURFACE pDDPrimary)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::BuildGraph() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
IBaseFilter *pOvM ;
|
|
WCHAR achwFileName[MAX_PATH] ;
|
|
LPWSTR lpszwFileName = NULL ;
|
|
IBaseFilter *pVR ;
|
|
|
|
// First release any existing interface pointer(s)
|
|
ReleaseInterfaces() ;
|
|
SetColorKey(253) ; // default magenta for 8bpp
|
|
|
|
// Check if a file name has been specified; if so, use that
|
|
if (lstrlen(GetFileName()) > 0) // if something was specified before
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(achwFileName, GetFileName()) ;
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, GetFileName(), -1, achwFileName, MAX_PATH) ;
|
|
#endif // UNICODE
|
|
|
|
lpszwFileName = achwFileName ;
|
|
}
|
|
else // no file specified, but we should have detected it before!!!
|
|
return E_FAIL ;
|
|
|
|
//
|
|
// Instantiate Overlay Mixer, add it to the graph and set DDraw params
|
|
//
|
|
hr = AddOvMToGraph(&pOvM, pDDObj, pDDPrimary) ;
|
|
if (FAILED(hr))
|
|
{
|
|
return E_FAIL ;
|
|
}
|
|
|
|
//
|
|
// First render the graph for the selected file
|
|
//
|
|
hr = m_pGraph->RenderFile(lpszwFileName, NULL) ;
|
|
if (S_OK != hr)
|
|
{
|
|
DbgLog((LOG_ERROR, 0,
|
|
TEXT("Rendering the given file didn't succeed completely (Error 0x%lx)"), hr)) ;
|
|
m_pGraph->RemoveFilter(pOvM) ; // remove from graph
|
|
pOvM->Release() ; // release filter
|
|
return E_FAIL ;
|
|
}
|
|
|
|
//
|
|
// Because there are some AVI files which on some machines decide to rather go
|
|
// through the Color Space Converter filter, just making sure that the OverlayMixer
|
|
// is actually being used. Otherwise we have to do some more (bull)work.
|
|
//
|
|
if (! IsOvMConnected(pOvM) )
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("OverlayMixer is not used in the graph. Try again..."))) ;
|
|
|
|
//
|
|
// Check that the specified file has a video stream. Otherwise OverlayMixer
|
|
// will never be used and DDraw exclusive mode playback doesn't make any sense.
|
|
//
|
|
if (FAILED(GetVideoRendererInterface(&pVR)))
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("Specified file doesn't have any video stream. Aborting graph building."))) ;
|
|
m_pGraph->RemoveFilter(pOvM) ; // remove from graph
|
|
pOvM->Release() ; // release filter
|
|
return E_FAIL ;
|
|
}
|
|
|
|
//
|
|
// Put the video stream to go through the OverlayMixer.
|
|
//
|
|
hr = PutVideoThroughOvM(pOvM, pVR) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_TRACE, 1, TEXT("Couldn't put video through the OverlayMixer."))) ;
|
|
m_pGraph->RemoveFilter(pOvM) ; // remove OvMixer from graph
|
|
pOvM->Release() ; // release OvMixer filter
|
|
pVR->Release() ; // release VR interface (before giving up)
|
|
return E_FAIL ;
|
|
}
|
|
pVR->Release() ; // done with VR interface
|
|
}
|
|
|
|
//
|
|
// We are successful in building the graph. Now the rest...
|
|
//
|
|
GetInterfaces(hWndApp) ;
|
|
|
|
// Get IDDrawExclModeVideo interface of the OvMixer and store it
|
|
hr = pOvM->QueryInterface(IID_IDDrawExclModeVideo, (LPVOID *)&m_pDDXM) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
|
|
// Get the color key to be used and store it
|
|
hr = GetColorKeyInternal(pOvM) ;
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
|
|
pOvM->Release() ; // done with it
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::GetInterfaces(): Gets some interfaces useful for DVD title playback
|
|
//
|
|
// NOTE: Don't really need this one. We could have as well used the base classes'.
|
|
//
|
|
HRESULT CFilePlayer::GetInterfaces(HWND hWndApp)
|
|
{
|
|
return CBaseVideoPlayer::GetInterfaces(hWndApp) ; // get the standard interfaces
|
|
}
|
|
|
|
//
|
|
// CFilePlayer::GetColorKeyInternal(): Private method to query the color key
|
|
// value from teh first input pin of the OverlayMixer.
|
|
//
|
|
HRESULT CFilePlayer::GetColorKeyInternal(IBaseFilter *pOvM)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::GetColorKeyInternal() entered"))) ;
|
|
|
|
if (NULL == pOvM)
|
|
return E_INVALIDARG ;
|
|
|
|
IEnumPins *pEnumPins ;
|
|
IPin *pPin ;
|
|
ULONG ul ;
|
|
PIN_DIRECTION pd ;
|
|
DWORD dwColorKey ;
|
|
IMixerPinConfig *pMPC ;
|
|
HRESULT hr = pOvM->EnumPins(&pEnumPins) ;
|
|
ASSERT(pEnumPins) ;
|
|
while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul) // try all pins
|
|
{
|
|
pPin->QueryDirection(&pd) ;
|
|
if (PINDIR_INPUT == pd) // only the 1st in pin
|
|
{
|
|
hr = pPin->QueryInterface(IID_IMixerPinConfig, (LPVOID *) &pMPC) ;
|
|
ASSERT(SUCCEEDED(hr) && pMPC) ;
|
|
hr = pMPC->GetColorKey(NULL, &dwColorKey) ; // just get the physical color
|
|
SetColorKey(dwColorKey) ;
|
|
// Set mode to stretch - that way we don't fight the overlay
|
|
// mixer about the exact way to fix the aspect ratio
|
|
pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED);
|
|
ASSERT(SUCCEEDED(hr)) ;
|
|
pMPC->Release() ;
|
|
pPin->Release() ; // exiting early; release pin
|
|
break ; // we are done
|
|
}
|
|
pPin->Release() ;
|
|
}
|
|
pEnumPins->Release() ; // done with pin enum
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::ClearGraph(): Releases the filter graph built by BuildGraph()
|
|
// and the interfaces taken for playback.
|
|
//
|
|
HRESULT CFilePlayer::ClearGraph(void)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::ClearGraph() entered"))) ;
|
|
|
|
ReleaseInterfaces() ; // let go of the other interfaces
|
|
if (m_pGraph)
|
|
{
|
|
m_pGraph->Release() ; // let the graph go (we'll create a fresh one next time)
|
|
m_pGraph = NULL ;
|
|
}
|
|
|
|
return S_OK ;
|
|
}
|
|
|
|
//
|
|
// CFilePlayer::SetVideoPosition(): Sets the source and dest rects for the video to
|
|
// be shown via IDDrawExclModeVideo interface of OverlayMixer.
|
|
//
|
|
HRESULT CFilePlayer::SetVideoPosition(DWORD dwLeft, DWORD dwTop, DWORD dwWidth, DWORD dwHeight)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetVideoPosition() entered"))) ;
|
|
|
|
RECT rectDest ;
|
|
SetRect(&rectDest, dwLeft, dwTop, dwLeft + dwWidth, dwTop + dwHeight) ;
|
|
|
|
// NULL or (0, 0, 10000, 10000) for full video
|
|
return m_pDDXM->SetDrawParameters(NULL, &rectDest) ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::GetNativeVideoData(): Returns the actual video size to the app.
|
|
//
|
|
HRESULT CFilePlayer::GetNativeVideoData(DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwARX, DWORD *pdwARY)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::GetNativeVideoData() entered"))) ;
|
|
|
|
return m_pDDXM->GetNativeVideoProps(pdwWidth, pdwHeight, pdwARX, pdwARY) ;
|
|
}
|
|
|
|
|
|
//
|
|
// CFilePlayer::SetOverlayCallback(): Specify the pointer to the overlay notification
|
|
// callback object which the OverlayMixer will call during playback.
|
|
//
|
|
HRESULT CFilePlayer::SetOverlayCallback(IDDrawExclModeVideoCallback *pCallback)
|
|
{
|
|
DbgLog((LOG_TRACE, 5, TEXT("CFilePlayer::SetOverlayCallback() entered"))) ;
|
|
|
|
HRESULT hr ;
|
|
hr = m_pDDXM->SetCallbackInterface(pCallback, 0) ;
|
|
if (FAILED(hr))
|
|
{
|
|
DbgLog((LOG_ERROR, 0, TEXT("ERROR: IDDrawExclModeVideo::SetCallbackInterface() failed (Error 0x%lx)"), hr)) ;
|
|
}
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|