IGraphBuilder: 负责 Filter Graph的创建
应用程序通过此接口建立过滤器流水线。主要方法为:RenderFile,自动识别多媒体文件的类型、格式,建立适用于该格式的过滤器流水线。
IMediaControl: 操作Filter Graph 中的多媒体数据流
控制过滤器流水线的运行。主要方法为:Run开始运行;Pause,暂停运行;Stop,停止运行。
IMediaEvent(Ex): 处理 Filter Graph (Event)的事件
应用程序通过此接口获得播放过程中发生的事件,如 EC_COMPLETE(播放完毕)等。主要方法为:SetNotifyWindow,指定处理事件通知的窗口;GetEvent,获得事件。
IVideoWindow: 用于设置多媒体播放窗口的属性
控制视频窗口的属性。主要方法为:put_Owner,指定视频窗口的父窗口;put_FullScreenMode,指定全屏播放模式;SetWindowPosition,指定视频窗口的位置;put_MessagerDrain,指定一个窗口,用于接收视频窗口发出的鼠标等消息。
IMediaSeeking:提供了一些简单的搜索功能
提供了对多媒体数据流的播放位置等属性的精确控制。主要方法为:SetPositons,设置播放的起始和终止位置;GetCurrentPosition,获得当前播放位置。
IFilterMapper2:对注册表中的滤波器进行枚举
IBasicAudio:
控制音频数据流的基本属性:音量和均衡。主要方法:put_Volume、get_Volume,设置或获得音量;put_Balance、get_Balance,设置或获得均衡。
在实现多媒体文件的播放时需要用到上述的接口,这些接口的每个方法只执行一个简单的操作。因此,有必要对这些接口进行封装,见(VC下利用DirectShow播放多媒体文件.PDF)
创建 Filter Graph Manager接口
以下是创建 Filter Graph Manager接口的例子:
//首先申明并且初始化必需的接口。由于接口的索引值是自动加1 ,所以不要调用
// Iunknow::Addref
IGraphBuilder pGraph = NULL;
IMediaControl pMediaControl = NULL;
IMediaEvent pEvent = NULL;
IVideoWindow pVW = NULL;
IMediaSeeking pMS = NULL;
IFilterMapper2 pMapper = NULL;
// 实例化一个 Filter Graph Manager ,并且查询各接口
CoCreateInstance(CLSID_FilterGraph, NULL , CLSCTX_ INPROC_SERVER,
IID_ IGraphBuilder , (void **) &pGraph) ;
pGraph -> QueryInterface ( IID_IMediaControl , ( void **)&pMediaControl2 ) ;
pGraph ->QueryInterface(IID_IMediaEvent , (void** ) &pEvent) ;
pGraph ->QueryInterface(IID_IVideoWindow, (void**) &pVW) ;
pGraph2>QueryInterface IID_IMediaSeeking, void(**)&pMS ;
CoCreateInstance(CLSID_FilterMapper2 , NULL , CLSCTX _INPROC,
IID_IFilterMapper2 ,(void **) &pMapper) ;
播放MP3音乐
MIDI音乐的问题是对声卡的依赖性过大,好声卡和差声卡的播放效果实在相差太远。WAV音乐虽然绝对足够精确,但占用的空间之大不可小视。MP3恐怕是一个较好的解决方案。值得注意的是,播放MP3并不需要DirectX
7.7.1
下面把初始化DirectShow和调入MP3合起来说说吧。首先,我们要定义三个对象,其中IGraphBuilder*类型的可以认为是媒体播放设备,IMediaControl*类型的变量负责媒体的播放控制,而IMediaPosition*类型的变量负责媒体的播放位置设定。
#define SAFE_RELEASE(o) if(o){o->Release();o=NULL;}
IGraphBuilder*
IMediaControl*
IMediaPosition*
CoInitialize(NULL);
//创建各个对象
CoCreateInstance(CLSID_FilterGraph,
CLSCTX_INPROC,
pGBuilder-> QueryInterface(IID_IMediaControl,
pGBuilder-> QueryInterface(IID_IMediaPosition,
CHAR
WCHAR
GetCurrentDirectory(MAX_PATH,
strcat(strSoundPath,
strcat(strSoundPath,
MultiByteToWideChar(CP_ACP,
pGBuilder-> RenderFile(wstrSoundPath,
7.7.2
播放MP3的方法十分简单:
pMPos-> put_CurrentPosition(0);
pMControl-> Run();
7.7.3
最后,我们要停止播放音乐并释放各个对象:
pMControl-> Stop();
Stop方法使filter graph停止,这个方法非常重要,因为在媒体文件播放结束后filter graph不会自己停止。
//释放对象
SAFE_RELEASE(pMControl);
SAFE_RELEASE(pMPos);
SAFE_RELEASE(pGBuilder);
CoUninitialize();
问题:
Q:如何能知道一个mp3文件播完没有?
A:DSHOW中是使用事件通知机制和应用程序进行通讯,在播放完成后Graph
关于事件接收:查看下一篇文章《DirectShow事件通知概述》
具体代码:
先得到IMediaEvent接口实例:
IGraphBuilder*
IMediaEvent* m_pMEvent;
CoCreateInstance(CLSID_FilterGraph,NULL, CLSCTX_INPROC,IID_IGraphBuilder,(void**)&m_pGBuilder);
m_pGBuilder->QueryInterface(IID_IMediaEvent, (void**)&m_pMEvent);
两种方法:
一:使用IMediaEvent接口的GetEvent方法:
二:在run之后等待
Q:如何进行播放循环?
A:在事件处理函数中处理EC_COMPLETE事件代码,就是把GRAPH定位到时间线的开头(不需要再次调用run方法,因为媒体文件播放完毕后并没有stop)
Q:播放a.mp3完毕后进行stop,然后重新Render进去一个新的B.wma文件,结果出现重叠播放B.wma和a.mp3文件的状况,我已经stop了啊,stop不是释放资源了吗??
A:换文件必须重新构建Filter
Q:如何调节播放器的声音?
A:使用IBasicAudio接口
本来这个问题没有任何悬念,但是,事实上并不是简单调用一下IBasicAudio.put_Volume就成了。我的实现代码如下,已在调试中通过,多谢VC+DirectShow+AVS的“上海--阿易”兄的帮助。
/// <summary>
转自:http://tianmoboping.blog.163.com/blog/static/15739532200871955244339/