利用DirectShow实现视频文件播放
基于DirectShow的客户端实时视频流回放技术

d, t ) e r lr  ̄ fe 等。过滤器通过向文件读写、 ei 修改数据和显示数据到输 出设备上来操作流媒体。为了完成整个 任务 。 必须要将所有的过滤器 F t 连接起来 , 3 ir l e 这 种过滤器组成了过滤器图表结构 , 如图 I 所示。
Die th w r cS o
术, 避开了复杂的视频流解压算法 , 具有较好的通用性和可移植性。
1 Drc hw 简 介 i t o eS
M ic hw的设计 目 SD eSo rt 标是: 隔离数据传输 、 硬件兼容、 流同步等底层处理, 使客户能够轻轻松松地创建 W n w 应用平台上的多媒体应用程序[。它对媒体数据的处理采用流媒体( uie a t ) i os d ¨ M l d 咖 的方式, t is m 在应用 中大大的减少了编程的复杂程度, 同时又可以自 动协商从数据源到应用的转换 , 口 流接 提供了统一的、 可以预测 的数据存取的控制方法, 这样应用程序在播放媒体数据时不需要考虑它最初的来源和格式。
V I 2 . o. 8N 1 o
Ma .2 o r 06
基 于 Drc hw的客户 端 i to eS 实 时视频 流 回放 技 术
刘 琼 , 慧灿 周
( 湖南文理学院 计算机科学系 。 湖南 常德 450 ) 103
摘
要: 介绍 了Dr t o 术的原理并 以 M E i c hw技 eS P G一1视频流解 码回放为例 , 详细说 明了 Ft Gah的构建 与实现方法。 ir r l e p 文献标识码 : A 文章编号 :6 1 2 120 )1 0 1 3 17 —03 (060 —06 —0
维普资讯
在过滤器图表结构中, 源过滤器用来从数据源劳敢数据 , 并将数据传送到过滤器 图表中, 这里的数据
基于Directshow的H.264网络视频监控客户端实现

基于Directshow的H.264网络视频监控客户端实现彭锋;林和志;黄联芬【摘要】In order to realize the real-time broadcasting of H. 264 at video monitoring client, a method that combines Directshow with MFC is adopted. Directshow taken as a drive of the video player receives data from the network, performs cache, decoding and display, and provides the API for MFC, which is used to design UI to control the process of playing. After verification on PC, the player can smoothly play the H. 264 video stream received from network, and the packet loss rate islow. The innovation of this paper is to use Directshow to play smoothly real-time H. 264 stream received from network.%为了实现视频监控客户端对H.264实时播放,采用Directshow与MFC相结合的方法,用Directshow作为视频播放的驱动,从网络接收数据,完成缓存,解码显示及封装成MFC可调用的API,MFC用来设计户界面,对播放过程进行相应的控制,达到了播放从网络接收到的H.264视频的目的.经过PC机上验证,可以流畅地从网络上接收播放H.264视频流,并且丢包率很小.在此用Directshow来实时流畅的播放从网络上接收到的H.264视频流.【期刊名称】《现代电子技术》【年(卷),期】2011(034)008【总页数】3页(P118-120)【关键词】H.264;Directshow;MFC;网络视频监控【作者】彭锋;林和志;黄联芬【作者单位】厦门大学,福建,厦门,361005;厦门大学,福建,厦门,361005;厦门大学,福建,厦门,361005【正文语种】中文【中图分类】TN919-340 引言视频监控以其直观方便信息内容丰富而广泛应用于安保,监控等场合,成为商业,交通,住宅等领域防范的重要手段。
基于DirectShow的MPEG-4监控系统的设计与实现

Drc 软件 开发包是微软公 司提供 的一套 在 i t eX Wi o s n w 操作平 台上开发高性能图形、声音 、输入 、 d 输 出和网络游戏 的编程接 口。Dic 是众多技术的 rt eX 集合, 其中的Drc h w i t o 技术为在Wi o s eS n w 平台上处 d 理各种格式的媒体文件的回放 、音视频采集等高性 能的 多媒 体应用 ,提 供完整 的解决方 案 【 1 l。 ‘ 6
Ab ta t A e a da v c dDi cS o tc n lg o lme i p l ain d v lp n rsn e . sr c n w n d a e r th w h oo yf r n e e mut daa p i to e eo me ti pe e td i c S T i tc oo S a p id i ewo k d dgtlv d o mo i r g s se b s d o Ⅳ【EG- .M ut e i hs e h lg i p l n a n t r e ii ie nt i y tm a e n n y e a on E ) 4 l m i da p o e s g i e l e i Di cS o fa eicu ig c pu i g d c d g pa ig b c , s e ig ec T i r c si s rai d n n z r t h w rm , ld a tr , e o i , l n a k e k t. hs e n n n n y n
DirectShow视频采集方案

流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络上得到了广泛地应用。如何能够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft推出了DirectShow,DirectShow是Microsoft推出的基于Windows平台的流媒体处理开发包,它与DirectX一起发布。DirectShow对流媒体的捕捉、回放提供了强大的支持,使用它还可以在基于WDM驱动的采集卡上进行数据捕捉。本节将介绍有关DirectShow的相关知识。
while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)
{
pOutpin->QueryDirection(&pDir);
if (pDir==dir)
{
return pOutpin;
}
}
return 0;
}
用户可以按下面的方式获得某个过滤器的输入、输出引脚。
IPin * pComOut,*pComIn ;
在开发DirectShow应用程序时,通常需要设计一个过滤图表(Filter Graph),向过滤图表中添加相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。例如,实现一个简单的视频预览功能,需要向过滤图表中添加一个视频捕捉源过滤器和一个Video Renderer过滤器,将视频捕捉源过滤器的输出引脚与Video Renderer过滤器的输入引脚相连就可以了。而在程序中只需要按照设计过滤图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注意:只能是输出过滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。
为了在程序中使用DirectShow,需要单独安装DirectX,当前DirectX的最新版本为9.0,即DirectX9.0,用户可以从Microsoft的官方网站上免费下载。在安装DirectX之后,程序中需要引用“dshow.h”头文件,并导入“Strmiids.lib”库文件和“quartz.lib”库文件才可以使用DirectShow。代码如下:
wince下用DirectShow播放音频和视频

wince下用DirectShow播放音频和视频wince下用DirectShow播放音频和视频虽然网上关于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:消息的参数.那么,现在以接收一个视频播放结束事件的代码片段为例子: //自定义一个消息 #define WM_GRAPHNOTIFY (WM_USER + 13)//设置接收消息窗口和消息m_pMedia->SetVideoWindow(hWnd,WM_GRAPHNOTIFY,NULL);...//这个是消息循环函数LRESULT CMainWnd::WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) ...{switch(wMsg)...{...case WM_GRAPHNOTIFY:...{LONG evCode,evParam1,evParam2;//获取此时的DirectShow事件if(m_pMedia->GetEvent(&evCode,&evParam1,&evParam2) == TRUE)...{if(evCode == EC_COMPLETE)...{MessageBox(NULL,TEXT("播放完毕"),TEXT(""),MB_OK);}}return 0;}}...}好了,知道播放完毕,就这么简单.恩,还很复杂..?呵呵,我觉得已经很简单了.文章的最后,让我们再来看看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: interface for the CMedia class.////Version:// 1.2.0//Date:// 2007.05.08/**///////////////////////////////////////////////////////////////////////#ifndef MEDIA_H#define MEDIA_H#include <mmsystem.h>#include <streams.h>//--------------------------------------------------------------------//Macro define//The volume value#define MAX_VOLUME 0#define MIN_VOLUME -10000//The balance value#define MAX_BALANCE 10000#define MIN_BALANCE -10000//--------------------------------------------------------------------//Enum valueenum DISPLAYMODE...{//Fit to the play window size. How wide (height) the window is, how//is the move. Keep aspect ratio.DISP_FIT,//Stretch to the play window size. Don't keep the aspect ratio.DISP_STRETCH,//Full screen play.DISP_FULLSCREEN,//When the size of video is smaller than the play window, it displayes//as the video size. If it's bigger , it just like the DISP_FIT mode.DISP_NATIVE};//--------------------------------------------------------------------//The media file propertytypedef struct...{//The volume range is –10,000 to 0.//Divide by 100 to get equivalent decibel value (for example –10,000 = –100 dB).LONG lVolume;//The value from –10,000 to 10,000 indicating the stereo balance//As with the Volume property, units correspond to .01 decibels (multiplied by –1 when plBalance is a positive value).//For example, a value of 1000 indicates –10 dB on the right channel and –90 dB on the left channel.LONG lBalance;//Width of the videoLONG lWidth;//Height of the videoLONG lHeight;//Approximate bit rateLONG lBitRate;}MEDIAPROPERTY,*PMEDIAPROPERTY;//--------------------------------------------------------------------class CMedia...{public:BOOL GetEvent(LONG *plEvCode, LONG *plParam1, LONG *plParam2);BOOL SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData);BOOL SetVolume(LONG lVolume, LONG lBalance = 0);BOOL SetDisplayMode(DISPLAYMODE mode);BOOL GetMediaProperty(PMEDIAPROPERTY pOutProperty);static CMedia * GetInstance();void Close();BOOL CheckVisibility();void SetVideoWindow(HWND hWndVideo);BOOL Open(TCHAR * pszFileName);BOOL Stop();BOOL Pause();BOOL Play();virtual ~CMedia();protected:CMedia();// Collection of interfacesIGraphBuilder *m_pGB;IMediaControl *m_pMC;IMediaEventEx *m_pME;IVideoWindow *m_pVW;IBasicAudio *m_pBA;IBasicVideo *m_pBV;IMediaSeeking *m_pMS;TCHAR m_szFileName[MAX_PATH];HWND m_hWndVideo; //The window play videoHWND m_hWndNotify; //The window notifyBOOL m_bExitThrd;BOOL m_bThrdRunning;static CMedia * m_pInstance;DISPLAYMODE m_DispMode;};#endif //#ifndef MEDIA_H/**///////////////////////////////////////////////////////////////////////// Media.cpp: implementation of the CMedia class.///**///////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "Media.h"//----------------------------------------------------------------------------------------------//Macro define//Default play mode#define DEFAULT_DISPLAY_MODE DISP_NATIVE//----------------------------------------------------------------------//InitializeCMedia *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)...{delete m_pInstance;m_pInstance = NULL;}}//------------------------------------------------------------//Description:// Play the media file// When you call the function,you should call Open() before.////-------------------------------------------------------------BOOL CMedia::Play()...{// Run the graph to play the media fileif(m_pMC == NULL)...{return FALSE;}m_pMC->Run();return TRUE;}//------------------------------------------------------------//Description:// Pause.// When you call the function,you should call Open() before.////-------------------------------------------------------------BOOL CMedia::Pause()...{if(m_pMC == NULL)...{return FALSE;}m_pMC->Pause();return TRUE;}//------------------------------------------------------------//Description:// Stop.// When you call the function,you should call Open() before.////-------------------------------------------------------------BOOL CMedia::Stop()...{if(m_pMC == NULL || m_pMS == NULL)...{return FALSE;}m_pMC->Stop();m_pMS->SetPositions(0, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);return TRUE;}//--------------------------------------------------------------------------//Description:// Open the media file. When succeed in calling the function ,//you should call the Close() to release the resource////-------------------------------------------------------------------------BOOL CMedia::Open(TCHAR *pszFileName)...{BOOL bResult = FALSE;if(_tcslen(pszFileName) >= MAX_PATH)...{goto END;}else...{_tcscpy(m_szFileName,pszFileName);//Check the file existingHANDLE hdFile =CreateFile(m_szFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);if(hdFile == INVALID_HANDLE_VALUE)...{//The file doesn't existgoto END;}else...{CloseHandle(hdFile);}}// Initialize COMif(CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK)...{goto END;}// Get the interface for DirectShow's GraphBuilderif(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB) != S_OK)...{goto END;}// Have the graph construct its the appropriate graph automaticallyif(m_pGB->RenderFile(m_szFileName, NULL) != NOERROR)...{goto END;}// QueryInterface for DirectShow interfacesif(m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC) != NOERROR)...{goto END;}if(m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME) != NOERROR)...{goto END;}if(m_pGB->QueryInterface(IID_IMediaSeeking, (void **)&m_pMS) != NOERROR)...{goto END;}// Query for video interfaces, which may not be relevant for audio filesif(m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW) != NOERROR)...{goto END;}if(m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV) != NOERROR)...{goto END;}// Query for audio interfaces, which may not be relevant for video-only files if(m_pGB->QueryInterface(IID_IBasicAudio, (void **)&m_pBA) != NOERROR)...{goto END;}// Is this an audio-only file (no video component)?if (CheckVisibility() == TRUE)...{if(m_pVW->put_Owner((OAHWND)m_hWndVideo) != NOERROR)...{goto END;}if(m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN) != NOERROR) ...{goto END;}}//Set play modeSetDisplayMode(m_DispMode);bResult = TRUE;END:if(bResult == FALSE)...{//Release the resourceClose();}return bResult;}//------------------------------------------------------------//Description:// This method sets an owning parent for the video window.////Parameters:// hWnd : [in] Handle of new owner window.////----------------------------------------------------------void CMedia::SetVideoWindow(HWND hWndVideo)...{m_hWndVideo = hWndVideo;}//------------------------------------------------------------//Description:// Check the file visibility// When you call the function,you should call Open() before.////Parameters:// TRUE: Video// FALSE: It's not the video////------------------------------------------------------------BOOL CMedia::CheckVisibility()...{if (!m_pVW)...{//No VideoWindow interface. Assuming audio/MIDI file or unsupported video codec return FALSE;}if (!m_pBV)...{//No BasicVideo interface. Assuming audio/MIDI file or unsupported video codec. return FALSE;}// 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.long lVisible;if(m_pVW->get_Visible(&lVisible) != NOERROR)...{return FALSE;}return TRUE;}//------------------------------------------------------------//Description:// Release the resource which opened in the Open()////------------------------------------------------------------void CMedia::Close()...{// Relinquish ownership (IMPORTANT!) after hidingif(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;}// Finished with COMmemset(m_szFileName,0,sizeof(m_szFileName));CoUninitialize();}//------------------------------------------------------------ //Description:// Get the instance of object////------------------------------------------------------------ CMedia * CMedia::GetInstance()...{if(m_pInstance == NULL)...{m_pInstance = new CMedia();}return m_pInstance;}//------------------------------------------------------------ //Description:// Get the media file property.// When you call the function,you should call Open() before. ////------------------------------------------------------------ BOOL CMedia::GetMediaProperty(PMEDIAPROPERTY pOutProperty) ...{MEDIAPROPERTY prop = ...{0};if(m_pBA == NULL || m_pBV == NULL)...{return FALSE;}//Get the audio propertym_pBA->get_Volume(&prop.lVolume);m_pBA->get_Balance(&prop.lBalance);//Get the video propertyif(CheckVisibility() == TRUE)...{m_pBV->get_BitRate(&prop.lBitRate);m_pBV->GetVideoSize(&prop.lWidth,&prop.lHeight);}*pOutProperty = prop;return TRUE;}//------------------------------------------------------------//Description:// Set the display mode.// When you call the function,you should call Open() before.////------------------------------------------------------------BOOL CMedia::SetDisplayMode(DISPLAYMODE mode)...{if(m_pVW == NULL)...{return FALSE;}m_DispMode = mode;if(mode == DISP_FULLSCREEN)...{m_pVW->put_FullScreenMode(OATRUE);}else...{//Restore to the normal modem_pVW->put_FullScreenMode(OAFALSE);RECT rcWnd = ...{0};GetClientRect(m_hWndVideo,&rcWnd);LONG lWndWidth = rcWnd.right - rcWnd.left;LONG lWndHeight = rcWnd.bottom - rcWnd.top;MEDIAPROPERTY prop = ...{0};GetMediaProperty(&prop);if(mode == DISP_FIT || mode == DISP_NATIVE)...{LONG lDispLeft,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;}else if(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);}else if(mode == DISP_STRETCH)...{m_pVW->put_Left(0);m_pVW->put_Top(0);m_pVW->put_Width(lWndWidth);m_pVW->put_Height(lWndHeight);}}return TRUE;}//------------------------------------------------------------//Description:// Set the volume.// When you call the function,you should call Open() before.////Parameters:// lVolume:[in] The volume (amplitude) of the audio signal.// Range is –10,000 to 0.// lBalance:[in] The balance for the audio signal. Default value is 0.// The value from –10,000 to 10,000 indicating the stereo balance.////------------------------------------------------------------BOOL CMedia::SetVolume(LONG lVolume, LONG lBalance)...{if(m_pBA == NULL)...{return FALSE;}if(lVolume < MIN_VOLUME && lVolume > MAX_VOLUME && lBalance < MIN_BALANCE && lBalance > MAX_BALANCE)...{return FALSE;}m_pBA->put_Volume(lVolume);m_pBA->put_Balance(lBalance);return TRUE;}//----------------------------------------------------------------------//Description:// Registers a window that will handle messages when a specified event occurs.////Parameters:// hWnd:[in] Handle of window to notify. Pass NULL to stop notification.// wMsg:[in] Window message to be passed as the notification.// lInstanceData:[in] Value (instance data) to be passed as the lParam parameter for the lMsg message.////-----------------------------------------------------------------------------BOOL CMedia::SetNotifyWindow(HWND hWnd, UINT wMsg,long lInstanceData)...{if(m_pME == NULL)...{return FALSE;}m_pME->SetNotifyWindow((OAHWND)hWnd,wMsg,lInstanceData);return TRUE;}//---------------------------------------------------------------------- //Description:// This method retrieves the notification event.////----------------------------------------------------------------------- BOOL CMedia::GetEvent(LONG *plEvCode, LONG *plParam1, LONG *plParam2) ...{if(m_pME == NULL)...{return FALSE;}LONG evCode, evParam1, evParam2;if(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0) == NOERROR)...{*plEvCode = evCode;*plParam1 = evParam1;*plParam2 = evParam2;// Spin through the eventsm_pME->FreeEventParams(evCode, evParam1, evParam2);}else...{return FALSE;}return TRUE;}本文来自CSDN博客,转载请标明出处:/norains/archive/2007/05/14/1609118.aspx。
基于Directshow的H.264流媒体播放器设计

命令控 制等 ; 其二就是客户端对接收到 的多媒体流实 时解 码 后播 放的技 术 。显然 , 网络 通信 可 以使 用 wn o ssce 技 i w ok t d 术 , 媒 体 流 的解 码 播 放 可 以使 用 dr t o 多 i es w技 术 。本 文 采 e h 用 dr t o i cs w应 用 框 架 , 计 了 网 络 源 ftr h 2 解 码 e h 设 i e 和 .6 l 4 ie 并 ft , 通过 Fl r rp lr ie ah构建 了流媒体播放器 J t G 。
1 D rc h w技术 和 H.6 i to es 2 4视频 压 缩标 准简 介
Dr t o i cs w是微软公 司提供的一套流媒体开发软件包 , e h 为 在 wno s 台 上处 理 各 种格 式 的媒 体 文件 的 回放 、 视 频 采 idw 平 音 集的高性能要求的多媒体应用 , 了完整的解决方案 。。 提供 Dre hw是一套完 全基 于 C M 的应用 系统 , i to es O 该系统位 于 应 用 层 中 , 使 用 Fl r rp 它 ie ah的 模 型 来 管 理 整 个 数 据 流 t G 的 处 理 过 程 ; 与 数 据 处 理 的 各 个 功 能 模 块 叫 Fl r各 个 参 ie ; t Fl r Fl rG ah中按 照 一定 的顺 序连 接成 一 条 “ 水 ie 在 ie rp t t 流 线” 同工作 。Flr 协 ie 是一个 C M 组件 , 功能可 以 由用 户 t O 其 自行 实 现 , i c hwS K 电为 用 户 提 供 了一 些 标 准 的 Fl r D r t o D eS ie t 供 用 户 使 用 。各 个 Fl r FlrG ah中按 一 定 顺 序 通 过 ie 在 ie rp t t
基于DirectShow的p2p流媒体播放器的实现

[ 键 词 ] Die th w; 媒 体 播 放 器 ; 2 关 rcS o 流 pp [ 图 分 类 号 ]P3 7 中 , 1 I 【 献 标 识 码 ]A 文 [ 章 编 号 ]1 0 — 5 0( 0 7 0 一 1 8 0 文 09 9 3 2 0 )3 O 1— 3
基于 Di cS o r th软件 学院 , 徽 合 肥 2 0 5 ) 中 安 3 0 2
的实现
【 摘 要 】 文 章 介 绍 了一 种 基 于 Die th w 技 术 的 p p流 媒 体 播 放 器 , 要 着 重 于 几 项 关 键 技 术 : rcS o 2 主
Di cS o 是 微 软 公 司 提 供 的 一 套 在 据 并 将 其 导 入 过 滤 器 图 ; 换 过 滤 器 用 来 获 取 、 r th w e 转 处 Wid w n o s平 台 上 进 行 多 媒 体 处 理 的 开 发 包 . 多 媒 理 和 传 送 媒 体 数 据 . 它 包 括 分 离 视 频 和 音 频 的 切 为 体 流 的 捕 捉 和 回 放 提 供 了 强 有 力 的 支 持 运 用 分 过 滤 器 、 压 视 频 数 据 的 视 频 解 码 过 滤 器 、 压 解 解 Die th w . 们 可 以 很 方 便 地 播 放 从 本 地 文 件 和 音 频 数 据 的 音 频 解 码 过 滤 器 : 表 现 过 滤 器 用 来 在 rcS o 我 网 络 播 放 多 媒 体 流 . 支 持 W DM 驱 动 模 型 的 采 集 硬 件 上 表 现 媒 体 数 据 . 如 显 卡 和 声 卡 或 是 磁 盘 文 从
户 。 P P流 媒 体 的 应 用 是 在 P P文 件 交 换 的 基 础 2 2 上产 生 的 . 户 在互 联 网 上观 看 视 频 流媒 体 时 , 用 可
用directshow开发视频解码插件

7
用 drc h w开 发视 频 解码 插 件 i to es
李 晓静 刘 爱 玉 李 舜 昌 邵 兰英
( 南柴 油 机 股 份有 限公 司 , 南 2 0视 频 回 放 系 统 需 要 专 门 开 发 播 放 软 件 。 文 介 绍 了在 V sa c 十 中 利 用 Di c h w DK 定 传 本 i l + u rto S eS
键 函数 。
关 键 词 : 频 解 码 插 件 视
Di c h w rto eS
视 频 监 控 系统 在实 际 中具 有 广 泛 的应 用 范 围 , 核 心 其
技 术 包 括 视 频 数 据 的 采 集 、 缩 、 输 、 存 与 回 放 。本 文 压 传 保
样, 我们 可 以利用 一 个 .e 文件 方 便 地 描述 需 要 导 出 的函 df
随着 信 息技 术 的发 展 ,多媒 体 技 术 面 临 越来 越 多 的 挑 战 , 发 多媒 体 应用 程 序 愈发 复 杂 。 i c h w的设 计初 开 Dr t o eS
衷 就是 让 应 用 程 序 开 发人 员 从 复 杂 的数 据 传输 、硬 件 差
Dl eCa s betP I A E l t l O jc R V T G s
R ls e ae版 本 ,tn a.b mscti wn m.b e s b 1 、 vr 1 n s i .b、 im 1 i
V 目录之 前 , C 以便 编 译器 使 用最 新 版 本 的源 文件 。
2 2 Fl r 类 的 选 择 . ie 基 t 我 们 的 设 计 主 要 包 括 两 个 核 心 类 ,分 别 是 C ie t Fhr r C 和 C eo eS em, 其 中 , Fhr t控 制 文 件 数 据 的 管 理 , D cd dt a r C ieCr
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
DirectShow 媒体文件回放总结收藏作者:Inkick1.概述DirectShow中媒体文件回放的过程也就是一个为媒体文件选择相应所需的Filter、构建Filter Graph、并对Filter Graph的状态进行维持、控制的过程。
这里所说的媒体文件,不仅仅是指音频、视频文件,同时也包括bmp、jpeg、gif等图形图像格式以及midi等数字化音乐序列。
因此,使用DirectShow进行媒体文件的回放需要经过以下的步骤:2.构建Filter GraphFilter Graph为Filter提供了一个容器,一个构建完整的Filter Graph也就是一个完整的Filter 连路,这个连路对于程序是透明的,可控制的。
而对于每一个媒体文件来说,Filter Graph 与媒体文件存在着对应的关系。
也就是说,一个Filter Graph只能实现一个(种)文件的回放。
在DirectShow中,Filter Graph是由接口对象IGraphBuilder实现的,我们可以调用Win32 API 函数CoCreateInstance()建立一个实体。
Filter Graph实体建立之后并不具有任何的Filter,因此不具有任何实际用途。
因此我们需要连接需要的Filter来完成FilterGraph的构建。
智能连接这个术语覆盖了一系列Filter Graph Manager用于构建所有或部份filter graph的算法。
任何时候,当Filter Graph Manager需要添加filter来完成graph时,它大致做以下几件事情:如果有一个filter存在于graph中,而且这个filter有至少一个没有连接的input pin,Filter Graph Manager试着去试用这个filter。
否则,Filter Graph Manager在已注册的filter中寻找连接时可以接受合适的媒体类型的filter。
每一个filter都注册有一个Merit值,这个值用以标记哪个filter最容易被Filter Graph Manager 选中来完成graph。
Filter Graph Manager按Merit值的顺序来选择filter,Merit值越大,被选中的机会越大。
对于每种流类型(如音频、视频、MIDI),默认的renderer具有一个很高的Merit值,解码器同样是,专用filter具有低Merit值。
如果Filter Graph Manager选择的filter不合适,它会返回来尝试另外的filter组合。
我们有三种构建graph的途径:1.filter graph manager构建整个graph2.filter graph manager构建部分graph3.应用程序构建整个graph2.1 RenderFileIGraphBuilder提供了多种智能完成FilterGraph构建的方法。
最简单的是使用接口方法IGraphBuilder::RenderFile。
HRESULT RenderFile(LPCWSTR lpwstrFile, LPCWSTR lpwstrPlayList);第一个参数为文件的路径(祥见后文),第二个参数保留,必须为空。
这个方法需要一个表示媒体文件路径或者URL的Unicode字符串参数。
而我们通过界面获得的文件路径的字符串往往是ANSI字符串。
我们可以使用下面方法进行转换:包含头文件:#include <tchar.h>#include <atlbase.h>这两个头文件包含了ANSI字符串与Unicode字符串相互转化的函数与宏使用宏:USES_CONVERSION;定义一个WCHAR的数组:WCHAR FileName[MAX_PA TH];而MAX_PA TH是在windef.h中定义的:#define MAX_PA TH 260这与windows路径最大字符为260个相符。
这个数组保存转化后的Unicode形式表示的路径。
然后可以使用下面的函数进行转换:(假定以ANSI形式给出的字符串为szFile)wcsncpy (FileName, T2W(szFile), NUMELMS(wFile)-1);FileName[MAX_PA TH-1] = 0;wcsncpy的原型:wchar_t *wcsncpy( wchar_t *strDest, const wchar_t *strSource, size_t count );这个函数的作用类似于strcpy,是实现字符串之间的复制。
只不过,这是一个用在Unicode 上的版本。
第一个参数指定了字符串转化后的存放地址,也就是我们要得到的Unicode字符串,第二个参数指定了要转化的字符串的来源地址,也就是我们要转化的ANSI字符串。
在第二个参数使用了宏T2W(szFile),这个宏可以把一个ANSI字符串转为一个WCHAR类型的字符串。
第三个参数为转化字符串中字符的数量。
现在问题出来了,这个函数的第二个参数需要宽字符串的地址,如果我们有这样的一个地址,我们还转换什么?因此这个的关键在于T2W上面。
让我们来看一下T2W的定义。
这个定义在头文件A TLCONV.H里面(只保留我们比较感兴趣的部分)。
#ifdef _UNICODEinline LPWSTR T2W(LPTSTR lp) { return lp; }inline LPTSTR W2T(LPWSTR lp) { return lp; }#else#define T2W A2W#endif我们可以看到,如果定义了_UNICODE,则T2W直接返回将要转化的字符串,这是因为在Unicode环境下,ANSI字符拥有和Unicode字符同样的宽度。
也就是说,ANSI是Unicode 的一个子集。
但是在非Unicode环境下,就将T2W替换成A2W,这样我们返回来看A2W 的定义(这个定义在同样的头文件中):#define A2W(lpa) (\((LPCSTR)lpa == NULL) ? NULL : (\_convert = (lstrlenA(lpa)+1),\A TLA2WHELPER((LPWSTR) alloca(_convert*2), lpa, _convert)))宏定义比较晦涩,我们转换成比较好理解的函数形式:LPCSTR A2W(LPTSTR lpa){if(lpa == NULL){return NULL;}_convert = (lstrlen(A)(lpa)+1);AtlA2WHelper ((LPWSTR)alloca(_covert*2),lpa,_convert);return lpa;}这个函数的结构比较清晰,首先判断是不是空字符串,如果是空字符串就返回空,因为ANSI 和Unicode意义上的空字符串都是NULL,如果不为空,则开始转换。
重点是函数A TLA2WWHELPER(),这个函数的实现部分在A TLCONV.CPP中:LPWSTR WINAPI AtlA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars){_ASSERTE(lpa != NULL);_ASSERTE(lpw != NULL);lpw[0] = '\0';MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars);return lpw;}这个函数除了做一些必要的安全性判定以及前序准备以外,核心工作是调用了一个函数MultiByteToWideChar,因此我们还要继续深入。
这次我们发现我们找不到源代码了,但是在MSDN中我们可以得到明确的提示:int MultiByteToWideChar(UINT CodePage, // code pageDWORD dwFlags, // character-type optionsLPCSTR lpMultiByteStr, // address of string to mapint cchMultiByte, // number of bytes in stringLPWSTR lpWideCharStr, // address of wide-character bufferint cchWideChar // size of buffer);这个API函数接受六个参数(Win32 API的风格——参数超多),第一个参数指定了CodePage(解释见附录5.1),在这里我们可以指定CP_ACP,来表示我们选择ANSI Code Page 代表我们要转换的源字符串编码形式为ANSI,第二个参数是一组位标志,决定了如何处理原字符串中的控制字符或者无效字符。
一般指定MB_PRECOMPOSED,第三个参数是源字符串的地址(或者指针)。
第四个字参数是要转化的字符串里面包含了多少个字符,第五个参数指定了转换后的字符串的存放地址,第六个参数指定了转换后字符串的Buffer的大小,也就是转换后占用内存空间的多少。
现在我们逐层返回,(如果你已经忘记了我们的初衷是什么建议你听一下F.I.R的歌),根据最核心的函数MultiByteToWideChar的分析,我们可以得出AtlA2Whelper几个参数的含义:AtlA2WHelper( LPWSTR lpw, //转化的目标字符串的地址LPCSTR lpa, //转化的源字符串的地址int nChars //源字符串中包含的字符数)因此在判断lpw以及lpa不为空之后便直接调用:lpw[0] = '\0';MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars);我们已经返回到了那个宏,还是让我们来看我们改写的那个函数吧:_convert = (lstrlen(A)(lpa)+1);AtlA2WHelper ((LPWSTR)alloca(_covert*2),lpa,_convert);return lpa;lstrlen函数得到参数字符串的长度(对于ANSI字符串来说是字节数,对于Unicode字符串来说是字符数),后面的(A)表明参数字符串为ANSI字符串,经过这个参数的调用,_convert 的值变成了要转换的字符串长度加一。
为什么要加一呢?因为字符串的结尾要补上一个’\0’,我们总要为这个’\0’预留空间。
下一步就是要申请空间来保存转化完成的字符串了,使用(LPWSTR)alloca(_covert*2),分配字符串数的两倍空间(因为Unicode字符占用的空间是ANSI的两倍),然后将地址转为LPWSTR,当作参数传递给AtlA2Whelper,开始转换,任务完成!可是,真的完成了吗?那个该死的_convert是哪里来的?哈哈,还记得我们一开始说的吗?回忆一下,在使用T2W之前要做的工作是什么?使用宏USES_CONVERSION;!为什么呢?我们继续看这个宏的定义:#ifndef _DEBUG#else#define USES_CONVERSION int _convert = 0#endif看到了吗?这个宏其实就是在定义这个_convert变量。