?? ericmediacontrol.cpp
字號:
/*-----------------------------------------
* Copyright (c) 2008 Eric Wong
* 本版緊供讀者參考,不得用于任何商業行為
*
* 文件名稱: EricMediaControl.cpp
* 文件標識:
* 摘要:用于封裝DSHOW 播放視頻文件
*
* 當前版本: 1.0
* 作者: 汪兵 Eric Wong
* 完成日期: 2008年2月2日
*
* 取代版本:
* 原作者:
* 完成日期:
----------------------------------------*/
#include "StdAfx.h"
#include "EricMediaControl.h"
//構造函數
CEricMediaControl::CEricMediaControl(void)
{
//將DSHOW接口置空
m_pGB = NULL;
m_pMC = NULL;
m_pME = NULL;
m_pVW = NULL;
m_pBA = NULL;
m_pBV = NULL;
m_pMS = NULL;
//初始化 COM 環境
CoInitialize(NULL);
}
//析構函數
CEricMediaControl::~CEricMediaControl(void)
{
//釋放DSHOW接口
UnInitDShow();
//釋放COM 環境
CoUninitialize();
}
/*
*函數介紹: 初始化DShow接口,并渲染好視頻文件
*入口參數: strFileName: 視頻文件名
hOwnerWnd: 顯示視頻的窗口句柄
hNotifyWnd: 接收DSHOW事件消息的串口句柄
*出口參數:(無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::InitDShow(LPCTSTR strFileName /*視頻文件名*/
,HWND hOwnerWnd /*顯示視頻的窗口句柄*/
,HWND hNotifyWnd /*接收DSHOW事件消息的串口句柄*/
)
{
HRESULT hResult;
//第1步:創建IGraphBuilder接口
hResult = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);
if (hResult != S_OK)
{
return FALSE;
}
//第2步:利用IGraphBuilder渲染視頻文件
hResult = m_pGB->RenderFile(strFileName,NULL);
if (hResult != S_OK )
{
//
if (hResult == VFW_S_PARTIAL_RENDER)
{
TRACE(L"Some of the streams in this movie are in an unsupported format.\n");
}
else if (hResult == VFW_S_AUDIO_NOT_RENDERED)
{
TRACE(L"Partial success; the audio was not rendered.\n");
}
else if (hResult == VFW_S_DUPLICATE_NAME)
{
TRACE(L"Success; the Filter Graph Manager modified the filter name to avoid duplication..\n");
}
else if (hResult == VFW_S_VIDEO_NOT_RENDERED)
{
TRACE(L"Partial success; some of the streams in this movie are in an unsupported format.\n");
}
else
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
}
//第3步:得到媒體播放控制接口
hResult = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
//第4步:得到媒體播放位置搜索接口
hResult = m_pGB->QueryInterface(IID_IMediaSeeking,(void**)&m_pMS);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
//設置查找定位的時間單位,這里設置:100納秒(十億分之一秒)
GUID guid_timeFormat = TIME_FORMAT_MEDIA_TIME;
m_pMS->SetTimeFormat(&guid_timeFormat);
//第5步:得到Filter Graph媒體事件接口
hResult = m_pGB->QueryInterface(IID_IMediaEventEx,(void**)&m_pME);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
//設置媒體事件通知消息窗口
m_pME->SetNotifyWindow((OAHWND)hNotifyWnd, WM_GRAPHNOTIFY, 0);
//第6步:得到視頻播放窗口接口
hResult = m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
//設置視頻播放窗口句柄
m_pVW->put_Owner((OAHWND)hOwnerWnd);
//設置視頻窗口格式
m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
//第7步:得到基礎視頻流接口
hResult = m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
//第8步:得到基礎音頻流接口
hResult = m_pGB->QueryInterface(IID_IBasicAudio, (void **)&m_pBA);
if (hResult != S_OK)
{
//釋放DSHOW接口
UnInitDShow();
return FALSE;
}
return TRUE;
}
/*
*函數介紹: 卸載DShow系列接口
*入口參數: (無)
*出口參數:(無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::UnInitDShow()
{
//1,釋放媒體播放控制接口
if (m_pMC != NULL)
{
//停止視頻播放
m_pMC->Stop();
m_pMC->Release();
m_pMC = NULL;
}
//2,釋放媒體事件接口
if (m_pME != NULL)
{
//消息通知窗口置空
m_pME->SetNotifyWindow(NULL, 0, 0);
m_pME->Release();
m_pME = NULL;
}
//3,釋放視頻播放窗口接口
if (m_pVW != NULL)
{
//隱藏視頻窗口
m_pVW->put_Visible(OAFALSE);
//設置視頻播放窗口句柄為空
m_pVW->put_Owner(NULL);
m_pVW->Release();
m_pVW = NULL;
}
//4,釋放基礎音頻流接口
if (m_pBA != NULL)
{
m_pBA->Release();
m_pBA = NULL;
}
//5,釋放基礎視頻流接口
if (m_pBV != NULL)
{
m_pBV->Release();
m_pBV = NULL;
}
//6,釋放媒體搜索接口
if (m_pMS != NULL)
{
m_pMS->Release();
m_pMS = NULL;
}
//7,最后釋放FilterGpaph接口
if (m_pGB != NULL)
{
m_pGB->Release();
m_pGB = NULL;
}
return TRUE;
}
/*
*函數介紹:打開視頻文件
*入口參數: strFileName: 視頻文件名
hOwnerWnd: 顯示視頻的窗口句柄
hNotifyWnd: 接收DSHOW事件消息的串口句柄
*出口參數:(無)
*返回值:TRUE:成功打開視頻文件;FALSE:打開視頻文件失敗
*/
BOOL CEricMediaControl::OpenFile(LPCTSTR strFileName /*視頻文件名*/
,HWND hOwnerWnd /*顯示視頻的窗口句柄*/
,HWND hNotifyWnd /*接收DSHOW事件消息的串口句柄*/
)
{
//存儲顯示視頻窗口句柄
m_hOwnerWnd = hOwnerWnd;
//重置DSHOW接口
UnInitDShow();
//打開視頻文件,并對DSHOW接口做初始化工作
return InitDShow(strFileName,hOwnerWnd,hNotifyWnd);
}
/*
*函數介紹:播放視頻
*入口參數:(無)
*出口參數:(無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::VideoRun()
{
//檢測IMediaControl控制接口有效性
if (m_pMC == NULL)
{
return FALSE;
}
//播放視頻
HRESULT hResult = m_pMC->Run();
if (hResult != S_OK)
{
return FALSE;
}
return TRUE;
}
/*
*函數介紹:暫停視頻
*入口參數:(無)
*出口參數:(無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::VideoPause()
{
//檢測IMediaControl控制接口有效性
if (m_pMC == NULL)
{
return FALSE;
}
//暫停視頻
HRESULT hResult = m_pMC->Pause();
if (hResult != S_OK)
{
return FALSE;
}
return TRUE;
}
/*
*函數介紹:停止視頻
*入口參數:(無)
*出口參數:(無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::VideoStop()
{
HRESULT hResult ;
//檢測IMediaControl控制接口有效性
if (m_pMC == NULL)
{
return FALSE;
}
//停止視頻
hResult = m_pMC->Stop();
if (hResult != S_OK)
{
return FALSE;
}
//將當前播放位置置0
LONGLONG pos=0;
hResult = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
return TRUE;
}
/*
*函數介紹: 設置視頻顯示比例
*入口參數: fScale : 顯示比例, <= 1.0
*出口參數: (無)
*返回值:TRUE:成功;FALSE:失敗,此處有點問題
*/
BOOL CEricMediaControl::FitVideoWindow(FLOAT fScale)
{
LONG lHeight, lWidth;
int iSeek = 0;
double dblScaleX,dblScaleY;
HRESULT hr = S_OK;
LONG lDeflateX = 0;
LONG lDeflateY = 0;
CRect clientRect;
CRect dstRect;
//
if (m_pBV == NULL)
{
return FALSE;
}
//放縮比例必須小于等于1
if (fScale > 1.0)
{
return FALSE;
}
//得到原始視頻尺寸
hr = m_pBV->GetVideoSize(&lWidth, &lHeight);
if (hr != S_OK)
{
return FALSE;
}
//設置拉伸后的尺寸
lWidth = lWidth * fScale;
lHeight = lHeight * fScale;
//得到視頻播放窗口的尺寸
GetClientRect(m_hOwnerWnd, &clientRect);
lDeflateX = (clientRect.Width() - clientRect.Width() * fScale) / 2;
lDeflateY = (clientRect.Height() - clientRect.Height() * fScale) / 2;
//重新設置客戶區域
clientRect.DeflateRect(lDeflateX,lDeflateY);
if ( (lWidth <= clientRect.Width())
&& (lHeight <= clientRect.Height()))
{
dstRect.left = (clientRect.right - clientRect.left - lWidth) /2;
dstRect.right = dstRect.left + lWidth;
dstRect.top = (clientRect.bottom - clientRect.top - lHeight) /2;
dstRect.bottom = dstRect.top + lHeight;
}
else
{
dblScaleX =double(clientRect.Width()) / double(lWidth) ;
dblScaleY = double(clientRect.Height()) / double(lHeight) ;
if (dblScaleX <= dblScaleY)
{
dstRect.left = clientRect.left;
dstRect.right = clientRect.right;
iSeek =(clientRect.Height() - clientRect.Width()*(double(lHeight) / double(lWidth)))/2;
dstRect.top = clientRect.top + iSeek;
dstRect.bottom = dstRect.top + clientRect.Width()*(double(lHeight) / double(lWidth));
}
else
{
dstRect.top = clientRect.top;
dstRect.bottom = clientRect.bottom;
iSeek =(clientRect.Width() - clientRect.Height()*(double(lWidth) / double(lHeight)))/2;
dstRect.left = clientRect.left + iSeek;
dstRect.right = dstRect.left + clientRect.Height()*(double(lWidth) / double(lHeight));
}
}
//設置視頻播放位置
m_pVW->SetWindowPosition(dstRect.left,dstRect.top,dstRect.Width(),dstRect.Height());
return TRUE;
}
/*
*函數介紹: 全屏顯示
*入口參數: (無)
*出口參數: (無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::FullScreen()
{
LONG lMode = 0;
static HWND hDrain=0;
if (m_pBV == NULL)
{
return FALSE;
}
//得到全屏狀態
m_pVW->get_FullScreenMode(&lMode);
if (lMode == OAFALSE)
{
// Save current message drain
m_pVW->get_MessageDrain((OAHWND *) &hDrain);
// Set message drain to application main window
m_pVW->put_MessageDrain((OAHWND)m_hOwnerWnd );
//設置全屏幕
lMode = OATRUE;
m_pVW->put_FullScreenMode(lMode);
}
else
{
//切換到非全屏模式
lMode = OAFALSE;
m_pVW->put_FullScreenMode(lMode);
// Undo change of message drain
m_pVW->put_MessageDrain((OAHWND) hDrain);
// Reset video window
FitVideoWindow(1);
m_pVW->SetWindowForeground(-1);
}
return TRUE;
}
/*
*函數介紹: 得到是否全屏幕播放
*入口參數: (無)
*出口參數: (無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::GetFullScreenStatus()
{
LONG lMode = 0;
if (m_pBV == NULL)
{
return FALSE;
}
m_pVW->get_FullScreenMode(&lMode);
if (lMode == OAFALSE)
{
return FALSE;
}
else
{
return TRUE;
}
}
/*
*函數介紹: 得到媒體事件
*入口參數: (無)
*出口參數: lEventCode
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::GetMediaEvent(long *lEventCode)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
if (m_pME == NULL)
{
return FALSE;
}
hr = m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0);
if (SUCCEEDED(hr))
{
*lEventCode = evCode;
// Spin through the events
hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
return TRUE;
}
return FALSE;
}
/*
*函數介紹: 設置播放進度
*入口參數: dwPos :播放進度,單位秒
*出口參數: (無)
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::SetPositions(DWORD dwPos /*設置當前播放進度*/)
{
//設置絕對位置,轉化成納秒為單位
LONGLONG llPos = dwPos * 10000 * 1000;
if (m_pMS == NULL)
{
return FALSE;
}
//設置視頻播放當前位置
HRESULT hr = m_pMS->SetPositions(&llPos,AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
if (hr == S_OK)
{
return TRUE;
}
else
{
return FALSE;
}
}
/*
*函數介紹: 得到視頻文件播放長度,單位秒
*入口參數: dwLength :視頻文件時間長度
*出口參數: dwLength :視頻文件時間長度
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::GetDuration(DWORD &dwLength)
{
dwLength = 0;
if (m_pMS == NULL)
{
return FALSE;
}
//得到視頻總時間長度
LONGLONG llDuration;
HRESULT hResult = m_pMS->GetDuration(&llDuration);
if (hResult != S_OK)
{
return FALSE;
}
//轉換成以秒為單位
llDuration = llDuration / 10000 ;
llDuration = llDuration / 1000;
dwLength = (DWORD)llDuration;
return TRUE;
}
/*
*函數介紹: 得到媒體當前播放進度位置,單位秒
*入口參數: dwPos :當前播放進度,單位秒
*出口參數: dwPos :當前播放進度,單位秒
*返回值:TRUE:成功;FALSE:失敗
*/
BOOL CEricMediaControl::GetCurrentPos(DWORD &dwPos)
{
dwPos = 0;
LONGLONG llPos = 0;
if (m_pMS== NULL)
{
return FALSE;
}
//得到當前視頻播放位置
HRESULT hResult = m_pMS->GetCurrentPosition(&llPos);
if (hResult != S_OK)
{
return FALSE;
}
//轉換成以秒為單位
llPos = llPos / 10000 ;
llPos = llPos / 1000;
dwPos = (DWORD)llPos;
return TRUE;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -