//========================================================================
//TITLE:
// wince下用DirectShow播放音频和视频
//AUTHOR:
// norains
//DATE:
// Monday 14-May-2007
//Environment:
// WinCE 5.0
//========================================================================
虽然网上关于wince下如何使用DirectShow播放多媒体文件的资料不多,但WinCE毕竟还属于windows,而桌面系统的DirectShow例子网上信手拈来,并且其中DirectShow的功能方法与之WinCE下差别不大,又本人实在没有信心比他们的轮子造得更为华丽,所以这篇文章就直接切入正题,不介绍DirectShow的结构功能,直接来看看怎么用吧.(其实还是自己懒惰的原因大一些,恩,不过这个和本文的主题没多大关系:-)).
为了方便代码的移植,所以我将DirectShow的操作封装成CMedia类,只要直接调用该类,就可以相当简便地调用DirectShow来播放多媒体文件了
好,闲话至此,我们以具体代码看看是如何:
//获取CMedia的实例
CMedia*m_pMedia=CMedia::GetInstance();

//设置播放的窗口
m_pMedia->SetVideoWindow(hWnd);

//打开媒体文件
m_pMedia->Open(TEXT("A.AVI"));

//播放
m_pMedia->Play();

...

//播放结束后,调用Close释放资源
m_pMedia->Open();
没错,就是六行代码,就这么简单,可以顺利播放媒体文件.在这里要说一下的是,因为我们播放的是视频,需要有一个窗口显示,所以需要调用SetVideoWindow()函数来设置播放窗口.这个播放视频的窗口,可以是普通的窗口,也可以是Picture控件.当然咯,如果是播放音频文件,那么则完全可以无视这个函数.
还有一个最值得注意的地方,当调用Open()成功之后,一定要调用Close()来释放资源,然后才能打开另一个媒体文件.否则,不释放的资源可能会导致很多莫名其妙的后果哦.
等等,代码似乎还不完美,比如说,我想在文件播放之后再接着播放另外一个文件,那么我如何知道什么时候文件已经播放完毕了呢?这时候我们就需要请出SetNotifyWindow().
该函数的作用是设置一个接受消息的窗口,当DirectShow有事件变更时,就会发送指定的消息到指定的窗口,原型如下:
SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData)
hWnd:接收消息的窗口句柄.
wMsg:指定的自定义消息
lInstanceData:消息的参数.
那么,现在以接收一个视频播放结束事件的代码片段为例子:
//自定义一个消息
#defineWM_GRAPHNOTIFY(WM_USER+13)

//设置接收消息窗口和消息
m_pMedia->SetVideoWindow(hWnd,WM_GRAPHNOTIFY,NULL);

...

//这个是消息循环函数
LRESULTCMainWnd::WndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)

...{
switch(wMsg)

...{

...

caseWM_GRAPHNOTIFY:

...{
LONGevCode,evParam1,evParam2;

//获取此时的DirectShow事件
if(m_pMedia->GetEvent(&evCode,&evParam1,&evParam2)==TRUE)

...{
if(evCode==EC_COMPLETE)

...{
MessageBox(NULL,TEXT("播放完毕"),TEXT(""),MB_OK);
}
}
return0;
}
}

...

}
好了,知道播放完毕,就这么简单.恩,还很复杂..?呵呵,我觉得已经很简单了.
文章的最后,让我们再来看看CMedia的其它几个有用的函数吧:
CheckVisibility()
描述:判断文件的种类
当返回值为TRUE时,为视频文件;反之为只是音频文件.
SetVolume(LONG lVolume, LONG lBalance)
描述:设置音量.
lVolume:设置音量的大小,范围为–10,000 到 0.
lBalance:设置左右音量的均衡,范围是–10,000 到 10,000,默认是0.
SetDisplayMode(DISPLAYMODE mode)
描述:设置播放模式.
DISP_FIT:按比例拉伸至视屏窗口.
DISP_STRETCH:不按比例拉伸至视屏窗口.
DISP_NATIVE:如果视频原本尺寸小于屏幕,则以原视频文件大小播放.否则,将和DISP_FIT相同
DISP_FULLSCREEN:全屏


/**//////////////////////////////////////////////////////////////////////
//Media.h:interfacefortheCMediaclass.
//
//Version:
//1.2.0
//Date:
//2007.05.08

/**///////////////////////////////////////////////////////////////////////
#ifndefMEDIA_H
#defineMEDIA_H


#include<mmsystem.h>
#include<streams.h>

//--------------------------------------------------------------------
//Macrodefine

//Thevolumevalue
#defineMAX_VOLUME0
#defineMIN_VOLUME-10000

//Thebalancevalue
#defineMAX_BALANCE10000
#defineMIN_BALANCE-10000

//--------------------------------------------------------------------
//Enumvalue

enumDISPLAYMODE

...{
//Fittotheplaywindowsize.Howwide(height)thewindowis,how
//isthemove.Keepaspectratio.
DISP_FIT,

//Stretchtotheplaywindowsize.Don'tkeeptheaspectratio.
DISP_STRETCH,

//Fullscreenplay.
DISP_FULLSCREEN,

//Whenthesizeofvideoissmallerthantheplaywindow,itdisplayes
//asthevideosize.Ifit'sbigger,itjustliketheDISP_FITmode.
DISP_NATIVE
};
//--------------------------------------------------------------------

//Themediafileproperty
typedefstruct

...{
//Thevolumerangeis–10,000to0.
//Divideby100togetequivalentdecibelvalue(forexample–10,000=–100dB).
LONGlVolume;

//Thevaluefrom–10,000to10,000indicatingthestereobalance
//AswiththeVolumeproperty,unitscorrespondto.01decibels(multipliedby–1whenplBalanceisapositivevalue).
//Forexample,avalueof1000indicates–10dBontherightchanneland–90dBontheleftchannel.
LONGlBalance;

//Widthofthevideo
LONGlWidth;

//Heightofthevideo
LONGlHeight;

//Approximatebitrate
LONGlBitRate;

}MEDIAPROPERTY,*PMEDIAPROPERTY;
//--------------------------------------------------------------------
classCMedia

...{
public:
BOOLGetEvent(LONG*plEvCode,LONG*plParam1,LONG*plParam2);
BOOLSetNotifyWindow(HWNDhWnd,UINTwMsg,longlInstanceData);
BOOLSetVolume(LONGlVolume,LONGlBalance=0);
BOOLSetDisplayMode(DISPLAYMODEmode);
BOOLGetMediaProperty(PMEDIAPROPERTYpOutProperty);
staticCMedia*GetInstance();
voidClose();
BOOLCheckVisibility();
voidSetVideoWindow(HWNDhWndVideo);
BOOLOpen(TCHAR*pszFileName);
BOOLStop();
BOOLPause();
BOOLPlay();
virtual~CMedia();

protected:


CMedia();

//Collectionofinterfaces
IGraphBuilder*m_pGB;
IMediaControl*m_pMC;
IMediaEventEx*m_pME;
IVideoWindow*m_pVW;
IBasicAudio*m_pBA;
IBasicVideo*m_pBV;
IMediaSeeking*m_pMS;

TCHARm_szFileName[MAX_PATH];
HWNDm_hWndVideo;//Thewindowplayvideo
HWNDm_hWndNotify;//Thewindownotify
BOOLm_bExitThrd;
BOOLm_bThrdRunning;
staticCMedia*m_pInstance;
DISPLAYMODEm_DispMode;

};

#endif//#ifndefMEDIA_H





/**///////////////////////////////////////////////////////////////////////
//Media.cpp:implementationoftheCMediaclass.
//

/**///////////////////////////////////////////////////////////////////////

#include"stdafx.h"
#include"Media.h"


//----------------------------------------------------------------------------------------------
//Macrodefine

//Defaultplaymode
#defineDEFAULT_DISPLAY_MODEDISP_NATIVE

//----------------------------------------------------------------------
//Initialize
CMedia*CMedia::m_pInstance=NULL;
//------------------------------------------------------------------------



/**///////////////////////////////////////////////////////////////////////
//Construction/Destruction

/**///////////////////////////////////////////////////////////////////////

CMedia::CMedia():
m_pGB(NULL),
m_pMC(NULL),
m_pME(NULL),
m_pVW(NULL),
m_pBA(NULL),
m_pBV(NULL),
m_pMS(NULL),
m_hWndVideo(NULL),
m_bExitThrd(TRUE),
m_bThrdRunning(FALSE),
m_DispMode(DEFAULT_DISPLAY_MODE),
m_hWndNotify(NULL)

...{
memset(m_szFileName,0,sizeof(m_szFileName));
}

CMedia::~CMedia()

...{
if(m_pInstance!=NULL)

...{
deletem_pInstance;
m_pInstance=NULL;
}

}




//------------------------------------------------------------
//Description:
//Playthemediafile
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//-------------------------------------------------------------
BOOLCMedia::Play()

...{
//Runthegraphtoplaythemediafile

if(m_pMC==NULL)

...{
returnFALSE;
}




m_pMC->Run();

returnTRUE;
}




//------------------------------------------------------------
//Description:
//Pause.
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//-------------------------------------------------------------
BOOLCMedia::Pause()

...{

if(m_pMC==NULL)

...{
returnFALSE;
}

m_pMC->Pause();

returnTRUE;
}




//------------------------------------------------------------
//Description:
//Stop.
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//-------------------------------------------------------------
BOOLCMedia::Stop()

...{

if(m_pMC==NULL||m_pMS==NULL)

...{
returnFALSE;
}


m_pMC->Stop();
m_pMS->SetPositions(0,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);

returnTRUE;
}




//--------------------------------------------------------------------------
//Description:
//Openthemediafile.Whensucceedincallingthefunction,
//youshouldcalltheClose()toreleasetheresource
//
//-------------------------------------------------------------------------
BOOLCMedia::Open(TCHAR*pszFileName)

...{
BOOLbResult=FALSE;


if(_tcslen(pszFileName)>=MAX_PATH)

...{
gotoEND;
}
else

...{
_tcscpy(m_szFileName,pszFileName);

//Checkthefileexisting
HANDLEhdFile=CreateFile(m_szFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
if(hdFile==INVALID_HANDLE_VALUE)

...{
//Thefiledoesn'texist
gotoEND;
}
else

...{
CloseHandle(hdFile);
}
}





//InitializeCOM
if(CoInitializeEx(NULL,COINIT_MULTITHREADED)!=S_OK)

...{
gotoEND;
}

//GettheinterfaceforDirectShow'sGraphBuilder
if(CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&m_pGB)!=S_OK)

...{
gotoEND;
}


//Havethegraphconstructitstheappropriategraphautomatically
if(m_pGB->RenderFile(m_szFileName,NULL)!=NOERROR)

...{
gotoEND;
}


//QueryInterfaceforDirectShowinterfaces
if(m_pGB->QueryInterface(IID_IMediaControl,(void**)&m_pMC)!=NOERROR)

...{
gotoEND;
}
if(m_pGB->QueryInterface(IID_IMediaEventEx,(void**)&m_pME)!=NOERROR)

...{
gotoEND;
}
if(m_pGB->QueryInterface(IID_IMediaSeeking,(void**)&m_pMS)!=NOERROR)

...{
gotoEND;
}


//Queryforvideointerfaces,whichmaynotberelevantforaudiofiles
if(m_pGB->QueryInterface(IID_IVideoWindow,(void**)&m_pVW)!=NOERROR)

...{
gotoEND;
}
if(m_pGB->QueryInterface(IID_IBasicVideo,(void**)&m_pBV)!=NOERROR)

...{
gotoEND;
}


//Queryforaudiointerfaces,whichmaynotberelevantforvideo-onlyfiles
if(m_pGB->QueryInterface(IID_IBasicAudio,(void**)&m_pBA)!=NOERROR)

...{
gotoEND;
}

//Isthisanaudio-onlyfile(novideocomponent)?
if(CheckVisibility()==TRUE)

...{
if(m_pVW->put_Owner((OAHWND)m_hWndVideo)!=NOERROR)

...{
gotoEND;
}


if(m_pVW->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN)!=NOERROR)

...{
gotoEND;
}
}



//Setplaymode
SetDisplayMode(m_DispMode);


bResult=TRUE;

END:

if(bResult==FALSE)

...{
//Releasetheresource
Close();
}

returnbResult;
}




//------------------------------------------------------------
//Description:
//Thismethodsetsanowningparentforthevideowindow.
//
//Parameters:
//hWnd:[in]Handleofnewownerwindow.
//
//----------------------------------------------------------
voidCMedia::SetVideoWindow(HWNDhWndVideo)

...{
m_hWndVideo=hWndVideo;
}



//------------------------------------------------------------
//Description:
//Checkthefilevisibility
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//Parameters:
//TRUE:Video
//FALSE:It'snotthevideo
//
//------------------------------------------------------------
BOOLCMedia::CheckVisibility()

...{


if(!m_pVW)

...{
//NoVideoWindowinterface.Assumingaudio/MIDIfileorunsupportedvideocodec
returnFALSE;
}

if(!m_pBV)

...{
//NoBasicVideointerface.Assumingaudio/MIDIfileorunsupportedvideocodec.
returnFALSE;
}


//Ifthisisanaudio-onlyclip,get_Visible()won'twork.
//
//Also,ifthisvideoisencodedwithanunsupportedcodec,
//wewon'tseeanyvideo,althoughtheaudiowillworkifitis
//ofasupportedformat.
longlVisible;
if(m_pVW->get_Visible(&lVisible)!=NOERROR)

...{
returnFALSE;
}


returnTRUE;
}




//------------------------------------------------------------
//Description:
//ReleasetheresourcewhichopenedintheOpen()
//
//------------------------------------------------------------
voidCMedia::Close()

...{

//Relinquishownership(IMPORTANT!)afterhiding
if(m_pVW)

...{
m_pVW->put_Visible(OAFALSE);
m_pVW->put_Owner(NULL);
}

if(m_pMC!=NULL)

...{
m_pMC->Release();
m_pMC=NULL;
}

if(m_pME!=NULL)

...{
m_pME->SetNotifyWindow(NULL,NULL,NULL);

m_pME->Release();
m_pME=NULL;
}

if(m_pMS!=NULL)

...{
m_pMS->Release();
m_pMS=NULL;
}

if(m_pBV!=NULL)

...{
m_pBV->Release();
m_pBV=NULL;
}

if(m_pBA!=NULL)

...{
m_pBA->Release();
m_pBA=NULL;
}

if(m_pVW!=NULL)

...{
m_pVW->Release();
m_pVW=NULL;
}

if(m_pGB!=NULL)

...{
m_pGB->Release();
m_pGB=NULL;
}

//FinishedwithCOM
memset(m_szFileName,0,sizeof(m_szFileName));


CoUninitialize();
}


//------------------------------------------------------------
//Description:
//Gettheinstanceofobject
//
//------------------------------------------------------------
CMedia*CMedia::GetInstance()

...{
if(m_pInstance==NULL)

...{
m_pInstance=newCMedia();
}

returnm_pInstance;
}




//------------------------------------------------------------
//Description:
//Getthemediafileproperty.
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//------------------------------------------------------------
BOOLCMedia::GetMediaProperty(PMEDIAPROPERTYpOutProperty)

...{


MEDIAPROPERTYprop=...{0};

if(m_pBA==NULL||m_pBV==NULL)

...{
returnFALSE;
}


//Gettheaudioproperty
m_pBA->get_Volume(&prop.lVolume);
m_pBA->get_Balance(&prop.lBalance);


//Getthevideoproperty
if(CheckVisibility()==TRUE)

...{
m_pBV->get_BitRate(&prop.lBitRate);
m_pBV->GetVideoSize(&prop.lWidth,&prop.lHeight);

}

*pOutProperty=prop;


returnTRUE;
}


//------------------------------------------------------------
//Description:
//Setthedisplaymode.
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//------------------------------------------------------------
BOOLCMedia::SetDisplayMode(DISPLAYMODEmode)

...{
if(m_pVW==NULL)

...{
returnFALSE;
}

m_DispMode=mode;

if(mode==DISP_FULLSCREEN)

...{
m_pVW->put_FullScreenMode(OATRUE);
}
else

...{
//Restoretothenormalmode
m_pVW->put_FullScreenMode(OAFALSE);


RECTrcWnd=...{0};
GetClientRect(m_hWndVideo,&rcWnd);
LONGlWndWidth=rcWnd.right-rcWnd.left;
LONGlWndHeight=rcWnd.bottom-rcWnd.top;


MEDIAPROPERTYprop=...{0};
GetMediaProperty(&prop);


if(mode==DISP_FIT||mode==DISP_NATIVE)

...{
LONGlDispLeft,lDispTop,lDispWidth,lDispHeight;

if(mode==DISP_NATIVE&&lWndWidth>=prop.lWidth&&lWndHeight>=prop.lHeight)

...{
lDispLeft=(lWndWidth-prop.lWidth)/2;
lDispTop=(lWndHeight-prop.lHeight)/2;
lDispWidth=prop.lWidth;
lDispHeight=prop.lHeight;
}
else

...{
if(prop.lWidth*lWndHeight>lWndWidth*prop.lHeight)

...{
lDispWidth=lWndWidth;
lDispHeight=(LONG)((float)lDispWidth/(float)prop.lWidth*prop.lHeight);
lDispLeft=0;
lDispTop=(lWndHeight-lDispHeight)/2;
}
elseif(prop.lWidth*lWndHeight<lWndWidth*prop.lHeight)

...{
lDispHeight=lWndHeight;
lDispWidth=(LONG)((float)lDispHeight/(float)prop.lHeight*prop.lWidth);
lDispLeft=(lWndWidth-lDispWidth)/2;
lDispTop=0;
}
else

...{
lDispWidth=lWndWidth;
lDispHeight=lWndHeight;
lDispLeft=0;
lDispTop=0;
}
}





m_pVW->put_Left(lDispLeft);
m_pVW->put_Top(lDispTop);
m_pVW->put_Width(lDispWidth);
m_pVW->put_Height(lDispHeight);
}
elseif(mode==DISP_STRETCH)

...{

m_pVW->put_Left(0);
m_pVW->put_Top(0);
m_pVW->put_Width(lWndWidth);
m_pVW->put_Height(lWndHeight);
}

}



returnTRUE;
}


//------------------------------------------------------------
//Description:
//Setthevolume.
//Whenyoucallthefunction,youshouldcallOpen()before.
//
//Parameters:
//lVolume:[in]Thevolume(amplitude)oftheaudiosignal.
//Rangeis–10,000to0.
//lBalance:[in]Thebalancefortheaudiosignal.Defaultvalueis0.
//Thevaluefrom–10,000to10,000indicatingthestereobalance.
//
//------------------------------------------------------------
BOOLCMedia::SetVolume(LONGlVolume,LONGlBalance)

...{
if(m_pBA==NULL)

...{
returnFALSE;
}

if(lVolume<MIN_VOLUME&&lVolume>MAX_VOLUME&&lBalance<MIN_BALANCE&&lBalance>MAX_BALANCE)

...{
returnFALSE;
}

m_pBA->put_Volume(lVolume);
m_pBA->put_Balance(lBalance);

returnTRUE;
}




//----------------------------------------------------------------------
//Description:
//Registersawindowthatwillhandlemessageswhenaspecifiedeventoccurs.
//
//Parameters:
//hWnd:[in]Handleofwindowtonotify.PassNULLtostopnotification.
//wMsg:[in]Windowmessagetobepassedasthenotification.
//lInstanceData:[in]Value(instancedata)tobepassedasthelParamparameterforthelMsgmessage.
//
//-----------------------------------------------------------------------------
BOOLCMedia::SetNotifyWindow(HWNDhWnd,UINTwMsg,longlInstanceData)

...{
if(m_pME==NULL)

...{
returnFALSE;
}

m_pME->SetNotifyWindow((OAHWND)hWnd,wMsg,lInstanceData);

returnTRUE;
}


//----------------------------------------------------------------------
//Description:
//Thismethodretrievesthenotificationevent.
//
//-----------------------------------------------------------------------
BOOLCMedia::GetEvent(LONG*plEvCode,LONG*plParam1,LONG*plParam2)

...{
if(m_pME==NULL)

...{
returnFALSE;
}

LONGevCode,evParam1,evParam2;

if(m_pME->GetEvent(&evCode,&evParam1,&evParam2,0)==NOERROR)

...{
*plEvCode=evCode;
*plParam1=evParam1;
*plParam2=evParam2;

//Spinthroughtheevents
m_pME->FreeEventParams(evCode,evParam1,evParam2);
}
else

...{
returnFALSE;
}


returnTRUE;
}
//TITLE:
// wince下用DirectShow播放音频和视频
//AUTHOR:
// norains
//DATE:
// Monday 14-May-2007
//Environment:
// WinCE 5.0
//========================================================================
虽然网上关于wince下如何使用DirectShow播放多媒体文件的资料不多,但WinCE毕竟还属于windows,而桌面系统的DirectShow例子网上信手拈来,并且其中DirectShow的功能方法与之WinCE下差别不大,又本人实在没有信心比他们的轮子造得更为华丽,所以这篇文章就直接切入正题,不介绍DirectShow的结构功能,直接来看看怎么用吧.(其实还是自己懒惰的原因大一些,恩,不过这个和本文的主题没多大关系:-)).
为了方便代码的移植,所以我将DirectShow的操作封装成CMedia类,只要直接调用该类,就可以相当简便地调用DirectShow来播放多媒体文件了
好,闲话至此,我们以具体代码看看是如何:
















没错,就是六行代码,就这么简单,可以顺利播放媒体文件.在这里要说一下的是,因为我们播放的是视频,需要有一个窗口显示,所以需要调用SetVideoWindow()函数来设置播放窗口.这个播放视频的窗口,可以是普通的窗口,也可以是Picture控件.当然咯,如果是播放音频文件,那么则完全可以无视这个函数.
还有一个最值得注意的地方,当调用Open()成功之后,一定要调用Close()来释放资源,然后才能打开另一个媒体文件.否则,不释放的资源可能会导致很多莫名其妙的后果哦.
等等,代码似乎还不完美,比如说,我想在文件播放之后再接着播放另外一个文件,那么我如何知道什么时候文件已经播放完毕了呢?这时候我们就需要请出SetNotifyWindow().
该函数的作用是设置一个接受消息的窗口,当DirectShow有事件变更时,就会发送指定的消息到指定的窗口,原型如下:
SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData)
hWnd:接收消息的窗口句柄.
wMsg:指定的自定义消息
lInstanceData:消息的参数.
那么,现在以接收一个视频播放结束事件的代码片段为例子:








































好了,知道播放完毕,就这么简单.恩,还很复杂..?呵呵,我觉得已经很简单了.
文章的最后,让我们再来看看CMedia的其它几个有用的函数吧:
CheckVisibility()
描述:判断文件的种类
当返回值为TRUE时,为视频文件;反之为只是音频文件.
SetVolume(LONG lVolume, LONG lBalance)
描述:设置音量.
lVolume:设置音量的大小,范围为–10,000 到 0.
lBalance:设置左右音量的均衡,范围是–10,000 到 10,000,默认是0.
SetDisplayMode(DISPLAYMODE mode)
描述:设置播放模式.
DISP_FIT:按比例拉伸至视屏窗口.
DISP_STRETCH:不按比例拉伸至视屏窗口.
DISP_NATIVE:如果视频原本尺寸小于屏幕,则以原视频文件大小播放.否则,将和DISP_FIT相同
DISP_FULLSCREEN:全屏













































































































































































































































































































































































































































































































































































































































































































































































































































