在前面的这篇博文中,我们开始利用的手动建立Filter Graph,已经完成了Splitter Source Filter和Audio/Video Decoder的建立和链接。接下来需要做的是渲染解码完成的音视频数据,分别由Audio Render和Video Render完成。音频渲染器较为简单也很少会出问题,我们主要讨论视频渲染器的问题。
DirectShow所提供的视频渲染器种类有多种,如Video Renderer(已不常用)、VMR-7、VMR-9、EVR等。MSDN的文档讲了各种视频渲染器的相关知识。其中提到了“在vista之后的windows版本中,如果硬件支持应使用EVR”,既然已经是win 7了,那自然是首选EVR了。这部分的代码如下:
int _tmain(int argc, _TCHAR* argv[]) { //...... hr = AddFilterByCLSID(pGraph,CLSID_LavSplitter_Source,L"Lav Splitter Source",&pLavSplitterSource); hr = pLavSplitterSource->QueryInterface(IID_IFileSourceFilter,(void **)&pFileSourceFilter); hr = pFileSourceFilter->Load(fileName,NULL);//必须loadfile后才能检索pin hr = AddFilterByCLSID(pGraph,CLSID_LavVideoDecoder,L"Lav Video Decoder",&pLavVideoDecoder); hr = ConnectFilters(pGraph,pLavSplitterSource,pLavVideoDecoder); hr = AddFilterByCLSID(pGraph,CLSID_LavAudioDecoder,L"Lav Audio Decoder",&pLavAudioDecoder); hr = ConnectFilters(pGraph,pLavSplitterSource,pLavAudioDecoder); hr = AddFilterByCLSID(pGraph,CLSID_EnhancedVideoRenderer,L"Enhanced Video Renderer",&pRenderer); hr = ConnectFilters(pGraph,pLavVideoDecoder,pRenderer); hr = AddFilterByCLSID(pGraph,CLSID_AudioRender,L"Audio render",&pAudioRender); hr = ConnectFilters(pGraph,pLavAudioDecoder,pAudioRender); //...... }
但是我们发现一个问题,电影已经正常播放,但是只有声音却没有图像,这是为何?
通过搜索得知,DirectShow的渲染器定义了两种模式:窗口模式和非窗口模式。窗口模式下,视频渲染器会自动生成一个视频播放窗口,渲染完成的画面会显示在这个视频窗口中;当然我们可以获取这个窗口的句柄进行下一步操作比如讲该窗口置于我们自定义的应用窗口下加以控制。非窗口模式下,视频渲染器需要指定一个视频输出窗口,将数据渲染在该窗口中。在这两种模式中,Video Renderer只支持窗口模式,VMR-7/9支持两种模式,默认为窗口模式。而在MSDN文档中指出,EVR并不支持窗口模式,显示窗口必须由应用程序自己创建。而我们的demo只是一个控制台程序,不存在窗口,自然也就无法渲染视频了。
既然不支持,那我们就换掉,改为使用VMR-9进行绘制。方法很简单,在添加EVR组件的语句中将CLSID_EnhancedVideoRenderer改为CLSID_VideoMixingRenderer9就可以了。
编译链接运行,查看Filter Graph,如下图:
播放画面:
至此,我们已经成功地把一部主流格式的电影文件通过手动建立Filter Graph的方式播放出来了,也对DirectShow的基本概念有了一定的了解。接下来还将继续进一步深入研究与其相关的更多内容。
下载该demo点这里