Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Players/PlayDMO/PlayDMODlg.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

1140 lines
30 KiB
C++

//------------------------------------------------------------------------------
// File: PlayDMODlg.cpp
//
// Desc: DirectShow sample code - Implementation for CPlayDMODlg
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "PlayDMO.h"
#include "PlayDMODlg.h"
#include <mtype.h>
#define DEFAULT_FILENAME TEXT("c:\\")
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPlayDMODlg dialog
CPlayDMODlg::CPlayDMODlg(CWnd* pParent /*=NULL*/)
: CDialog(CPlayDMODlg::IDD, pParent), m_pVW(0), m_pGB(0), m_pMC(0)
{
//{{AFX_DATA_INIT(CPlayDMODlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CPlayDMODlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPlayDMODlg)
DDX_Control(pDX, IDC_BUTTON_PROPPAGE, m_btnProperties);
DDX_Control(pDX, IDC_STATIC_STATUS, m_strStatus);
DDX_Control(pDX, IDC_STATIC_OUT_MINBUFFERSIZE, m_nOutBufferSize);
DDX_Control(pDX, IDC_STATIC_OUT_ALIGNMENT, m_nOutAlignment);
DDX_Control(pDX, IDC_STATIC_MAXLATENCY, m_nMaxLatency);
DDX_Control(pDX, IDC_STATIC_IN_MINBUFFERSIZE, m_nInBufferSize);
DDX_Control(pDX, IDC_STATIC_IN_MAXLOOKAHEAD, m_nInLookahead);
DDX_Control(pDX, IDC_STATIC_IN_ALIGNMENT, m_nInAlignment);
DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
DDX_Control(pDX, IDC_LIST_FILTER_OUTPUTS, m_ListFilterOutputs);
DDX_Control(pDX, IDC_LIST_FILTER_INPUTS, m_ListFilterInputs);
DDX_Control(pDX, IDC_LIST_AUDIO_DMOS, m_ListAudioDMO);
DDX_Control(pDX, IDC_EDIT_FILENAME, m_StrFilename);
DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
DDX_Control(pDX, IDC_BUTTON_PLAY, m_btnPlay);
DDX_Control(pDX, IDC_BUTTON_PAUSE, m_btnPause);
DDX_Control(pDX, IDC_SCREEN, m_Screen);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPlayDMODlg, CDialog)
//{{AFX_MSG_MAP(CPlayDMODlg)
ON_WM_ERASEBKGND()
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_CLOSE()
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BUTTON_PLAY, OnButtonPlay)
ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnButtonPause)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_BN_CLICKED(IDC_BUTTON_FILE, OnButtonFile)
ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
ON_BN_CLICKED(IDC_BUTTON_ADD_DMO, OnButtonAddDmo)
ON_BN_CLICKED(IDC_BUTTON_CLEAR, OnButtonClear)
ON_BN_CLICKED(IDC_BUTTON_PROPPAGE, OnButtonProppage)
ON_LBN_DBLCLK(IDC_LIST_FILTERS, OnDblclkListFilters)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPlayDMODlg message handlers
void CPlayDMODlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CPlayDMODlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CPlayDMODlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BOOL CPlayDMODlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
////////////////////////////////////////////////////////////////////////
//
// DirectShow-specific initialization code
CoInitialize(NULL);
SetDefaults();
// Initialize DirectShow and query for needed interfaces
HRESULT hr = InitDirectShow();
if(FAILED(hr))
{
RetailOutput(TEXT("Failed to initialize DirectShow! hr=0x%x\r\n"), hr);
return FALSE;
}
// IMPORTANT
// Since we're embedding video in a child window of a dialog,
// we must set the WS_CLIPCHILDREN style to prevent the bounding
// rectangle from drawing over our video frames.
//
// Neglecting to set this style can lead to situations when the video
// is erased and replaced with black (or the default color of the
// bounding rectangle).
m_Screen.ModifyStyle(0, WS_CLIPCHILDREN);
hr = FillLists();
if(FAILED(hr))
{
RetailOutput(TEXT("Failed to fill DMO list! hr=0x%x\r\n"), hr);
return FALSE;
}
return TRUE; // return TRUE unless you set the focus to a control
}
void CPlayDMODlg::SetDefaults()
{
// Zero DirectShow interface pointers (sanity check)
m_pGB=0;
m_pMS=0;
m_pMC=0;
m_pME=0;
m_pVW=0;
// Zero DMO list
for (int i=0; i<MAX_DMOS; i++)
m_pDMOList[i] = 0;
// Set default values for controls on the dialog
m_StrFilename.SetWindowText(DEFAULT_FILENAME);
g_psCurrent = State_Stopped;
}
HRESULT CPlayDMODlg::FillLists()
{
HRESULT hr;
// Enumerate and display the audio DMOs installed in the system
hr = AddDMOsToList(&DMOCATEGORY_AUDIO_EFFECT, m_ListAudioDMO, TRUE);
if (FAILED(hr))
return hr;
// Set internal variables
m_nLoadedDMOs = 0;
m_nDMOCount = m_ListAudioDMO.GetCount();
return hr;
}
//
// Displays a text string in a status line near the bottom of the dialog
//
void CPlayDMODlg::Say(LPTSTR szText)
{
m_strStatus.SetWindowText(szText);
}
HRESULT CPlayDMODlg::InitDirectShow(void)
{
HRESULT hr = S_OK;
m_bAudioOnly = FALSE;
// Get interfaces
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&m_pGB));
JIF(m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC));
JIF(m_pGB->QueryInterface(IID_IMediaSeeking, (void **)&m_pMS));
JIF(m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW));
JIF(m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME));
return S_OK;
CLEANUP:
FreeDirectShow();
return(hr);
}
HRESULT CPlayDMODlg::FreeDirectShow(void)
{
HRESULT hr=S_OK;
StopMedia();
// Disable event callbacks
if (m_pME)
hr = m_pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
// Hide video window and remove owner. This is not necessary here,
// since we are about to destroy the filter graph, but it is included
// for demonstration purposes. Remember to hide the video window and
// clear its owner when destroying a window that plays video.
if(m_pVW)
{
hr = m_pVW->put_Visible(OAFALSE);
hr = m_pVW->put_Owner(NULL);
}
#ifdef DEBUG
RemoveGraphFromRot(m_dwRegister);
#endif
RemoveDMOsFromGraph();
SAFE_RELEASE(m_pMC);
SAFE_RELEASE(m_pMS);
SAFE_RELEASE(m_pVW);
SAFE_RELEASE(m_pME);
SAFE_RELEASE(m_pGB);
ClearLists();
return hr;
}
void CPlayDMODlg::ResetDirectShow(void)
{
// Destroy the current filter graph its filters.
FreeDirectShow();
// Reinitialize graph builder and query for interfaces
InitDirectShow();
}
void CPlayDMODlg::ClearAllocatedLists()
{
// Clear the lists and delete the allocated CLSID bytes
ClearFilterListWithCLSID(m_ListAudioDMO);
}
void CPlayDMODlg::ClearLists()
{
// Clear the lists that don't contain extra data
m_ListFilters.ResetContent();
m_ListFilterInputs.ResetContent();
m_ListFilterOutputs.ResetContent();
}
void CPlayDMODlg::OnClose()
{
// Release DirectShow interfaces
StopMedia();
FreeDirectShow();
ClearAllocatedLists();
// Release COM
CoUninitialize();
CDialog::OnClose();
}
void CPlayDMODlg::OnDestroy()
{
// Release DirectShow interfaces
FreeDirectShow();
ClearAllocatedLists();
CDialog::OnDestroy();
}
void CPlayDMODlg::OnButtonPlay()
{
if (g_psCurrent == State_Paused)
{
RunMedia();
}
else
{
if (SUCCEEDED(OnSelectFile()))
{
// Add any selected DMOs to the graph
OnButtonAddDmo();
// Disconnect audio renderer and insert DMOs
if (m_nLoadedDMOs != 0)
{
if (FAILED(ConnectDMOsToRenderer()))
{
MessageBeep(0);
EnableButtons(FALSE);
return;
}
}
EnableButtons(FALSE);
RunMedia();
}
else
{
MessageBox(TEXT("Please enter a valid media file name."),
TEXT("Error opening media file!"));
return;
}
}
Say(TEXT("Running"));
}
void CPlayDMODlg::OnButtonPause()
{
PauseMedia();
Say(TEXT("Paused"));
}
void CPlayDMODlg::OnButtonStop()
{
HRESULT hr;
// Stop playback immediately with IMediaControl::Stop().
StopMedia();
EnableButtons(TRUE);
// Reset to beginning of media clip
LONGLONG pos=0;
hr = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to seek to beginning of media! hr=0x%x\r\n"), hr);
}
// Display the first frame of the media clip, if it contains video.
// StopWhenReady() pauses all filters internally (which allows the video
// renderer to queue and display the first video frame), after which
// it sets the filters to the stopped state. This enables easy preview
// of the video's poster frame.
hr = m_pMC->StopWhenReady();
if (FAILED(hr))
{
RetailOutput(TEXT("Failed in StopWhenReady! hr=0x%x\r\n"), hr);
}
Say(TEXT("Stopped"));
}
void CPlayDMODlg::OnButtonFile()
{
CFileDialog dlgFile(TRUE);
CString title;
CString strFilter, strDefault, strFilename;
VERIFY(title.LoadString(AFX_IDS_OPENFILE));
// Initialize the file extensions and descriptions
strFilter += "Media Files (*.avi, *.mpg, *.wav, *.mid)";
strFilter += (TCHAR)'\0';
strFilter += _T("*.avi;*.mpg;*.wav;*.mid");
strFilter += (TCHAR)'\0';
dlgFile.m_ofn.nMaxCustFilter++;
CString allFilter;
VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));
// Append the "*.*" all files filter
strFilter += allFilter;
strFilter += (TCHAR)'\0'; // next string
strFilter += _T("*.*");
strFilter += (TCHAR)'\0\0'; // last string
dlgFile.m_ofn.nMaxCustFilter++;
dlgFile.m_ofn.lpstrFilter = strFilter;
dlgFile.m_ofn.lpstrTitle = title;
dlgFile.m_ofn.lpstrFile = strFilename.GetBuffer(_MAX_PATH);
// Display the file open dialog
INT_PTR nResult = dlgFile.DoModal();
// If a file was selected, update the main dialog
if (nResult == IDOK)
{
m_StrFilename.SetWindowText(strFilename);
// Render this file and show the first video frame, if present
OnSelectFile();
}
strFilename.ReleaseBuffer();
}
void CPlayDMODlg::OnButtonAddDmo()
{
// Release any currently loaded DMOs
RemoveDMOsFromGraph();
// Add the currently selected DMOs to the graph
AddDMOsToGraph();
// Update the graph filter display to show rendered graph
AddGraphFiltersToList(m_pGB, m_ListFilters);
}
void CPlayDMODlg::OnButtonClear()
{
// Release any currently loaded DMOs
RemoveDMOsFromGraph();
// Clear the list of active DMOs
m_ListAudioDMO.SelItemRange(FALSE, 0, m_nDMOCount);
// Update the graph filter display to show rendered graph
AddGraphFiltersToList(m_pGB, m_ListFilters);
}
HRESULT CPlayDMODlg::RemoveDMOsFromGraph(void)
{
HRESULT hr=S_OK;
// Remove and release each loaded DMO
for (int i=0; i < m_nLoadedDMOs; i++)
{
if (m_pDMOList[i])
{
// Remove filter from graph.
hr = m_pGB->RemoveFilter(m_pDMOList[i]);
// Since we're not holding a reference to the filter,
// there's no need to Release() it, but do clear the variable.
m_pDMOList[i]=0;
}
}
m_nLoadedDMOs = 0;
return hr;
}
HRESULT CPlayDMODlg::AddDMOsToGraph(void)
{
USES_CONVERSION;
HRESULT hr=S_OK;
IBaseFilter *pDMOFilter=0;
IDMOWrapperFilter *pWrap;
CLSID *pStoredCLSID = NULL;
int rnItems[MAX_DMOS];
WCHAR wszDMOName[64];
TCHAR szItem[64];
// Clear status
m_nLoadedDMOs = 0;
// Get a list of the DMO entries selected in the multiple-select listbox
int nSelected = m_ListAudioDMO.GetSelItems(MAX_DMOS, rnItems);
// Load each selected DMO and add it to the graph
for (int i=0; i < nSelected; i++)
{
// Read this DMO's CLSID from the list box
pStoredCLSID = (CLSID *) m_ListAudioDMO.GetItemDataPtr(rnItems[i]);
// Create the DMO Wrapper filter.
hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void **)&pDMOFilter);
if (FAILED(hr))
continue;
// Get its DMOWrapperFilter interface so that it can be added to
// the DirectShow filter graph
hr = pDMOFilter->QueryInterface(IID_IDMOWrapperFilter, (void **)&pWrap);
if (SUCCEEDED(hr))
{
// Initialize the wrapper filter with our DMO's CLSID and category
hr = pWrap->Init(*pStoredCLSID, DMOCATEGORY_AUDIO_EFFECT);
if (FAILED(hr))
{
pWrap->Release();
pDMOFilter->Release();
continue;
}
pWrap->Release();
// Read the DMO's name and convert to a wide string
m_ListAudioDMO.GetText(rnItems[i], szItem);
wcscpy(wszDMOName, T2W(szItem));
// Add the DMO to the graph
hr = m_pGB->AddFilter(pDMOFilter, wszDMOName);
if (FAILED(hr))
return hr;
// If this filter was added to the graph, save its reference
// and increment the count of loaded DMOs
m_pDMOList[i] = pDMOFilter;
m_nLoadedDMOs++;
}
pDMOFilter->Release();
}
return hr;
}
void CPlayDMODlg::OnSelchangeListFilters()
{
IBaseFilter *pFilter = NULL;
TCHAR szNameToFind[128];
// Use a helper function to display the filter's pins in listboxes
AddFilterPinsToLists(m_pGB, m_ListFilters, m_ListFilterInputs, m_ListFilterOutputs);
// Read the current filter name from the list box
m_ListFilters.GetText(m_ListFilters.GetCurSel(), szNameToFind);
// Read the current list box name and find it in the graph.
// Display DMO-specific information if present in the graph.
pFilter = FindFilterFromName(m_pGB, szNameToFind);
if (pFilter)
{
HRESULT hr;
IMediaObject *pDMO=NULL;
// Find out if this filter supports a property page
if (SupportsPropertyPage(pFilter))
m_btnProperties.EnableWindow(TRUE);
else
m_btnProperties.EnableWindow(FALSE);
// If this is a DMO, it will support IMediaObject, so show more info.
hr = pFilter->QueryInterface(IID_IMediaObject, (void**) &pDMO);
// Show information or default values
ShowInputBufferInfo(pDMO, 0);
ShowOutputBufferInfo(pDMO, 0);
if (SUCCEEDED(hr))
pDMO->Release();
pFilter->Release();
}
}
HRESULT CPlayDMODlg::OnSelectFile()
{
HRESULT hr;
TCHAR szFilename[MAX_PATH];
// Read file name from list box
m_StrFilename.GetWindowText(szFilename, MAX_PATH);
// First release any existing interfaces
ResetDirectShow();
// Clear filter/pin/event information listboxes
m_ListFilters.ResetContent();
m_ListFilterInputs.ResetContent();
m_ListFilterOutputs.ResetContent();
// Load the selected media file
hr = PrepareMedia(szFilename);
if (FAILED(hr))
{
MessageBeep(0);
return hr;
}
else
{
m_btnPlay.EnableWindow(TRUE);
}
// Enumerate and display filters in graph
hr = AddGraphFiltersToList(m_pGB, m_ListFilters);
// Select the first filter in the list to display pin info
m_ListFilters.SetCurSel(0);
OnSelchangeListFilters();
// Cue the first video frame
m_pMC->StopWhenReady();
return hr;
}
HRESULT CPlayDMODlg::PrepareMedia(LPTSTR lpszMovie)
{
USES_CONVERSION;
HRESULT hr = S_OK;
Say(TEXT("Loading..."));
// Allow DirectShow to create the FilterGraph for this media file
hr = m_pGB->RenderFile(T2W(lpszMovie), NULL);
if (FAILED(hr)) {
RetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
hr, lpszMovie);
return hr;
}
// Add our filter graph to the running object table for debugging
#ifdef DEBUG
AddGraphToRot(m_pGB, &m_dwRegister);
#endif
// Set the message drain of the video window to point to our main
// application window. If this is an audio-only or MIDI file,
// then put_MessageDrain will fail.
hr = m_pVW->put_MessageDrain((OAHWND) m_hWnd);
if (FAILED(hr))
{
m_bAudioOnly = TRUE;
}
// Have the graph signal events via window callbacks
hr = m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
// Configure the video window
if (!m_bAudioOnly)
{
hr = m_pVW->put_Owner((OAHWND) m_Screen.GetSafeHwnd());
hr = m_pVW->put_WindowStyle(WS_CHILD);
// We'll manually set the video to be visible
hr = m_pVW->put_Visible(OAFALSE);
// Place video window within the bounding rectangle
CenterVideo();
// Make the video window visible within the screen window.
// If this is an audio-only file, then there won't be a video interface.
hr = m_pVW->put_Visible(OATRUE);
hr = m_pVW->SetWindowForeground(-1);
}
Say(TEXT("Ready"));
return hr;
}
void CPlayDMODlg::CenterVideo(void)
{
LONG width, height;
HRESULT hr;
if ((m_bAudioOnly) || (!m_pVW))
return;
// Read coordinates of video container window
RECT rc;
m_Screen.GetClientRect(&rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
// Ignore the video's original size and stretch to fit bounding rectangle
hr = m_pVW->SetWindowPosition(rc.left, rc.top, width, height);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to set window position! hr=0x%x\r\n"), hr);
return;
}
}
LRESULT CPlayDMODlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// Field notifications from the DirectShow filter graph manager
// and those posted by the application
switch (message)
{
case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;
}
// Pass along this message to the video window, which exists as a child
// of the m_Screen window. This method should be used by windows that
// make a renderer window a child window. It forwards significant messages
// to the child window that the child window would not otherwise receive.
if (m_pVW)
{
m_pVW->NotifyOwnerMessage((LONG_PTR) m_hWnd, message, wParam, lParam);
}
return CDialog::WindowProc(message, wParam, lParam);
}
HRESULT CPlayDMODlg::HandleGraphEvent(void)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
// Check that event interface is still valid
if (!m_pME)
return S_OK;
// Spin through the events
while(SUCCEEDED(hr = m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
(LONG_PTR *) &evParam2, 0)))
{
if(EC_COMPLETE == evCode)
{
// Since we're looping, reset to beginning and continue playing
LONGLONG pos=0;
hr = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
}
// Free memory associated with this event
hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
}
return hr;
}
HRESULT CPlayDMODlg::RunMedia()
{
HRESULT hr=S_OK;
if (!m_pMC)
return S_OK;
// Start playback
hr = m_pMC->Run();
if (FAILED(hr)) {
RetailOutput(TEXT("\r\n*** Failed(%08lx) in Run()!\r\n"), hr);
return hr;
}
// Remember play state
g_psCurrent = State_Running;
return hr;
}
HRESULT CPlayDMODlg::StopMedia()
{
HRESULT hr=S_OK;
if (!m_pMC)
return S_OK;
// If we're already stopped, don't check again
if (g_psCurrent == State_Stopped)
return hr;
// Stop playback
hr = m_pMC->Stop();
if (FAILED(hr)) {
RetailOutput(TEXT("\r\n*** Failed(%08lx) in Stop()!\r\n"), hr);
return hr;
}
// Wait for the stop to propagate to all filters
OAFilterState fs;
hr = m_pMC->GetState(500, &fs);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to read graph state! hr=0x%x\r\n"), hr);
}
// Remember play state
g_psCurrent = State_Stopped;
return hr;
}
HRESULT CPlayDMODlg::PauseMedia(void)
{
HRESULT hr=S_OK;
if (!m_pMC)
return S_OK;
// Don't pause unless we're in the running state
if(g_psCurrent != State_Running)
return S_OK;
// Pause playback
hr = m_pMC->Pause();
if (FAILED(hr)) {
RetailOutput(TEXT("\r\n*** Failed(%08lx) in Pause()!\r\n"), hr);
return hr;
}
// Remember play state
g_psCurrent = State_Paused;
return hr;
}
void CPlayDMODlg::OnButtonProppage()
{
IBaseFilter *pFilter = NULL;
TCHAR szNameToFind[128];
// Read the current filter name from the list box
int nCurSel = m_ListFilters.GetCurSel();
m_ListFilters.GetText(nCurSel, szNameToFind);
// Find this filter in the graph
pFilter = FindFilterFromName(m_pGB, szNameToFind);
if (!pFilter)
return;
// Show the property page for the selected DMO or filter
ShowFilterPropertyPage(pFilter, m_hWnd);
}
void CPlayDMODlg::OnDblclkListFilters()
{
// Show the property page for the selected DMO or filter
OnButtonProppage();
}
void CPlayDMODlg::ShowInputBufferInfo(IMediaObject *pDMO, int nSel)
{
HRESULT hr;
TCHAR sz[32];
DWORD dwSize=0, dwLookahead=0, dwAlign=0;
// If the selected item is not a DMO, display default information
if (!pDMO)
{
m_nInBufferSize.SetWindowText(STR_NOTDMO);
m_nInLookahead.SetWindowText(STR_NOTDMO);
m_nInAlignment.SetWindowText(STR_NOTDMO);
m_nMaxLatency.SetWindowText(STR_NOTDMO);
return;
}
// Read/display maximum latency
REFERENCE_TIME reftime=0;
hr = pDMO->GetInputMaxLatency(nSel, &reftime);
if (SUCCEEDED(hr))
{
DWORD dwLatency = (DWORD) (reftime * 100000);
wsprintf(sz, TEXT("%ld"), dwLatency);
m_nMaxLatency.SetWindowText(sz);
}
else if (hr == E_NOTIMPL)
m_nMaxLatency.SetWindowText(TEXT("0"));
else
m_nMaxLatency.SetWindowText(STR_UNKNOWN);
// Read/display input buffer size information
hr = pDMO->GetInputSizeInfo(nSel, &dwSize, &dwLookahead, &dwAlign);
if (SUCCEEDED(hr))
{
wsprintf(sz, TEXT("%ld"), dwSize);
m_nInBufferSize.SetWindowText(sz);
wsprintf(sz, TEXT("%ld"), dwLookahead);
m_nInLookahead.SetWindowText(sz);
wsprintf(sz, TEXT("%ld"), dwAlign);
m_nInAlignment.SetWindowText(sz);
}
else
{
m_nInBufferSize.SetWindowText(STR_UNKNOWN);
m_nInLookahead.SetWindowText(STR_UNKNOWN);
m_nInAlignment.SetWindowText(STR_UNKNOWN);
}
}
void CPlayDMODlg::ShowOutputBufferInfo(IMediaObject *pDMO, int nSel)
{
HRESULT hr;
TCHAR sz[32];
DWORD dwSize=0, dwAlign=0;
// If the selected item is not a DMO, display default information
if (!pDMO)
{
m_nOutBufferSize.SetWindowText(STR_NOTDMO);
m_nOutAlignment.SetWindowText(STR_NOTDMO);
return;
}
// Read/display output buffer size information
hr = pDMO->GetOutputSizeInfo(nSel, &dwSize, &dwAlign);
if (SUCCEEDED(hr))
{
wsprintf(sz, TEXT("%ld"), dwSize);
m_nOutBufferSize.SetWindowText(sz);
wsprintf(sz, TEXT("%ld"), dwAlign);
m_nOutAlignment.SetWindowText(sz);
}
else
{
m_nOutBufferSize.SetWindowText(STR_UNKNOWN);
m_nOutAlignment.SetWindowText(STR_UNKNOWN);
}
}
void CPlayDMODlg::EnableButtons(BOOL bEnable)
{
// Enable or disable buttons and other dialog items
m_StrFilename.EnableWindow(bEnable);
m_ListAudioDMO.EnableWindow(bEnable);
GetDlgItem(IDC_BUTTON_ADD_DMO)->EnableWindow(bEnable);
GetDlgItem(IDC_BUTTON_CLEAR)->EnableWindow(bEnable);
GetDlgItem(IDC_BUTTON_FILE)->EnableWindow(bEnable);
}
HRESULT CPlayDMODlg::ConnectDMOsToRenderer()
{
USES_CONVERSION;
HRESULT hr=0;
IPin *pInputPin=0, *pUpstreamOutputPin=0;
IBaseFilter *pRenderer=0;
// Make sure that the graph is stopped before manipulating its filters
hr = m_pMC->Stop();
// Find the audio renderer in the graph
#if 0
// It's not recommended to search for Microsoft-provided filters by text
// name, since the name could change in the future. Instead, use
// the more reliable method outlined below.
WCHAR wszFilter[64];
wcscpy(wszFilter, T2W(TEXT("Default DirectSound Device")));
hr = m_pGB->FindFilterByName(wszFilter, &pRenderer);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to find audio renderer!\r\n"));
goto err;
}
#else
//
// Enumerate ALL filters in the graph, find one that has one input and
// no outputs, and check to see if it is configured to receive audio data.
//
hr = FindAudioRenderer(m_pGB, &pRenderer);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to find audio renderer!\r\n"));
goto err;
}
#endif
// Verify that an audio renderer is present
if (!pRenderer)
{
MessageBox(TEXT("This file contains no audio component.\r\n\r\n")
TEXT("Please select an audio file or a video file with audio."),
TEXT("No audio renderer!"));
goto err;
}
// Get the pin interface for its input pin
hr = GetPin(pRenderer, PINDIR_INPUT, 0, &pInputPin);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to find audio input pin!\r\n"));
goto err;
}
// Find its upstream connection
hr = pInputPin->ConnectedTo(&pUpstreamOutputPin);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to find audio renderer upstream output pin!\r\n"));
goto err;
}
// Break the connection between these pins
hr = pUpstreamOutputPin->Disconnect();
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to disconnect upstream output pin!\r\n"));
goto err;
}
hr = pInputPin->Disconnect();
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to disconnect renderer input pin!\r\n"));
goto err;
}
// Render the upstream filter's output pin again. This will cause
// the filter graph manager to connect our newly loaded DMOs into
// the renderer's input pin.
hr = m_pGB->Render(pUpstreamOutputPin);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to render upstream output pin!\r\n"));
goto err;
}
err:
SAFE_RELEASE(pInputPin);
SAFE_RELEASE(pUpstreamOutputPin);
SAFE_RELEASE(pRenderer);
return hr;
}
BOOL CPlayDMODlg::OnEraseBkgnd(CDC *pDC)
{
// Intercept background erasing for the movie window, since the
// video renderer will keep the screen painted. Without this code,
// your video window might get painted over with gray (the default
// background brush) when it is obscured by another window and redrawn.
CRect rc;
// Get the bounding rectangle for the movie screen
m_Screen.GetWindowRect(&rc);
ScreenToClient(&rc);
// Exclude the clipping region occupied by our movie screen
pDC->ExcludeClipRect(&rc);
// Erase the remainder of the dialog as usual
return CDialog::OnEraseBkgnd(pDC);
}