/**************************************************************************
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
* PURPOSE.
*
* Copyright (c) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
*
**************************************************************************/
//
// DVDSampl.cpp: DvdGraphBuilder test/sample app
//
#include <streams.h>
#include <windows.h>
#include <IL21Dec.h>
#include <dvdevcod.h>
#include "DVDSampl.h"
#define APPNAME TEXT("DVDSampl")
// -------------------------------------------------------------------------
// .... Windows App Requirement starts ....
// -------------------------------------------------------------------------
//
// Forward declaration of functions
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ;
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) ;
LRESULT CALLBACK SelectLang(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) ;
LRESULT CALLBACK SelectViewLevel(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) ;
LRESULT CALLBACK MenuProc(HWND hWnd, WPARAM wParam, LPARAM lParam) ;
LRESULT CALLBACK KeyProc(HWND hWnd, WPARAM wParam, LPARAM lParam) ;
CSampleDVDPlay Player ; // global player object
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg ;
HACCEL hAccelTable ;
DbgInitialise(hInstance);
Player.SetAppValues(hInstance, APPNAME, IDS_APP_TITLE) ;
if (! Player.InitApplication() )
{
DbgTerminate();
return (FALSE) ;
}
// Perform application initialization:
if (! Player.InitInstance(nCmdShow) )
{
DbgTerminate();
return (FALSE) ;
}
hAccelTable = LoadAccelerators(hInstance, Player.GetAppName()) ;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (! TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
{
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
}
DbgTerminate();
return (msg.wParam) ;
}
// A helper function to convert render flags to corresponding menu ids
int FlagToMenuID(DWORD dwFlag)
{
dwFlag = (dwFlag & (~AM_DVD_NOVPE)) ; // strip off VPE flag
switch (dwFlag)
{
case AM_DVD_HWDEC_PREFER:
return (IDM_FLAGBASE + 1) ;
case AM_DVD_HWDEC_ONLY:
return (IDM_FLAGBASE + 2) ;
case AM_DVD_SWDEC_PREFER:
return (IDM_FLAGBASE + 3) ;
case AM_DVD_SWDEC_ONLY:
return (IDM_FLAGBASE + 4) ;
default: // huh!!!
return 0 ;
}
}
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_SELECT:
Player.FileSelect() ; // if volume has been changed, playback stopped.
break;
case IDM_ABOUT:
DialogBox(Player.GetInstance(), TEXT("AboutBox"), Player.GetWindow(),
(DLGPROC) About);
break;
case IDM_EXIT:
DestroyWindow(Player.GetWindow());
break;
case IDM_HWMAX:
if (0 == (Player.GetRenderFlag() & AM_DVD_HWDEC_PREFER))
{
CheckMenuItem(hMenu, FlagToMenuID(Player.GetRenderFlag()),
MF_UNCHECKED) ;
Player.SetRenderFlag(AM_DVD_HWDEC_PREFER) ;
CheckMenuItem(hMenu, IDM_HWMAX, MF_CHECKED) ;
}
break;
case IDM_HWONLY:
if (0 == (Player.GetRenderFlag() & AM_DVD_HWDEC_ONLY))
{
CheckMenuItem(hMenu, FlagToMenuID(Player.GetRenderFlag()),
MF_UNCHECKED) ;
Player.SetRenderFlag(AM_DVD_HWDEC_ONLY) ;
CheckMenuItem(hMenu, IDM_HWONLY, MF_CHECKED) ;
}
break;
case IDM_SWMAX:
if (0 == (Player.GetRenderFlag() & AM_DVD_SWDEC_PREFER))
{
CheckMenuItem(hMenu, FlagToMenuID(Player.GetRenderFlag()),
MF_UNCHECKED) ;
Player.SetRenderFlag(AM_DVD_SWDEC_PREFER) ;
CheckMenuItem(hMenu, IDM_SWMAX, MF_CHECKED) ;
}
break;
case IDM_SWONLY:
if (0 == (Player.GetRenderFlag() & AM_DVD_SWDEC_ONLY))
{
CheckMenuItem(hMenu, FlagToMenuID(Player.GetRenderFlag()),
MF_UNCHECKED) ;
Player.SetRenderFlag(AM_DVD_SWDEC_ONLY) ;
CheckMenuItem(hMenu, IDM_SWONLY, MF_CHECKED) ;
}
break;
case IDM_NOVPE:
Player.SetRenderFlag(AM_DVD_NOVPE) ;
CheckMenuItem(hMenu, IDM_NOVPE,
(Player.GetRenderFlag() & AM_DVD_NOVPE) ? MF_CHECKED : MF_UNCHECKED) ;
break;
case IDM_BUILDGRAPH:
Player.BuildGraph() ;
break ;
case IDM_PLAY:
Player.Play() ;
break;
case IDM_STOP:
Player.Stop() ;
break;
case IDM_PAUSE:
Player.Pause() ;
break;
case IDM_FASTFWD:
Player.FastForward() ;
break;
case IDM_VERYFASTFWD:
Player.VeryFastForward() ;
break;
case IDM_FASTRWND:
Player.FastRewind() ;
break;
case IDM_VERYFASTRWND:
Player.VeryFastRewind() ;
break;
case IDM_MENU:
Player.ShowMenu() ;
break;
case IDM_USER_MENUSTATUS:
//
// This is a custom user message that informs the app to update the
// menu according to the state.
//
ModifyMenu(hMenu, IDM_MENU, MF_STRING, IDM_MENU,
lParam ? TEXT("Resume") : TEXT("Menu")) ;
break ;
case IDM_LANG:
if (! Player.IsLangKnown() )
{
MessageBox(Player.GetWindow(),
TEXT("Can't specify audio/subpicture language until playback starts."),
TEXT("Error"), MB_OK | MB_ICONINFORMATION) ;
break ;
}
DialogBox(Player.GetInstance(), MAKEINTRESOURCE(IDD_LANGUAGE), Player.GetWindow(),
(DLGPROC) SelectLang);
break;
case IDM_VIEWLEVEL:
if (Playing == Player.GetState())
{
MessageBox(Player.GetWindow(),
TEXT("Can't change parental control level during playback. Please stop first."),
TEXT("Error"), MB_OK | MB_ICONINFORMATION) ;
break ;
}
DialogBox(Player.GetInstance(), MAKEINTRESOURCE(IDD_VIEWLEVEL), Player.GetWindow(),
(DLGPROC) SelectViewLevel);
break;
case IDM_CC:
if (Player.ClosedCaption()) // CC turned on
CheckMenuItem(hMenu, IDM_CC, MF_CHECKED) ;
else // CC turned off
CheckMenuItem(hMenu, IDM_CC, MF_UNCHECKED) ;
break ;
case IDM_FULLSCRN:
if (Player.ShowFullScreen()) // if really in fullscreen mode
CheckMenuItem(hMenu, IDM_FULLSCRN, MF_CHECKED) ;
else // full screen turned off
CheckMenuItem(hMenu, IDM_FULLSCRN, MF_UNCHECKED) ;
break;
default:
break ;
}
return 0 ;
}
LRESULT CALLBACK KeyProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case VK_ESCAPE:
{
MessageBeep(MB_OK) ;
HMENU hMenu = GetMenu(hWnd) ;
Player.StopFullScreen() ;
CheckMenuItem(hMenu, IDM_FULLSCRN, MF_UNCHECKED) ; // no fullscrn anymore
}
break ;
case VK_UP:
Player.CursorMove(Cursor_Up) ;
break ;
case VK_DOWN:
Player.CursorMove(Cursor_Down) ;
break ;
case VK_LEFT:
Player.CursorMove(Cursor_Left) ;
break ;
case VK_RIGHT:
Player.CursorMove(Cursor_Right) ;
break ;
case VK_RETURN:
Player.CursorSelect() ;
break ;
default:
break ;
}
return 0 ;
}
//
// One function to update the menu state based on the player object state.
// Used by WM_INITMENUPOPUP message handling.
//
void UpdateMenuState(void)
{
HMENU hMenu = GetMenu(Player.GetWindow()) ;
switch (Player.GetState())
{
case Unknown:
EnableMenuItem(hMenu, IDM_BUILDGRAPH, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_PAUSE, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_PLAY, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_STOP, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_SLOWPLAY, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FASTFWD, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VERYFASTFWD, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FASTRWND, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VERYFASTRWND, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_MENU, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_LANG, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VIEWLEVEL, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_CC, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FULLSCRN, MF_GRAYED) ;
break ;
case Stopped:
EnableMenuItem(hMenu, IDM_BUILDGRAPH, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_STOP, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_PAUSE, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_PLAY, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_SLOWPLAY, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_MENU, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FULLSCRN, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_LANG, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VIEWLEVEL, MF_ENABLED) ;
// CC option has been turned on/off above based on Line21Dec presence
break ;
case Paused:
EnableMenuItem(hMenu, IDM_BUILDGRAPH, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_PAUSE, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_STOP, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_PLAY, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_SLOWPLAY, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_MENU, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FULLSCRN, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_LANG, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VIEWLEVEL, MF_ENABLED) ;
break ;
case Playing:
EnableMenuItem(hMenu, IDM_BUILDGRAPH, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_PLAY, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_PAUSE, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_STOP, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_SLOWPLAY, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTFWD, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VERYFASTRWND, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_MENU, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_FULLSCRN, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_LANG, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_VIEWLEVEL, MF_ENABLED) ;
break ;
case Scanning:
EnableMenuItem(hMenu, IDM_BUILDGRAPH, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_SLOWPLAY, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FASTFWD, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VERYFASTFWD, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FASTRWND, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VERYFASTRWND, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_MENU, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_FULLSCRN, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_LANG, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_VIEWLEVEL, MF_GRAYED) ;
EnableMenuItem(hMenu, IDM_STOP, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_PAUSE, MF_ENABLED) ;
EnableMenuItem(hMenu, IDM_PLAY, MF_ENABLED) ;
break ;
default: // Huh!!!
break ;
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hDC ;
static PAINTSTRUCT ps ;
switch (message) {
case WM_INITMENUPOPUP:
UpdateMenuState() ;
break ;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps) ;
ASSERT(hDC) ;
Player.DrawStatus(hDC) ;
EndPaint(hWnd, &ps) ;
break ;
case WM_DVDPLAY_EVENT:
Player.OnDVDPlayEvent(wParam, lParam) ;
break ;
case WM_KEYUP:
KeyProc(hWnd, wParam, lParam) ;
break ;
case WM_COMMAND:
MenuProc(hWnd, wParam, lParam) ;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return 0 ;
}
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
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;
}
LRESULT CALLBACK SelectLang(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
{
Player.MakeAudioStreamList(hDlg, IDD_LANG_AUDIOLANG) ;
Player.MakeSPStreamList(hDlg, IDD_LANG_SPLANG) ;
BOOL bSPOn = IsDlgButtonChecked(hDlg, IDD_LANG_SHOWSUBPIC) ;
EnableWindow(GetDlgItem(hDlg, IDD_LANG_SPLANGTEXT), bSPOn) ;
EnableWindow(GetDlgItem(hDlg, IDD_LANG_SPLANG), bSPOn) ;
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDD_LANG_SHOWSUBPIC:
{
BOOL bSPOn = IsDlgButtonChecked(hDlg, IDD_LANG_SHOWSUBPIC) ;
EnableWindow(GetDlgItem(hDlg, IDD_LANG_SPLANGTEXT), bSPOn) ;
EnableWindow(GetDlgItem(hDlg, IDD_LANG_SPLANG), bSPOn) ;
}
break ;
case IDOK:
{
LONG lStream ;
BOOL bRes ;
// Set the SP choice value & option specified by the user
BOOL bSPOn = IsDlgButtonChecked(hDlg, IDD_LANG_SHOWSUBPIC) ;
if (bSPOn)
{
lStream = SendDlgItemMessage(hDlg, IDD_LANG_SPLANG, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0) ;
if (CB_ERR == lStream)
DbgLog((LOG_ERROR, 1,
TEXT("WARNING: Couldn't get selected SP stream id (Error %d)"), lStream)) ;
else
{
bRes = Player.SetSPState(lStream, bSPOn) ; // TRUE
ASSERT(bRes) ;
}
}
else
{
bRes = Player.SetSPState(SPSTREAM_NOCHANGE, bSPOn) ; // FALSE
ASSERT(bRes) ;
}
// Set the audio choice value specified by the user
lStream = SendDlgItemMessage(hDlg, IDD_LANG_AUDIOLANG, CB_GETCURSEL, (WPARAM) 0, (LPARAM) 0) ;
if (CB_ERR == lStream)
DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't get selected audio stream id (Error %d)"), lStream)) ;
else
{
bRes = Player.SetAudioState(lStream) ;
ASSERT(bRes) ;
}
}
// Now fall through to just end the dialog
case IDCANCEL:
EndDialog(hDlg, TRUE);
return TRUE;
}
break;
default:
break ;
}
return FALSE;
}
LRESULT CALLBACK SelectViewLevel(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
Player.MakeParentalLevelList(hDlg, IDD_VIEW_LEVELLIST) ;
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
{
LONG lLevel ;
lLevel = SendDlgItemMessage(hDlg, IDD_VIEW_LEVELLIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0) ;
if (CB_ERR == lLevel)
DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't get selected parental control level (Error %d)"), lLevel)) ;
else
Player.SetParentalLevel(lLevel) ;
}
// Now fall through to just end the dialog
case IDCANCEL:
EndDialog(hDlg, TRUE);
return TRUE;
}
break;
default:
break ;
}
return FALSE;
}
// -------------------------------------------------------------------------
// .... Windows App Requirement ends ....
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// .... CSampleDVDPlay class implementation ....
// -------------------------------------------------------------------------
CSampleDVDPlay::CSampleDVDPlay(void)
{
CoInitialize(NULL) ;
// The app stuff
m_dwRenderFlag = 0 ;
m_bMenuOn = FALSE ;
m_bCCOn = FALSE ;
m_bFullScrnOn = FALSE ;
m_ulSPStream = 0 ;
m_bSPOn = TRUE ;
m_ulAudioStream = 0 ;
m_bStillOn = FALSE ;
m_bLangKnown = FALSE ;
m_eState = Unknown ;
m_ulParentCtrlLevel = 3 ; // 3 is the index to level 6 which is for "R"
m_pDvdGB = NULL ;
m_pGraph = NULL ;
m_pDvdC = NULL ;
m_pDvdI = NULL ;
m_pVW = NULL ;
m_pMC = NULL ;
m_pME = NULL ;
ZeroMemory(m_achFileName, sizeof(m_achFileName)) ;
ZeroMemory(m_achStillText, sizeof(m_achStillText)) ;
ZeroMemory(m_achTitleText, sizeof(m_achTitleText)) ;
ZeroMemory(m_achChapterText, sizeof(m_achChapterText)) ;
ZeroMemory(m_achTimeText, sizeof(m_achTimeText)) ;
}
CSampleDVDPlay::~CSampleDVDPlay(void)
{
// Release the DS interfaces we have got
ReleaseInterfaces() ;
if (m_pDvdGB)
m_pDvdGB->Release() ;
CoUninitialize() ;
DbgLog((LOG_TRACE, 0, TEXT("CSampleDVDPlay d-tor exiting..."))) ;
}
void CSampleDVDPlay::ReleaseInterfaces(void)
{
if (m_pDvdC) {
m_pDvdC->Release() ;
m_pDvdC = NULL ;
}
if (m_pDvdI) {
m_pDvdI->Release() ;
m_pDvdI = NULL ;
}
if (m_pVW) {
m_pVW->Release() ;
m_pVW = NULL ;
}
if (m_pMC) {
m_pMC->Release() ;
m_pMC = NULL ;
}
if (m_pME) {
// clear any already set notification arrangement
m_pME->SetNotifyWindow(NULL, WM_DVDPLAY_EVENT, (ULONG)(LPVOID)m_pME) ;
m_pME->Release() ;
m_pME = NULL ;
}
if (m_pGraph) {
m_pGraph->Release() ;
m_pGraph = NULL ;
}
}
void CSampleDVDPlay::SetAppValues(HINSTANCE hInst, LPTSTR szAppName,
int iAppTitleResId)
{
// The Windows stuff
m_hInstance = hInst ;
lstrcpy(m_szAppName, APPNAME) ;
LoadString(m_hInstance, IDS_APP_TITLE, m_szTitle, 100) ;
}
BOOL CSampleDVDPlay::InitApplication(void)
{
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
m_hWnd = FindWindow (m_szAppName, m_szTitle) ;
if (m_hWnd) {
// We found another version of ourself. Lets defer to it:
if (IsIconic(m_hWnd)) {
ShowWindow(m_hWnd, SW_RESTORE);
}
SetForegroundWindow(m_hWnd);
// 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 = m_hInstance ;
wc.hIcon = LoadIcon(m_hInstance, m_szAppName) ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
wc.lpszMenuName = m_szAppName ;
wc.lpszClassName = m_szAppName ;
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 ;
}
BOOL CSampleDVDPlay::InitInstance(int nCmdShow)
{
m_hWnd = CreateWindowEx(0, m_szAppName, m_szTitle, WS_OVERLAPPEDWINDOW,
200, 400, 400, 200,
NULL, NULL, m_hInstance, NULL);
if (!m_hWnd) {
return FALSE ;
}
ShowWindow(m_hWnd, nCmdShow);
UpdateWindow(m_hWnd) ;
//
// The DirectShow stuff:
// 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)
{
MessageBox(m_hWnd,
TEXT("DirectShow DVD software not installed properly.\nPress OK to end the app."),
TEXT("Error"), MB_OK | MB_ICONSTOP) ;
return FALSE ;
}
//
// By default we use HW decoding as preferred mode. Set menu option.
// Also we don't turn on CC by default.
m_dwRenderFlag = AM_DVD_HWDEC_PREFER ;
CheckMenuItem(GetMenu(m_hWnd), IDM_HWMAX, MF_CHECKED) ;
CheckMenuItem(GetMenu(m_hWnd), IDM_CC, MF_UNCHECKED) ;
CheckMenuItem(GetMenu(m_hWnd), IDM_FULLSCRN, MF_UNCHECKED) ;
return TRUE;
}
void CSampleDVDPlay::BuildGraph(void)
{
// First release any existing interface pointer(s)
ReleaseInterfaces() ;
// 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(m_achFileName) > 0) // if something was specified before
{
#ifdef UNICODE
lstrcpy(achwFileName, m_achFileName) ;
#else
MultiByteToWideChar(CP_ACP, 0, m_achFileName, -1, achwFileName, MAX_PATH) ;
#endif // UNICODE
lpszwFileName = achwFileName ;
}
// Build the graph
AM_DVD_RENDERSTATUS Status ;
HRESULT hr = m_pDvdGB->RenderDvdVideoVolume(lpszwFileName,
m_dwRenderFlag, &Status) ;
if (FAILED(hr))
{
AMGetErrorText(hr, m_achBuffer, sizeof(m_achBuffer)) ;
MessageBox(m_hWnd, m_achBuffer, m_szAppName, MB_OK) ;
return ;
}
if (S_FALSE == hr) // if partial success
{
TCHAR achStatusText[1000] ;
if (0 == GetStatusText(&Status, achStatusText, sizeof(achStatusText)))
{
lstrcpy(achStatusText, TEXT("An unknown error has occurred")) ;
}
lstrcat(achStatusText, TEXT("\n\nDo you still want to continue?")) ;
if (IDNO == MessageBox(m_hWnd, achStatusText, TEXT("Warning"), MB_YESNO))
{
return ;
}
}
m_eState = Stopped ; // graph has been built, however bad it may be
// Now get all the interfaces to playback the DVD-Video volume
hr = m_pDvdGB->GetFiltergraph(&m_pGraph) ;
ASSERT(SUCCEEDED(hr) && m_pGraph) ;
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) m_hWnd, WM_DVDPLAY_EVENT,
(ULONG)(LPVOID)m_pME) ;
ASSERT(SUCCEEDED(hr)) ;
hr = m_pDvdGB->GetDvdInterface(IID_IDvdControl, (LPVOID *)&m_pDvdC) ;
ASSERT(SUCCEEDED(hr) && m_pDvdC) ;
hr = m_pDvdGB->GetDvdInterface(IID_IDvdInfo, (LPVOID *)&m_pDvdI) ;
ASSERT(SUCCEEDED(hr) && m_pDvdI) ;
IAMLine21Decoder *pL21Dec ;
hr = m_pDvdGB->GetDvdInterface(IID_IAMLine21Decoder, (LPVOID *)&pL21Dec) ;
if (pL21Dec)
{
EnableMenuItem(GetMenu(m_hWnd), IDM_CC, MF_ENABLED) ;
pL21Dec->SetServiceState(m_bCCOn ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off) ;
pL21Dec->Release() ;
}
else
{
EnableMenuItem(GetMenu(m_hWnd), IDM_CC, MF_GRAYED) ;
DbgLog((LOG_TRACE, 2, TEXT("Line21 Decoder interface not found. Can't CC"))) ;
}
// Now change the title of the playback window
hr = m_pDvdGB->GetDvdInterface(IID_IVideoWindow, (LPVOID *)&m_pVW) ;
if (SUCCEEDED(hr) && m_pVW)
{
TCHAR achTitle[40] ;
#ifdef UNICODE
LoadString(m_hInstance, IDS_WINDOW_TITLE, achwTitle, sizeof(achwTitle)) ;
#else
WCHAR achwTitle[40] ;
LoadString(m_hInstance, IDS_WINDOW_TITLE, achTitle, sizeof(achTitle)) ;
MultiByteToWideChar(CP_ACP, 0, achTitle, -1, achwTitle, sizeof(achwTitle)) ;
#endif // UNICODE
m_pVW->put_Caption((BSTR)achwTitle) ;
}
else
DbgLog((LOG_ERROR, 1, TEXT("IVideoWindow interface not found. No window title change."))) ;
return ;
}
BOOL CSampleDVDPlay::Play(void)
{
HRESULT hr ;
//
// If somehow the still image is On, ask Nav to get just out of that mode
//
if (m_eState != Playing && m_bStillOn && m_pDvdC)
{
if (SUCCEEDED(hr = m_pDvdC->StillOff()))
{
m_bStillOn = FALSE ;
m_eState = Playing ;
return TRUE ; // we are done!!!
}
else
DbgLog((LOG_TRACE, 3, TEXT("IDvdControl::StillOff() failed (Error 0x%lx)"), hr)) ;
}
//
// If we are scanning now, just set the scanning speed to normal, i.e, play
//
PLAYER_STATE State = GetState() ;
if (Scanning == State)
{
hr = m_pDvdC->ForwardScan(1.0) ;
ASSERT(SUCCEEDED(hr)) ;
}
//
// Parental level needs to be set every time we run, because the Nav flushes its
// settings everytime the graph is "stopped". So we better apply it on transition
// to "play".
// Use the actual value of viewing level rather than list box index
//
else if (Stopped == State) // if stopped, set parental level again
{
hr = m_pDvdC->ParentalLevelSelect(m_ViewLevels.GetValue(m_ulParentCtrlLevel)) ;
ASSERT(SUCCEEDED(hr)) ;
}
//
// We need to do some work to play...
//
if (NULL == m_pMC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
hr = m_pMC->Run() ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IMediaControl::Run() failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
// Some state changes now
m_eState = Playing ;
m_bStillOn = FALSE ; // should be, right?
return TRUE ; // success
}
BOOL CSampleDVDPlay::Stop(void)
{
if (NULL == m_pMC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
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 ;
}
m_eState = Stopped ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::Pause(void)
{
if (NULL == m_pMC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
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 ;
}
m_eState = Paused ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::FastForward(void)
{
if (NULL == m_pDvdC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
HRESULT hr = m_pDvdC->ForwardScan(2.0) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdControl::ForwardScan(2.0) failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
m_eState = Scanning ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::VeryFastForward(void)
{
if (NULL == m_pDvdC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
HRESULT hr = m_pDvdC->ForwardScan(8.0) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdControl::ForwardScan(8.0) failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
m_eState = Scanning ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::FastRewind(void)
{
if (NULL == m_pDvdC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
HRESULT hr = m_pDvdC->BackwardScan(2.0) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdControl::BackwardScan(2.0) failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
m_eState = Scanning ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::VeryFastRewind(void)
{
if (NULL == m_pDvdC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
HRESULT hr = m_pDvdC->BackwardScan(8.0) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdControl::BackwardScan(8.0) failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
m_eState = Scanning ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::SlowPlay(void)
{
if (NULL == m_pDvdC)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
HRESULT hr = m_pDvdC->ForwardScan(0.5) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdControl::ForwardScan(0.5) failed (Error 0x%lx)"), hr)) ;
return FALSE ;
}
m_eState = Scanning ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::SetSPState(LONG lSPStream, BOOL bState)
{
HRESULT hr = m_pDvdC->SubpictureStreamChange(lSPStream, bState) ;
if (SUCCEEDED(hr))
{
m_bSPOn = bState ;
m_ulSPStream = lSPStream ; // store new SP stream id
return TRUE ; // success
}
DbgLog((LOG_ERROR, 0,
TEXT("WARNING: IDvdControl::SubpictureStreamChange(%ld, %s) failed (Error 0x%lx)"),
lSPStream, bState ? TEXT("TRUE") : TEXT("FALSE"), hr)) ;
return FALSE ; // failure
}
//
// On Windows 95 (and OSR2), the locale information is not retrieved properly. To get
// the audio and subpicture language names properly, we have to do a bit of work around.
// This should be fixed in Windows 98 making the extra work unnecessary.
//
int CSampleDVDPlay::MakeSPStreamList(HWND hDlg, int iListID)
{
if (NULL == m_pDvdI)
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdInfo interface not available"))) ;
return FALSE ;
}
ULONG ulStream ;
LCID lcid ;
TCHAR achLang[MAX_PATH] ;
int iRes ;
ULONG ulNumLang ;
ULONG ulCurrLang ;
BOOL bSPOn ;
// First clear the list box of all SP stream names
SendDlgItemMessage(hDlg, iListID, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0) ;
// Now add all other available SP streams
HRESULT hr = m_pDvdI->GetCurrentSubpicture(&ulNumLang, &ulCurrLang, &bSPOn) ;
if (FAILED(hr))
{
MessageBox(m_hWnd, TEXT("Not ready to find language information"), TEXT("Warning"), MB_OK) ;
return 0 ;
}
for (ulStream = 0 ; ulStream < ulNumLang ; ulStream++)
{
if (SUCCEEDED(m_pDvdI->GetSubpictureLanguage(ulStream, &lcid)) &&
0 != lcid)
{
iRes = GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, achLang, MAX_PATH) ;
if (0 == iRes)
{
if (! GetSPLanguage(ulStream, bSPOn, achLang, MAX_PATH) ) // Pre-Win98
continue ;
}
}
else // SP language enum failed
{
if (! GetSPLanguage(ulStream, bSPOn, achLang, MAX_PATH) ) // Pre-Win98
continue ;
}
// Add to the listbox now
iRes = SendDlgItemMessage(hDlg, iListID, CB_ADDSTRING, (WPARAM) 0, (LPARAM)(LPVOID) achLang) ;
if (CB_ERR == iRes || CB_ERRSPACE == iRes)
{
DbgLog((LOG_ERROR, 1, TEXT("Error (%d) adding SP language '%s' to list"), iRes, achLang)) ;
}
}
//
// GetSPLanguage() method might have changed the currently set SP stream and/or state.
// Let's set it back to what it was before.
//
hr = m_pDvdC->SubpictureStreamChange(m_ulSPStream, m_bSPOn) ;
ASSERT(SUCCEEDED(hr)) ;
if (ulStream > 0)
{
iRes = SendDlgItemMessage(hDlg, IDD_LANG_SPLANG, CB_SETCURSEL,
(WPARAM) m_ulSPStream, (LPARAM) 0) ;
if (CB_ERR == iRes)
DbgLog((LOG_ERROR, 1,
TEXT("WARNING: Couldn't set %ld as selected SP stream id (Error %d)"),
m_ulSPStream, iRes)) ;
}
CheckDlgButton(hDlg, IDD_LANG_SHOWSUBPIC, m_bSPOn) ;
return ulStream ;
}
void CSampleDVDPlay::GetSPLangCode(DVD_SubpictureATR *pSPATR, LPTSTR lpszCode)
{
lpszCode[0] = (((LANGINFO *)pSPATR)->wLang & 0xFF) | 0x20 ; // get byte & lower case
lpszCode[1] = ((((LANGINFO *)pSPATR)->wLang >> 8) & 0xFF) | 0x20 ; // get byte & lower case
lpszCode[2] = 0 ;
}
BOOL CSampleDVDPlay::GetSPLanguage(ULONG ulStream, BOOL bSPOn, LPTSTR lpszLang, int iMaxLang)
{
HRESULT hr = m_pDvdC->SubpictureStreamChange(ulStream, bSPOn) ;
if (FAILED(hr))
return FALSE ; // stream disabled?
DVD_SubpictureATR SPATR ;
hr = m_pDvdI->GetCurrentSubpictureAttributes(&SPATR) ;
ASSERT(SUCCEEDED(hr)) ;
TCHAR achCode[3] ;
GetSPLangCode(&SPATR, achCode) ;
BOOL bRes = m_Langs.GetLangString(achCode, lpszLang) ;
ASSERT((bRes && 0 != lstrcmp(TEXT("Unknown"), lpszLang)) ||
(0 == lstrcmp(TEXT("Unknown"), lpszLang))) ;
return TRUE ; // success
}
BOOL CSampleDVDPlay::SetAudioState(LONG lAudioStream)
{
HRESULT hr = m_pDvdC->AudioStreamChange(lAudioStream) ;
if (SUCCEEDED(hr))
{
m_ulAudioStream = lAudioStream ; // store new audio stream id
return TRUE ; // success
}
DbgLog((LOG_ERROR, 0,
TEXT("WARNING: IDvdControl::AudioStreamChange(%ld) failed (Error 0x%lx)"),
lAudioStream, hr)) ;
return FALSE ; // failure
}
int CSampleDVDPlay::MakeAudioStreamList(HWND hDlg, int iListID)
{
if (NULL == m_pDvdI)
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdInfo interface not available"))) ;
return FALSE ;
}
ULONG ulStream ;
LCID lcid ;
TCHAR achLang[MAX_PATH] ;
int iRes ;
ULONG ulNumLang ;
ULONG ulCurrLang ;
// First clear the list box of all SP stream names
SendDlgItemMessage(hDlg, iListID, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0) ;
// Now add all available audio streams
HRESULT hr = m_pDvdI->GetCurrentAudio(&ulNumLang, &ulCurrLang) ;
if (FAILED(hr))
{
MessageBox(m_hWnd, TEXT("Not ready to find language information"), TEXT("Warning"), MB_OK) ;
return 0 ;
}
for (ulStream = 0 ; ulStream < ulNumLang ; ulStream++)
{
if (SUCCEEDED(m_pDvdI->GetAudioLanguage(ulStream, &lcid)) &&
0 != lcid)
{
iRes = GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, achLang, MAX_PATH) ;
if (0 == iRes)
{
if (! GetAudioLanguage(ulStream, achLang, MAX_PATH) ) // Pre-Win98
continue ;
}
}
else
{
if (! GetAudioLanguage(ulStream, achLang, MAX_PATH) ) // Pre-Win98
continue ;
}
// Add to the listbox now
iRes = SendDlgItemMessage(hDlg, iListID, CB_ADDSTRING, (WPARAM) 0, (LPARAM)(LPVOID) achLang) ;
if (CB_ERR == iRes || CB_ERRSPACE == iRes)
{
DbgLog((LOG_ERROR, 1, TEXT("Error (%d) adding audio language '%s' to list"), iRes, achLang)) ;
}
}
//
// GetAudioLanguage() method might have changed the currently set audio stream.
// Let's set it back to what it was before.
//
hr = m_pDvdC->AudioStreamChange(m_ulAudioStream) ;
ASSERT(SUCCEEDED(hr)) ;
if (ulStream > 0)
{
iRes = SendDlgItemMessage(hDlg, iListID, CB_SETCURSEL,
(WPARAM) m_ulAudioStream, (LPARAM) 0) ;
if (CB_ERR == iRes)
DbgLog((LOG_ERROR, 1,
TEXT("WARNING: Couldn't set %ld as selected audio stream id (Error %d)"),
m_ulAudioStream, iRes)) ;
}
return ulStream ;
}
void CSampleDVDPlay::GetAudioLangCode(DVD_AudioATR *pAudATR, LPTSTR lpszCode)
{
lpszCode[0] = (((LANGINFO *)pAudATR)->wLang & 0xFF) | 0x20 ; // get byte & lower case
lpszCode[1] = ((((LANGINFO *)pAudATR)->wLang >> 8) & 0xFF) | 0x20 ; // get byte & lower case
lpszCode[2] = 0 ;
}
BOOL CSampleDVDPlay::GetAudioLanguage(ULONG ulStream, LPTSTR lpszLang, int iMaxLang)
{
HRESULT hr = m_pDvdC->AudioStreamChange(ulStream) ;
if (FAILED(hr))
return FALSE ; // stream disabled?
DVD_AudioATR AudATR ;
hr = m_pDvdI->GetCurrentAudioAttributes(&AudATR) ;
ASSERT(SUCCEEDED(hr)) ;
TCHAR achCode[3] ;
GetAudioLangCode(&AudATR, achCode) ;
BOOL bRes = m_Langs.GetLangString(achCode, lpszLang) ;
ASSERT((bRes && 0 != lstrcmp(TEXT("Unknown"), lpszLang)) ||
(0 == lstrcmp(TEXT("Unknown"), lpszLang))) ;
return TRUE ; // success
}
int CSampleDVDPlay::MakeParentalLevelList(HWND hDlg, int iListID)
{
if (NULL == m_pDvdI)
{
DbgLog((LOG_ERROR, 0, TEXT("WARNING: IDvdInfo interface not available"))) ;
return FALSE ;
}
int iLevels = m_ViewLevels.GetCount() ;
int iRes ;
// First clear the list box of all SP stream names
SendDlgItemMessage(hDlg, iListID, LB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0) ;
// Now add all other available SP streams
for (int i = 0 ; i < iLevels ; i++)
{
// Add to the listbox now
iRes = SendDlgItemMessage(hDlg, iListID, LB_ADDSTRING, (WPARAM) 0,
(LPARAM)(LPVOID) m_ViewLevels.GetName(i)) ;
if (LB_ERR == iRes || LB_ERRSPACE == iRes)
{
DbgLog((LOG_ERROR, 1,
TEXT("Error (%d) adding parental level '%s'(%d) to list"),
iRes, m_ViewLevels.GetName(i), i)) ;
}
}
if (iLevels > 0)
{
iRes = SendDlgItemMessage(hDlg, iListID, LB_SETCURSEL,
(WPARAM) m_ulParentCtrlLevel, (LPARAM) 0) ;
if (LB_ERR == iRes)
{
DbgLog((LOG_ERROR, 1,
TEXT("WARNING: Couldn't set %ld as selected parent level (Error %d)"),
m_ulParentCtrlLevel, iRes)) ;
}
}
return iLevels ;
}
ULONG CSampleDVDPlay::SetParentalLevel(LONG lLevel)
{
m_ulParentCtrlLevel = lLevel ;
return m_ulParentCtrlLevel ;
}
BOOL CSampleDVDPlay::IsLangKnown(void)
{
if (NULL == m_pDvdI) // most probably graph hasn't been built yet
return FALSE ;
// Otherwise see if we can find out our current SP stream id; that indicates it
ULONG ulNumLang ;
ULONG ulSPLang ;
BOOL bSPOn ;
HRESULT hr = m_pDvdI->GetCurrentSubpicture(&ulNumLang, &ulSPLang, &bSPOn) ;
m_bLangKnown = SUCCEEDED(hr) ;
return m_bLangKnown ;
}
BOOL CSampleDVDPlay::ShowMenu(void)
{
if (NULL == m_pDvdC || NULL == m_pDvdI)
{
MessageBox(m_hWnd, TEXT("DVD-Video playback graph hasn't been built yet"), TEXT("Error"), MB_OK) ;
return FALSE ;
}
DVD_DOMAIN Domain ;
HRESULT hr = m_pDvdI->GetCurrentDomain(&Domain) ;
if (FAILED(hr))
{
DbgLog((LOG_TRACE, 0, TEXT("IDvdInfo::GetCurentDomain() failed (0x%lx)"), hr)) ;
return FALSE ;
}
//
// Decide what the menu state flag should be
//
switch (Domain)
{
case DVD_DOMAIN_FirstPlay: // lEvent = 1
case DVD_DOMAIN_Stop: // lEvent = 5
break ;
case DVD_DOMAIN_VideoManagerMenu: // lEvent = 2
case DVD_DOMAIN_VideoTitleSetMenu: // lEvent = 3
m_bMenuOn = TRUE ;
break ;
case DVD_DOMAIN_Title: // lEvent = 4
m_bMenuOn = FALSE ;
break ;
}
if (m_bMenuOn) // if ON now, turn it OFF
{
m_pDvdC->Resume() ;
m_bMenuOn = FALSE ;
// Inform the app to update the menu option to show "Menu" again
PostMessage(m_hWnd, WM_COMMAND, IDM_USER_MENUSTATUS, (LPARAM) 0) ;
return m_bMenuOn ;
}
// Turn root menu ON
hr = m_pDvdC->MenuCall(DVD_MENU_Root) ;
if (SUCCEEDED(hr))
{
m_bMenuOn = TRUE ;
// Inform the app to update the menu option to show "Resume" now
PostMessage(m_hWnd, WM_COMMAND, IDM_USER_MENUSTATUS, (LPARAM) 1) ;
return m_bMenuOn ;
}
return m_bMenuOn ;
}
BOOL CSampleDVDPlay::ClosedCaption(void)
{
IAMLine21Decoder *pL21Dec ;
m_pDvdGB->GetDvdInterface(IID_IAMLine21Decoder, (LPVOID *)&pL21Dec) ;
if (NULL == pL21Dec) // we should have not come here at all!!
MessageBox(m_hWnd, TEXT("Line21 Decoder not found. Can't show Closed Caption"), TEXT("Error"), MB_OK) ;
else
{
m_bCCOn = !m_bCCOn ;
pL21Dec->SetServiceState(m_bCCOn ?
AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off) ;
pL21Dec->Release() ;
}
return m_bCCOn ;
}
BOOL CSampleDVDPlay::ShowFullScreen(void)
{
if (NULL == m_pVW)
MessageBox(m_hWnd, TEXT("Video interface not found. Can't show in full screen mode."), TEXT("Error"), MB_OK) ;
else
{
if (!m_bFullScrnOn)
StartFullScreen() ;
else
StopFullScreen() ;
}
return m_bFullScrnOn ;
}
void CSampleDVDPlay::SetRenderFlag(DWORD dwFlag)
{
if (AM_DVD_NOVPE == dwFlag) // VPE related flag
m_dwRenderFlag ^= dwFlag ;
else // HW/SW Dec related flag
m_dwRenderFlag = (dwFlag | (AM_DVD_NOVPE & m_dwRenderFlag)) ;
}
DWORD CSampleDVDPlay::GetStatusText(AM_DVD_RENDERSTATUS *pStatus,
LPTSTR lpszStatusText,
DWORD dwMaxText)
{
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, "* ") ;
lpszBuff += lstrlen("* ") ;
iChars = AMGetErrorText(pStatus->hrVPEStatus, lpszBuff, 200) ;
lpszBuff += iChars ;
lstrcat(lpszBuff, "\n") ;
lpszBuff += lstrlen("\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 ;
}
BOOL CSampleDVDPlay::FileSelect(void)
{
OPENFILENAME ofn ;
TCHAR achFileName[MAX_PATH] ;
// Init the filename buffer with either a filename or *.ifo
if (lstrlen(m_achFileName) > 0)
lstrcpy(achFileName, m_achFileName) ;
else
lstrcpy(achFileName, TEXT("*.ifo")) ;
ZeroMemory(&ofn, sizeof(OPENFILENAME)) ;
ofn.lStructSize = sizeof(OPENFILENAME) ;
ofn.hwndOwner = m_hWnd ;
ofn.lpstrFilter = TEXT("IFO Files\0*.ifo\0All Files\0*.*\0") ;
ofn.nFilterIndex = 1 ;
ofn.lpstrFile = achFileName ;
ofn.nMaxFile = sizeof(achFileName) ;
ofn.lpstrFileTitle = NULL ;
ofn.lpstrTitle = TEXT("Select DVD-Video Volume") ;
ofn.nMaxFileTitle = 0 ;
ofn.lpstrInitialDir = NULL ;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY ;
if (GetOpenFileName(&ofn)) // user specified a file
{
if (m_pDvdC) // Graph has already been built; set it now
{
Stop() ; // first ask player to stop the playback.
// Convert TCHAR filename to WCHAR for COM
WCHAR achwFileName[MAX_PATH] ;
#ifdef UNICODE
lstrcpy(achwFileName, achFileName) ;
#else
MultiByteToWideChar(CP_ACP, 0, achFileName, -1, achwFileName, MAX_PATH) ;
#endif // UNICODE
HRESULT hr = m_pDvdC->SetRoot(achwFileName) ;
if (SUCCEEDED(hr)) // if the new file name is valid DVD-video volume
{
lstrcpy(m_achFileName, achFileName) ; // store it
}
else
DbgLog((LOG_ERROR, 2, TEXT("WARNING: SetRoot(%s) failed (Error 0x%lx)"), achFileName, hr)) ;
}
else // graph not yet built; store name and use in graph building
{
lstrcpy(m_achFileName, achFileName) ;
}
return TRUE ; // DVD-Video volume changed
}
// Either failed or user hit Esc.
DWORD dw = CommDlgExtendedError() ;
DbgLog((LOG_TRACE, 3, TEXT("GetOpenFileName() cancelled/failed with error %lu"), dw)) ;
return FALSE ; // DVD-Video volume not changed
}
LPTSTR CSampleDVDPlay::GetStringRes(int id)
{
LoadString(GetModuleHandle(NULL), id, m_achBuffer, 100) ;
return m_achBuffer ;
}
HRESULT CSampleDVDPlay::OnDVDPlayEvent(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam == (LONG)(LPVOID) m_pME) ;
LONG lEvent ;
LONG 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(m_pME->GetEvent(&lEvent, &lParam1, &lParam2, 0))) // no wait
{
switch (lEvent)
{
//
// First the DVD related events
//
case EC_DVD_STILL_ON:
if (1 == lParam1 && 0xFFFFFFFF == lParam2)
{
wsprintf(m_achStillText, TEXT("Still On")) ;
InvalidateRect(m_hWnd, NULL, TRUE) ;
}
break ;
case EC_DVD_STILL_OFF:
wsprintf(m_achStillText, TEXT("Still Off")) ;
InvalidateRect(m_hWnd, NULL, TRUE) ;
break ;
case EC_DVD_DOMAIN_CHANGE:
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
PostMessage(m_hWnd, WM_COMMAND, IDM_USER_MENUSTATUS, (LPARAM) 1) ;
m_bMenuOn = TRUE ; // now menu is "On"
break ;
case DVD_DOMAIN_Title: // = 4
// Inform the app to update the menu option to show "Menu" again
PostMessage(m_hWnd, WM_COMMAND, IDM_USER_MENUSTATUS, (LPARAM) 0) ;
m_bMenuOn = FALSE ; // now menu is "Off"
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:
wsprintf(m_achTitleText, TEXT("Title %ld"), lParam1) ;
InvalidateRect(m_hWnd, NULL, TRUE) ;
break ;
case EC_DVD_CHAPTER_START:
wsprintf(m_achChapterText, TEXT("Chapter %ld"), lParam1) ;
InvalidateRect(m_hWnd, NULL, TRUE) ;
break ;
case EC_DVD_CURRENT_TIME:
{
DVD_TIMECODE *pTime = (DVD_TIMECODE *) &lParam1 ;
wsprintf(m_achTimeText, TEXT("Current Time is %d%d:%d%d:%d%d"),
pTime->Hours10, pTime->Hours1,
pTime->Minutes10, pTime->Minutes1,
pTime->Seconds10, pTime->Seconds1) ;
InvalidateRect(m_hWnd, NULL, TRUE) ;
}
break ;
//
// Then the general DirectShow related events
//
case EC_COMPLETE:
DbgLog((LOG_TRACE, 5, TEXT("DVD Event: Playback complete"))) ;
m_pMC->Stop() ; // DShow doesn't stop on end; we should do that
// fall through now...
case EC_USERABORT:
case EC_ERRORABORT:
case EC_FULLSCREEN_LOST:
DbgLog((LOG_TRACE, 5, TEXT("DVD Event: 0x%lx"), lEvent)) ;
StopFullScreen() ; // we must get out of fullscreen mode now
break ;
default:
DbgLog((LOG_TRACE, 5, TEXT("Unknown DVD Event: 0x%lx"), lEvent)) ;
break ;
}
//
// Remember to free the event params
//
m_pME->FreeEventParams(lEvent, lParam1, lParam2) ;
} // end of while (GetEvent()) loop
return 0 ;
}
void CSampleDVDPlay::DrawStatus(HDC hDC)
{
TextOut(hDC, 10, 10, m_achStillText, lstrlen(m_achStillText)) ;
TextOut(hDC, 10, 25, m_achTitleText, lstrlen(m_achTitleText)) ;
TextOut(hDC, 110, 25, m_achChapterText, lstrlen(m_achChapterText)) ;
TextOut(hDC, 10, 40, m_achTimeText, lstrlen(m_achTimeText)) ;
}
void CSampleDVDPlay::CursorMove(CURSOR_DIR Dir)
{
if (! m_bMenuOn ) // if menu is not ON, we can't select!!
return ;
switch (Dir)
{
case Cursor_Up:
m_pDvdC->UpperButtonSelect() ;
break ;
case Cursor_Down:
m_pDvdC->LowerButtonSelect() ;
break ;
case Cursor_Left:
m_pDvdC->LeftButtonSelect() ;
break ;
case Cursor_Right:
m_pDvdC->RightButtonSelect() ;
break ;
default: // huh!!!
break ;
}
}
void CSampleDVDPlay::CursorSelect(void)
{
if (m_bMenuOn)
m_pDvdC->ButtonActivate() ;
}
BOOL CSampleDVDPlay::StartFullScreen()
{
DbgLog((LOG_TRACE, 5, TEXT("CSampleDVDPlay::StartFullScreen()"))) ;
if (NULL == m_pVW)
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StartFullScreen() -- no IVideoWindow pointer yet"))) ;
return m_bFullScrnOn ;
}
HRESULT hr ;
hr = m_pVW->put_MessageDrain((OAHWND) m_hWnd) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StartFullScreen() -- IVideoWindow::put_MessageDrain() failed (0x%lx)"),
hr)) ;
return m_bFullScrnOn ;
}
hr = m_pVW->put_FullScreenMode(OATRUE) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StartFullScreen() -- IVideoWindow::put_FullScreenMode() failed (0x%lx)"),
hr)) ;
return m_bFullScrnOn ;
}
m_bFullScrnOn = TRUE ; // we are really in full screen mode
return m_bFullScrnOn ;
}
BOOL CSampleDVDPlay::StopFullScreen()
{
DbgLog((LOG_TRACE, 5, TEXT("CSampleDVDPlay::StopFullScreen()"))) ;
HRESULT hr ;
if (NULL == m_pVW)
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StopFullScreen() -- no IVideoWindow pointer yet"))) ;
return m_bFullScrnOn ;
}
hr = m_pVW->put_FullScreenMode(OAFALSE) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StopFullScreen() -- IVideoWindow::put_FullScreenMode() failed (0x%lx)"),
hr)) ;
return m_bFullScrnOn ;
}
hr = m_pVW->put_MessageDrain((OAHWND) NULL) ;
if (FAILED(hr))
{
DbgLog((LOG_ERROR, 0,
TEXT("CSampleDVDPlay::StopFullScreen() -- IVideoWindow::put_MessageDrain() failed (0x%lx)"),
hr)) ;
return m_bFullScrnOn ;
}
m_bFullScrnOn = FALSE ; // we are no more in full screen mode
return m_bFullScrnOn ;
}
CViewLevels::CViewLevels()
{
m_iCount = 6 ;
m_alpszNames[0] = TEXT(" G ") ; m_aiValues[0] = 1 ;
m_alpszNames[1] = TEXT(" PG ") ; m_aiValues[1] = 3 ;
m_alpszNames[2] = TEXT(" PG-13 ") ; m_aiValues[2] = 4 ;
m_alpszNames[3] = TEXT(" R ") ; m_aiValues[3] = 6 ;
m_alpszNames[4] = TEXT(" NC-17 ") ; m_aiValues[4] = 7 ;
m_alpszNames[5] = TEXT(" Adult ") ; m_aiValues[5] = 8 ;
}
//
// Only 10 languages have been used here as a sample. The list can be extended to
// include any language listed in ISO 639.
//
CDVDLanguages::CDVDLanguages()
{
m_alpszCodes[0] = TEXT("de") ; m_alpszLangNames[0] = TEXT("German") ;
m_alpszCodes[1] = TEXT("en") ; m_alpszLangNames[1] = TEXT("English") ;
m_alpszCodes[2] = TEXT("es") ; m_alpszLangNames[2] = TEXT("Spanish") ;
m_alpszCodes[3] = TEXT("fr") ; m_alpszLangNames[3] = TEXT("French") ;
m_alpszCodes[4] = TEXT("ja") ; m_alpszLangNames[4] = TEXT("Japanese") ;
m_alpszCodes[5] = TEXT("ko") ; m_alpszLangNames[5] = TEXT("Korean") ;
m_alpszCodes[6] = TEXT("ni") ; m_alpszLangNames[6] = TEXT("Dutch") ;
m_alpszCodes[7] = TEXT("pt") ; m_alpszLangNames[7] = TEXT("Portuguese") ;
m_alpszCodes[8] = TEXT("sv") ; m_alpszLangNames[8] = TEXT("Swedish") ;
m_alpszCodes[9] = TEXT("zh") ; m_alpszLangNames[9] = TEXT("Chinese") ;
}
BOOL CDVDLanguages::GetLangString(LPTSTR lpszCode, LPTSTR lpszLang)
{
for (int i = 0 ; i < 10 ; i++)
{
if (0 == lstrcmp(lpszCode, m_alpszCodes[i])) // match!!
{
lstrcpy(lpszLang, m_alpszLangNames[i]) ;
return TRUE ; // got a match
}
}
lstrcpy(lpszLang, TEXT("Unknown")) ;
return FALSE ; // didn't get a match
}