📄 playwnd.cpp
字号:
//------------------------------------------------------------------------------
// File: PlayWnd.cpp
//
// Desc: DirectShow sample code - a simple audio/video media file player
// application. Pause, stop, mute, and fullscreen mode toggle can
// be performed via keyboard commands.
//
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
// Modify by Longee
//------------------------------------------------------------------------------
#include <dshow.h>
#include <stdio.h>
#include <tchar.h>
#include <atlbase.h>
#include "playwnd.h"
//-----------------------------------------------------------------------------
// An application can advertise the existence of its filter graph
// by registering the graph with a global Running Object Table (ROT).
// The GraphEdit application can detect and remotely view the running
// filter graph, allowing you to 'spy' on the graph with GraphEdit.
//
// To enable registration in this sample, define REGISTER_FILTERGRAPH.
//-----------------------------------------------------------------------------
#define REGISTER_FILTERGRAPH
//-----------------------------------------------------------------------------
CDXPlayer g_objMediaPlayer;
//-----------------------------------------------------------------------------
CDXPlayer::CDXPlayer()
{
m_pGraphBuilder = NULL;
m_pMediaControl = NULL;
m_pMediaEventEx = NULL;
m_pVideoWindow = NULL;
m_pBaseAudio = NULL;
m_pBaseVidio = NULL;
m_pMediaSeeking = NULL;
m_pMediaPosition = NULL;
m_pVideoFrameStep = NULL;
m_bAudioOnly = FALSE;
m_bFullscreen = FALSE;
m_bRepeat = TRUE;
m_lVolume = VOLUME_FULL;
m_dwGraphRegister = 0;
m_psCurrent = _STOPPED;
m_PlaybackRate = 1.0;
m_hWnd = NULL;
// Initialize COM
//if(FAILED(CoInitialize(NULL)))
//{
// Msg(TEXT("CoInitialize Failed!\r\n"));
// exit(1);
//}
}
//-----------------------------------------------------------------------------
CDXPlayer::~CDXPlayer()
{
// Finished with COM
// CoUninitialize();
}
//-----------------------------------------------------------------------------
HRESULT CDXPlayer::PlayMovieInWindow(LPTSTR szFile)
{
USES_CONVERSION;
WCHAR wFile[MAX_PATH];
HRESULT hr;
// Clear open dialog remnants before calling RenderFile()
UpdateWindow(m_hWnd);
// Convert filename to wide character string
wcscpy(wFile, T2W(szFile));
// Get the interface for DirectShow's GraphBuilder
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&m_pGraphBuilder));
if(SUCCEEDED(hr))
{
// Have the graph builder construct its the appropriate graph automatically
JIF(m_pGraphBuilder->RenderFile(wFile, NULL));
// QueryInterface for DirectShow interfaces
JIF(m_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&m_pMediaControl));
JIF(m_pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&m_pMediaEventEx));
JIF(m_pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&m_pMediaSeeking));
JIF(m_pGraphBuilder->QueryInterface(IID_IMediaPosition, (void **)&m_pMediaPosition));
// Query for video interfaces, which may not be relevant for audio files
JIF(m_pGraphBuilder->QueryInterface(IID_IVideoWindow, (void **)&m_pVideoWindow));
JIF(m_pGraphBuilder->QueryInterface(IID_IBasicVideo, (void **)&m_pBaseVidio));
// Query for audio interfaces, which may not be relevant for video-only files
JIF(m_pGraphBuilder->QueryInterface(IID_IBasicAudio, (void **)&m_pBaseAudio));
// Is this an audio-only file (no video component)?
CheckVisibility();
// Have the graph signal event via window callbacks for performance
JIF(m_pMediaEventEx->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0));
if (!m_bAudioOnly)
{
JIF(m_pVideoWindow->put_Owner((OAHWND)m_hWnd));
JIF(m_pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
JIF(InitVideoWindow(1, 1));
GetFrameStepInterface();
}
// Let's get ready to rumble!
//ShowWindow(ghApp, SW_SHOWNORMAL);
//UpdateWindow(ghApp);
//SetForegroundWindow(ghApp);
//SetFocus(ghApp);
//m_bFullscreen = FALSE;
m_PlaybackRate = 1.0;
//UpdateMainTitle();
#ifdef REGISTER_FILTERGRAPH
hr = AddGraphToRot(m_pGraphBuilder, &m_dwGraphRegister);
if (FAILED(hr))
{
Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr);
m_dwGraphRegister = 0;
}
#endif
// Run the graph to play the media file
JIF(m_pMediaControl->Run());
m_psCurrent = _RUNNING;
//SetFocus(m_hWnd);
}
return hr;
}
//-----------------------------------------------------------------------------
HRESULT CDXPlayer::InitVideoWindow(int nMultiplier, int nDivider)
{
LONG lHeight, lWidth;
HRESULT hr = S_OK;
RECT rect;
if (!m_pBaseVidio)
return S_OK;
// Read the default video size
hr = m_pBaseVidio->GetVideoSize(&lWidth, &lHeight);
if (hr == E_NOINTERFACE)
return S_OK;
//EnablePlaybackMenu(TRUE);
// Account for requests of normal, half, or double size
lWidth = lWidth * nMultiplier / nDivider;
lHeight = lHeight * nMultiplier / nDivider;
//SetWindowPos(ghApp, NULL, 0, 0, lWidth, lHeight,
// SWP_NOMOVE | SWP_NOOWNERZORDER);
int nTitleHeight = GetSystemMetrics(SM_CYCAPTION);
int nBorderWidth = GetSystemMetrics(SM_CXBORDER);
int nBorderHeight = GetSystemMetrics(SM_CYBORDER);
// Account for size of title bar and borders for exact match
// of window client area to default video size
//SetWindowPos(ghApp, NULL, 0, 0, lWidth + 2*nBorderWidth,
// lHeight + nTitleHeight + 2*nBorderHeight,
// SWP_NOMOVE | SWP_NOOWNERZORDER);
GetClientRect(m_hWnd, &rect);
JIF(m_pVideoWindow->SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom));
return hr;
}
//-----------------------------------------------------------------------------
void CDXPlayer::MoveVideoWindow(HWND hWnd)
{
HRESULT hr;
// Track the movement of the container window and resize as needed
if(m_pVideoWindow)
{
RECT client;
GetClientRect(hWnd, &client);
hr = m_pVideoWindow->SetWindowPosition(client.left, client.top,
client.right, client.bottom);
}
}
//-----------------------------------------------------------------------------
void CDXPlayer::CheckVisibility(void)
{
long lVisible;
HRESULT hr;
if ((!m_pVideoWindow) || (!m_pBaseVidio))
{
// Audio-only files have no video interfaces. This might also
// be a file whose video component uses an unknown video codec.
m_bAudioOnly = TRUE;
return;
}
else
{
// Clear the global flag
m_bAudioOnly = FALSE;
}
hr = m_pVideoWindow->get_Visible(&lVisible);
if (FAILED(hr))
{
// If this is an audio-only clip, get_Visible() won't work.
//
// Also, if this video is encoded with an unsupported codec,
// we won't see any video, although the audio will work if it is
// of a supported format.
//
if (hr == E_NOINTERFACE)
{
m_bAudioOnly = TRUE;
}
else
{
Msg(TEXT("Failed(%08lx) in m_pVideoWindow->get_Visible()!\r\n"), hr);
}
}
}
//-----------------------------------------------------------------------------
void CDXPlayer::PauseClip(void)
{
if (!m_pMediaControl)
return;
// Toggle play/pause behavior
if((m_psCurrent == _PAUSED) || (m_psCurrent == _STOPPED))
{
if (SUCCEEDED(m_pMediaControl->Run()))
m_psCurrent = _RUNNING;
}
else
{
if (SUCCEEDED(m_pMediaControl->Pause()))
m_psCurrent = _PAUSED;
}
UpdateMainTitle();
}
//-----------------------------------------------------------------------------
void CDXPlayer::StopClip(void)
{
HRESULT hr;
if ((!m_pMediaControl) || (!m_pMediaSeeking))
return;
// Stop and reset postion to beginning
if((m_psCurrent == _PAUSED) || (m_psCurrent == _RUNNING))
{
LONGLONG pos = 0;
hr = m_pMediaControl->Stop();
m_psCurrent = _STOPPED;
// Seek to the beginning
hr = m_pMediaSeeking->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
// Display the first frame to indicate the reset condition
hr = m_pMediaControl->Pause();
}
UpdateMainTitle();
}
//-----------------------------------------------------------------------------
void CDXPlayer::OpenClip(TCHAR* pszFileName)
{
HRESULT hr;
// Reset status variables
m_psCurrent = _STOPPED;
m_lVolume = VOLUME_FULL;
// Start playing the media file
hr = PlayMovieInWindow(pszFileName);
// If we couldn't play the clip, clean up
if (FAILED(hr))
CloseClip();
}
//-----------------------------------------------------------------------------
void CDXPlayer::CloseClip()
{
HRESULT hr;
// Stop media playback
if(m_pMediaControl)
hr = m_pMediaControl->Stop();
// Clear global flags
m_psCurrent = _STOPPED;
m_bAudioOnly = TRUE;
m_bFullscreen = FALSE;
// Free DirectShow interfaces
CloseInterfaces();
// Clear file name to allow selection of new file with open dialog
// m_szFileName[0] = L'\0';
// No current media state
m_psCurrent = _INIT;
// Reset the player window
RECT rect;
GetClientRect(m_hWnd, &rect);
InvalidateRect(m_hWnd, &rect, TRUE);
UpdateMainTitle();
}
//-----------------------------------------------------------------------------
void CDXPlayer::CloseInterfaces(void)
{
HRESULT hr;
// Relinquish ownership (IMPORTANT!) after hiding video window
if(m_pVideoWindow)
{
hr = m_pVideoWindow->put_Visible(OAFALSE);
hr = m_pVideoWindow->put_Owner(NULL);
}
// Disable event callbacks
if (m_pMediaEventEx)
hr = m_pMediaEventEx->SetNotifyWindow((OAHWND)NULL, 0, 0);
#ifdef REGISTER_FILTERGRAPH
if (m_dwGraphRegister)
{
RemoveGraphFromRot(m_dwGraphRegister);
m_dwGraphRegister = 0;
}
#endif
// Release and zero DirectShow interfaces
SAFE_RELEASE(m_pMediaEventEx);
SAFE_RELEASE(m_pMediaSeeking);
SAFE_RELEASE(m_pMediaPosition);
SAFE_RELEASE(m_pMediaControl);
SAFE_RELEASE(m_pBaseAudio);
SAFE_RELEASE(m_pBaseVidio);
SAFE_RELEASE(m_pVideoWindow);
SAFE_RELEASE(m_pVideoFrameStep);
SAFE_RELEASE(m_pGraphBuilder);
}
//-----------------------------------------------------------------------------
#ifdef REGISTER_FILTERGRAPH
//-----------------------------------------------------------------------------
HRESULT CDXPlayer::AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
IMoniker * pMoniker;
IRunningObjectTable *pROT;
if (FAILED(GetRunningObjectTable(0, &pROT)))
{
return E_FAIL;
}
WCHAR wsz[128];
wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph,
GetCurrentProcessId());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -