Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Players/DDrawXCL/ddrawxcl.cpp
LGram16 e067522598 Initial commit: ROW Client source code
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>
2025-11-29 16:24:34 +09:00

872 lines
26 KiB
C++

//------------------------------------------------------------------------------
// File: DDrawXcl.cpp
//
// Desc: DirectShow sample code - DDraw Exclusive Mode Video Playback
// test/sample application.
//
// Copyright (c) 1993-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
#include <windows.h>
#include <commdlg.h>
#include <DVDEvCod.h>
#include "VidPlay.h"
#include "DDrawObj.h"
#include "DDrawXcl.h"
//
// WinMain(): Entry point to our sample app.
//
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg ;
HACCEL hAccelTable ;
DbgInitialise(hInstance) ;
CoInitialize(NULL) ;
ghInstance = hInstance ;
LoadString(ghInstance, IDS_APP_TITLE, gszAppTitle, 100) ;
LoadString(ghInstance, IDS_APP_NAME, gszAppName, 10) ;
if (! InitApplication() )
{
DbgTerminate() ;
return FALSE ;
}
if (! InitInstance(nCmdShow) )
{
DbgTerminate() ;
return FALSE ;
}
hAccelTable = LoadAccelerators(hInstance, gszAppName) ;
//
// Create a DDraw object and init it
//
gpDDrawObj = new CDDrawObject(ghWndApp) ;
if (NULL == gpDDrawObj)
{
DbgTerminate() ;
return FALSE ;
}
gpPlayer = NULL ; // Init Video playback object pointer to NULL
geVideoType = Unspecified ; // no video type specified on start up
gbAppActive = TRUE ; // app is activated on start up
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (! TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
{
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
}
//
// Release the video playback object, if any
//
if (gpPlayer)
delete gpPlayer ;
//
// Release DDraw now
//
delete gpDDrawObj ;
CoUninitialize() ;
DbgTerminate() ;
return (int) (msg.wParam) ;
}
//
// InitApplication(): Registers the class if no other instance of this app is
// already running.
//
BOOL InitApplication(void)
{
DbgLog((LOG_TRACE, 5, TEXT("App's InitApplication() entered"))) ;
WNDCLASSEX wc ;
// Win32 will always set hPrevInstance to NULL, so lets check
// things a little closer. This is because we only want a single
// version of this app to run at a time
ghWndApp = FindWindow (gszAppName, gszAppTitle) ;
if (ghWndApp) {
// We found another version of ourself. Lets defer to it:
if (IsIconic(ghWndApp)) {
ShowWindow(ghWndApp, SW_RESTORE);
}
SetForegroundWindow(ghWndApp);
// If this app actually had any functionality, we would
// also want to communicate any action that our 'twin'
// should now perform based on how the user tried to
// execute us.
return FALSE;
}
// Register the app main window class
wc.cbSize = sizeof(wc) ;
wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.lpfnWndProc = (WNDPROC) WndProc ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = ghInstance ;
wc.hIcon = LoadIcon(ghInstance, gszAppName) ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
wc.lpszMenuName = gszAppName ;
wc.lpszClassName = gszAppName ;
wc.hIconSm = NULL ;
if (0 == RegisterClassEx(&wc))
{
DbgLog((LOG_ERROR, 0,
TEXT("ERROR: RegisterClassEx() for app class failed (Error %ld)"),
GetLastError())) ;
return FALSE ;
}
return TRUE ;
}
//
// InitInstance(): Starts this instance of the app (creates the window).
//
BOOL InitInstance(int nCmdShow)
{
DbgLog((LOG_TRACE, 5, TEXT("App's InitInstance() entered"))) ;
ghWndApp = CreateWindowEx(0, gszAppName, gszAppTitle,
WS_OVERLAPPEDWINDOW,
0, 0,
DEFAULT_WIDTH, DEFAULT_HEIGHT,
NULL, NULL, ghInstance, NULL);
if (! ghWndApp ) {
return FALSE ;
}
ShowWindow(ghWndApp, nCmdShow);
UpdateWindow(ghWndApp) ;
return TRUE ;
}
//
// MenuProc(): Handles menu choices picked by the user.
//
LRESULT CALLBACK MenuProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
HMENU hMenu = GetMenu(hWnd) ;
int wmId = LOWORD(wParam);
// int wmEvent = HIWORD(wParam);
//Parse the menu selections:
switch (wmId) {
case IDM_SELECTDVD:
if (FileSelect(hWnd, DVD)) // selection changed
{
CheckMenuItem(hMenu, IDM_SELECTDVD, MF_CHECKED) ;
CheckMenuItem(hMenu, IDM_SELECTFILE, MF_UNCHECKED) ;
}
break;
case IDM_SELECTFILE:
if (FileSelect(hWnd, File)) // selection changed
{
CheckMenuItem(hMenu, IDM_SELECTDVD, MF_UNCHECKED) ;
CheckMenuItem(hMenu, IDM_SELECTFILE, MF_CHECKED) ;
}
break;
case IDM_ABOUT:
DialogBox(ghInstance, TEXT("AboutBox"), ghWndApp, (DLGPROC) About);
break;
case IDM_EXIT:
DestroyWindow(ghWndApp);
break;
case IDM_STARTPLAY:
if (StartPlay(hWnd)) // playback started successfully
gbAppActive = TRUE ; // if we are playing, we must be active
else // playback failed due to some reason
MessageBox(hWnd,
STR_EXCLUSIVE_MODE_FAILURE,
TEXT("Error"), MB_OK | MB_ICONINFORMATION) ;
break;
default:
break ;
}
return 0 ;
}
//
// FileSelect(): Lets the user specify the file to play.
//
BOOL FileSelect(HWND hWnd, VIDEO_TYPE eType)
{
DbgLog((LOG_TRACE, 5, TEXT("App's FileSelect(%s) entered"),
DVD == eType ? "DVD" : "File")) ;
OPENFILENAME ofn ;
TCHAR achFileName[MAX_PATH] ;
// Init the filename buffer with either a filename or *.ifo
if (DVD == eType)
lstrcpy(achFileName, TEXT("*.ifo")) ;
else
lstrcpy(achFileName, TEXT("*.avi")) ;
ZeroMemory(&ofn, sizeof(OPENFILENAME)) ;
ofn.lStructSize = sizeof(OPENFILENAME) ;
ofn.hwndOwner = hWnd ;
if (DVD == eType)
{
ofn.lpstrTitle = TEXT("Select DVD-Video Volume\0") ;
ofn.lpstrFilter = TEXT("IFO Files\0*.ifo\0All Files\0*.*\0\0") ;
}
else
{
ofn.lpstrTitle = TEXT("Select Video file\0") ;
ofn.lpstrFilter = TEXT("AVI Files\0*.avi\0MPEG Files\0*.mpg\0All Files\0*.*\0\0") ;
}
ofn.nFilterIndex = 1 ;
ofn.lpstrFile = achFileName ;
ofn.nMaxFile = sizeof(achFileName) ;
ofn.lpstrFileTitle = NULL ;
ofn.nMaxFileTitle = 0 ;
ofn.lpstrInitialDir = NULL ;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY ;
if (GetOpenFileName(&ofn)) // user specified a file
{
if (! CreatePlayer(eType) || // creating player failed!!
NULL == gpPlayer ) // how!?!
{
DbgLog((LOG_ERROR, 0, TEXT("ERROR: Couldn't create %s player"),
DVD == eType ? "DVD" : "File")) ;
return FALSE ;
}
gpPlayer->SetFileName(achFileName) ;
return TRUE ; // user specified file name
}
// Either failed or user hit Esc.
DbgLog((LOG_TRACE, 3, TEXT("GetOpenFileName() cancelled/failed (Error %lu)"),
CommDlgExtendedError())) ;
return FALSE ; // DVD-Video volume not changed
}
BOOL IsVideoTypeKnown(void)
{
return (Unspecified != geVideoType) ;
}
VIDEO_TYPE GetVideoType(void)
{
return geVideoType ;
}
BOOL CreatePlayer(VIDEO_TYPE eType)
{
if (geVideoType == eType) // same type as before
{
if (gpPlayer) // we have already have the player
return TRUE ; // we'll use the same one; everything is OK
}
else // video type has changed
{
if (gpPlayer) // we created a player before...
{
delete gpPlayer ; // release it now
gpPlayer = NULL ;
}
}
// If we are here, we need to create a new player of the specified type
if (DVD == eType)
gpPlayer = new CDVDPlayer ;
else if (File == eType)
gpPlayer = new CFilePlayer ;
else // what then??
{
ASSERT(FALSE) ;
return NULL ;
}
geVideoType = eType ; // this our current video type
return TRUE ;
}
//
// OnEndOfPlayback(): Releases everything on end of playback (but checks to
// avoid doing it too many times) as it "may be" called a little more than
// we would like to.
//
void OnEndOfPlayback(HWND hWndApp)
{
DbgLog((LOG_TRACE, 5, TEXT("App's OnEndOfPlayback() entered"))) ;
if (0 != guTimerID) // if any timer is still set
{
BOOL bRes = KillTimer(hWndApp, TIMER_ID) ; // don't need that timer anymore
ASSERT(bRes) ; bRes = bRes; // Suppress C4189 warning
guTimerID = 0 ; // timer released
}
if (gpPlayer && gpPlayer->IsGraphReady())
{
DbgLog((LOG_TRACE, 5, TEXT("Turn off color keying before stopping the graph"))) ;
gpDDrawObj->SetOverlayState(FALSE) ; // don't paint color key in video's position
#ifndef NOFLIP
gpDDrawObj->UpdateAndFlipSurfaces() ; // flip the surface so that video doesn't show anymore
#endif // NOFLIP
gpPlayer->Stop() ;
// Remove the overlay callback interface for OverlayMixer
HRESULT hr = gpPlayer->SetOverlayCallback(NULL) ;
ASSERT(SUCCEEDED(hr)) ; hr = hr; // Suppress C4189 warning
gpPlayer->ClearGraph() ;
}
if (gpDDrawObj->IsInExclusiveMode())
{
gpDDrawObj->StopExclusiveMode(hWndApp) ;
// Resize main window to default size
SetWindowPos(ghWndApp, HWND_TOP, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0);
}
}
//
// WndPorc(): Message handles for our sample app.
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hDC ;
static PAINTSTRUCT ps ;
switch (message) {
case WM_ACTIVATEAPP:
//
// NOTE: We don't try to recover playback on switching back into focus.
//
gbAppActive = (BOOL) wParam ;
if (! gbAppActive ) // losing activation
{
DbgLog((LOG_TRACE, 2, TEXT("Got a WM_ACTIVATEAPP message with Active = %s"),
gbAppActive ? "TRUE" : "FALSE")) ;
OnEndOfPlayback(hWnd) ; // should stop playback now
}
break ;
case WM_TIMER:
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_TIMER message with ID = %ld (Active = %s)"),
wParam, gbAppActive ? "T" : "F")) ;
if ( TIMER_ID != wParam || // this is not the timer we have set or
! gbAppActive || // the app isn't active anymore or
! gpPlayer->IsGraphReady() ) // the graph is not currently ready
// (...but we should have turned timer off then anyway!!)
break ; // don't do anything
//
// We could do some status update here that could be used by the
// UpdateAndFlipSurfaces() call below.
//
#ifndef NOFLIP
gpDDrawObj->UpdateAndFlipSurfaces() ;
#endif // NOFLIP
break;
case WM_COMMAND:
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_COMMAND message with wParam = %ld"), wParam)) ;
MenuProc(hWnd, wParam, lParam) ;
break;
case WM_PLAY_EVENT:
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_PLAY_EVENT message with wParam = %ld"), wParam)) ;
if (1 == OnPlaybackEvent(hWnd, wParam, lParam)) // playback ended
OnEndOfPlayback(hWnd) ; // do the necessary things
break ;
case WM_SIZE_CHANGE:
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_SIZE_CHANGE message"))) ;
if (gpPlayer->IsGraphReady()) // ONLY if the graph is ready
SetVideoPosition(FALSE) ;
else
DbgLog((LOG_TRACE, 1, TEXT("WARNING: Got a WM_SIZE_CHANGE message after graph was released!!"))) ;
break ;
case WM_KEYUP:
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_KEYUP message with wParam = %ld"), wParam)) ;
KeyProc(hWnd, wParam, lParam) ;
break ;
case WM_DESTROY:
OnEndOfPlayback(hWnd) ; // must stop playback before quitting
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return 0 ;
}
//
// KeyProc(): Handles key presses to exit playback (on Esc) or move the ball
// using arrow keys.
//
LRESULT CALLBACK KeyProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
DbgLog((LOG_TRACE, 5, TEXT("App's KeyProc() entered"))) ;
switch (wParam)
{
case VK_ESCAPE:
OnEndOfPlayback(hWnd) ;
break ;
case VK_UP:
gpDDrawObj->MoveBallPosition(0, -BALL_STEP) ;
break ;
case VK_DOWN:
gpDDrawObj->MoveBallPosition(0, BALL_STEP) ;
break ;
case VK_LEFT:
gpDDrawObj->MoveBallPosition(-BALL_STEP, 0) ;
break ;
case VK_RIGHT:
gpDDrawObj->MoveBallPosition(BALL_STEP, 0) ;
break ;
default:
break ;
}
return 0 ;
}
//
// About(): Dialog box code for the About box.
//
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
DbgLog((LOG_TRACE, 5, TEXT("App's About() entered"))) ;
switch (message) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, TRUE);
return TRUE;
}
break;
default:
break ;
}
return FALSE;
}
//
// OnPlaybackEvent(): Handles playback events, specially completed/stopped-on-error.
//
// Returns 0 if playback is continuing.
// Returns 1 if playback is over for any reason.
//
LRESULT OnPlaybackEvent(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
DbgLog((LOG_TRACE, 5,
TEXT("App's OnPlaybackEvent(0x%lx, 0x%lx) entered"),
wParam, lParam)) ;
IMediaEventEx *pME = (IMediaEventEx *) lParam ;
if (NULL == pME || Playing != gpPlayer->GetState())
{
DbgLog((LOG_TRACE, 1, TEXT("Either pME = NULL or not playing anymore. Skip everything."))) ;
return 0 ; // or 1 ??
}
LONG lEvent ;
LONG_PTR lParam1, lParam2 ;
//
// Because the message mode for IMediaEvent may not be set before
// we get the first event it's important to read all the events
// pending when we get a window message to say there are events pending.
// GetEvent() returns E_ABORT when no more event is left.
//
while (SUCCEEDED(pME->GetEvent(&lEvent, &lParam1, &lParam2, 0))) // no wait
{
switch (lEvent)
{
//
// First the DVD related events
//
case EC_DVD_STILL_ON:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_STILL_ON"))) ;
break ;
case EC_DVD_STILL_OFF:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_STILL_OFF"))) ;
break ;
case EC_DVD_DOMAIN_CHANGE:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_DOMAIN_CHANGE, %ld"), lParam1)) ;
switch (lParam1)
{
case DVD_DOMAIN_FirstPlay: // = 1
case DVD_DOMAIN_Stop: // = 5
break ;
case DVD_DOMAIN_VideoManagerMenu: // = 2
case DVD_DOMAIN_VideoTitleSetMenu: // = 3
// Inform the app to update the menu option to show "Resume" now
break ;
case DVD_DOMAIN_Title: // = 4
// Inform the app to update the menu option to show "Menu" again
break ;
default: // hmmmm...
break ;
}
break ;
case EC_DVD_BUTTON_CHANGE:
DbgLog((LOG_TRACE, 5, TEXT("DVD Event: Button Changed to %d out of %d"),
lParam2, lParam1));
break;
case EC_DVD_TITLE_CHANGE:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_TITLE_CHANGE"))) ;
break ;
case EC_DVD_CHAPTER_START:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_CHAPTER_START"))) ;
break ;
case EC_DVD_CURRENT_TIME:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_CURRENT_TIME"))) ;
break ;
//
// Then the general DirectShow related events
//
case EC_COMPLETE:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: Playback complete"))) ;
MessageBeep(MB_OK) ; // just to inform that the playback is over
// Remember to free the event params
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
// We don't do the release part here. That will be done in WndProc()
// after return from this function.
return 1 ; // playback over
case EC_USERABORT:
case EC_ERRORABORT:
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: 0x%lx"), lEvent)) ;
MessageBeep(MB_ICONEXCLAMATION) ; // to inform that the playback has errored out
// Remember to free the event params
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
// We don't do the release part here. That will be done in WndProc()
// after return from this function.
return 1 ; // playback over
default:
DbgLog((LOG_TRACE, 5, TEXT("Ignored unknown playback event: 0x%lx"), lEvent)) ;
break ;
}
//
// Remember to free the event params
//
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
} // end of while (GetEvent()) loop
return 0 ;
}
typedef enum _AM_TRANSFORM
{
AM_SHRINK,
AM_STRETCH
} AM_TRANSFORM ;
void TransformRect(RECT *prRect, double dPictAspectRatio, AM_TRANSFORM transform)
{
double dWidth, dHeight, dNewWidth, dNewHeight ;
double dResolutionRatio = 0.0, dTransformRatio = 0.0 ;
ASSERT(transform == AM_SHRINK || transform == AM_STRETCH) ;
dNewWidth = dWidth = prRect->right - prRect->left ;
dNewHeight = dHeight = prRect->bottom - prRect->top ;
dResolutionRatio = dWidth / dHeight ;
dTransformRatio = dPictAspectRatio / dResolutionRatio ;
// shrinks one dimension to maintain the coorect aspect ratio
if (transform == AM_SHRINK)
{
if (dTransformRatio > 1.0)
{
dNewHeight = dNewHeight / dTransformRatio ;
}
else if (dTransformRatio < 1.0)
{
dNewWidth = dNewWidth * dTransformRatio ;
}
}
// stretches one dimension to maintain the coorect aspect ratio
else if (transform == AM_STRETCH)
{
if (dTransformRatio > 1.0)
{
dNewWidth = dNewWidth * dTransformRatio ;
}
else if (dTransformRatio < 1.0)
{
dNewHeight = dNewHeight / dTransformRatio ;
}
}
if (transform == AM_SHRINK)
{
ASSERT(dNewHeight <= dHeight) ;
ASSERT(dNewWidth <= dWidth) ;
}
else
{
ASSERT(dNewHeight >= dHeight) ;
ASSERT(dNewWidth >= dWidth) ;
}
// cut or add equal portions to the changed dimension
prRect->left += (LONG)(dWidth - dNewWidth)/2 ;
prRect->right = prRect->left + (LONG)dNewWidth ;
prRect->top += (LONG)(dHeight - dNewHeight)/2 ;
prRect->bottom = prRect->top + (LONG)dNewHeight ;
}
//
// SetVideoPosition(): Gets the original video size and positions it at the center.
//
void SetVideoPosition(BOOL bSetBallPosition)
{
DbgLog((LOG_TRACE, 5, TEXT("App's SetVideoPosition() entered"))) ;
DWORD dwVideoWidth, dwVideoHeight ;
DWORD dwARX, dwARY ;
gpPlayer->GetNativeVideoData(&dwVideoWidth, &dwVideoHeight, &dwARX, &dwARY) ;
DbgLog((LOG_TRACE, 5, TEXT("Native video size: %lu x %lu, Aspect Ratio: %lu x %lu"),
dwVideoWidth, dwVideoHeight, dwARX, dwARY)) ;
// Update output size to make it aspect ratio corrected
RECT rectCorrected ;
SetRect(&rectCorrected, 0, 0, dwVideoWidth, dwVideoHeight) ;
TransformRect(&rectCorrected, (double)dwARX / (double)dwARY, AM_STRETCH) ;
DbgLog((LOG_TRACE, 5, TEXT("Updated video size: %ld x %ld"),
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected))) ;
RECT ScrnRect ;
gpDDrawObj->GetScreenRect(&ScrnRect) ;
DbgLog((LOG_TRACE, 5, TEXT("Screen size is %ld x %ld"),
RECTWIDTH(ScrnRect), RECTHEIGHT(ScrnRect))) ;
DWORD dwVideoTop ;
DWORD dwVideoLeft ;
if (RECTWIDTH(rectCorrected) <= RECTWIDTH(ScrnRect) && // video width less than screen
RECTHEIGHT(rectCorrected) <= RECTHEIGHT(ScrnRect)) // video height less than screen
{
dwVideoLeft = (RECTWIDTH(ScrnRect) - RECTWIDTH(rectCorrected)) / 2 ;
dwVideoTop = (RECTHEIGHT(ScrnRect) - RECTHEIGHT(rectCorrected)) / 2 ;
}
else // video width more than screen
{
rectCorrected = ScrnRect ;
TransformRect(&rectCorrected, (double)dwARX / (double)dwARY, AM_SHRINK) ;
dwVideoLeft = rectCorrected.left ;
dwVideoTop = rectCorrected.top ;
}
gpDDrawObj->SetVideoPosition(dwVideoLeft, dwVideoTop,
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
if (bSetBallPosition) // if ball position should be (re)set
gpDDrawObj->SetBallPosition(dwVideoLeft, dwVideoTop,
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
else // don't reset the ball position, just...
gpDDrawObj->MoveBallPosition(0, 0) ; // ... make sure it's in the new video area
gpPlayer->SetVideoPosition(dwVideoLeft, dwVideoTop,
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
DbgLog((LOG_TRACE, 5, TEXT("Video is %ld x %ld at (%ld x %ld)"),
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected), dwVideoLeft, dwVideoTop)) ;
}
//
// StartPlay(): Switches to fulscreen exclusive mode, sets up for selected media
// playback, gets the video size and positions video at the center, starts playing
// and sets a timer to tell WndProc() every 1/10 second.
//
LRESULT StartPlay(HWND hWndApp)
{
HRESULT hr ;
DbgLog((LOG_TRACE, 5, TEXT("App's StartPlay() entered"))) ;
if (! IsVideoTypeKnown() )
{
MessageBox(hWndApp,
TEXT("No playback option (DVD/File) has been specified through the menu option yet.\nCan't run test."),
TEXT("Sorry"), MB_OK | MB_ICONINFORMATION) ;
return 0 ;
}
//
// Make sure that DShow components are installed etc so that
// the graph building can be init-ed
//
if (! gpPlayer->Initialize() )
{
MessageBox(hWndApp,
TEXT("DShow components couldn't be initialized.\n\nCan't run test.\nPlease check DxMedia installation"),
TEXT("Sorry"), MB_OK | MB_ICONSTOP) ;
return 0 ;
}
//
// Go into fullscreen exclusive mode
//
hr = gpDDrawObj->StartExclusiveMode(hWndApp) ;
if (FAILED(hr)) // error message shown by the above method
{
gpPlayer->ClearGraph() ;
return 0 ;
}
//
// Build video playback graph
//
hr = gpPlayer->BuildGraph(hWndApp, gpDDrawObj->GetDDObject(), gpDDrawObj->GetDDPrimary()) ;
if (FAILED(hr))
{
gpPlayer->ClearGraph() ;
gpDDrawObj->StopExclusiveMode(hWndApp) ; // get out of exclusive mode
return 0 ;
}
//
// Specify the overlay callback interface for OverlayMixer to notify us
//
hr = gpPlayer->SetOverlayCallback(gpDDrawObj->GetCallbackInterface()) ;
ASSERT(SUCCEEDED(hr)) ;
//
// Pause the video playback graph to get it ready to play
//
BOOL bSuccess = gpPlayer->Pause() ;
if (!bSuccess)
{
gpPlayer->SetOverlayCallback(NULL) ; // first remove overlay callback
gpPlayer->ClearGraph() ; // then remove graph
gpDDrawObj->StopExclusiveMode(hWndApp) ; // then get out of exclusive mode
return 0 ;
}
//
// Get the color key info from the Player object and pass it to the DDraw object
//
DWORD dwVideoColorKey ;
gpPlayer->GetColorKey(&dwVideoColorKey) ;
gpDDrawObj->SetColorKey(dwVideoColorKey) ;
//
// Get the video width and height, center it and pass the coordinates to
// the player and the DDraw object
//
SetVideoPosition(TRUE) ;
//
// Create the first screen on back buffer and then flip
//
#ifndef NOFLIP
gpDDrawObj->UpdateAndFlipSurfaces() ;
#endif // NOFLIP
//
// Play video now...
//
if (! gpPlayer->Play() )
{
gpPlayer->SetOverlayCallback(NULL) ; // first remove overlay callback
gpPlayer->ClearGraph() ; // then remove graph
gpDDrawObj->StopExclusiveMode(hWndApp) ; // then get out of exclusive mode
return 0 ;
}
//
// Now set a timer based on which we'll update the buffers and flip
//
guTimerID = (UINT) SetTimer(hWndApp, TIMER_ID, TIMER_RATE, NULL) ;
ASSERT(0 != guTimerID) ;
// We are done with starting the playback. WndProc will stop the playback on
// playback event messages or user hitting Esc key as well the timer based
// actions will be taken in WM_TIMER handler there.
return 1 ;
}