DirectXVisual C++ 7.1Windows Vista.NET 1.0C++/CLIVisual Studio .NET 2003Windows 2003.NET 1.1Windows 2000Windows XP中级开发Visual StudioWindowsC++.NET
使用 DirectShow Video Mixing Renderer 9 过滤器






4.58/5 (28投票s)
2005年1月3日
2分钟阅读

829498

11392
本文介绍了如何动态混合两个视频文件(.mpeg、.mpg、.avi 和 .dat)。混合包括使用 DirectShow 的 VMR9 过滤器,对两个视频流分别进行 Alpha 混合、拉伸/缩小和定位。
引言
本文介绍了创建和配置 DirectShow 的 Video Mixing Renderer Filter 9 (VMR9) 的步骤。两个视频流,一个在另一个之上,渲染在单个表面上。 在我们的例子中,这个表面是一个 PictureBox
控件。每个流的 Alpha 值、位置和高度/宽度都可以在运行时调整。
VMR9 的不同之处
以下图表显示了使用 VMR9 和不使用 VMR9 渲染两个视频的区别。
不使用 VMR9
我们注意到,简单地渲染两个视频会导致两个单独的视频渲染器,这意味着视频是在两个单独的表面上播放的。
使用 VMR9
在这种情况下,VMR9 过滤器将两个视频流导向其自身的输入引脚。 这意味着只有一个渲染器,因此两个视频流只有一个渲染表面。
工作原理
为了增强可重用性和可读性,VMR9 过滤器的功能已被封装在一个名为 myVMR9
的类中。
myVMR9 类
此类具有以下私有数据成员
VMR9NormalizedRect *r;
IVMRWindowlessControl9 *pWC;
IVMRMixerControl9 *pMix;
IGraphBuilder *pGB;
IBaseFilter *pVmr;
IVMRFilterConfig9 *pConfig;
IMediaControl *pMC;
IMediaSeeking *pMS;
构造函数
构造函数接收 PictureBox
的类型为 System::Drawing::Rectangle
的坐标,以及类型为 HWND
的处理程序。 VMR9 使用这两个属性进行渲染。
public: myVMR9(System::Drawing::Rectangle rect, HWND hwnd) { // initialize video coordinates with normal values r = new VMR9NormalizedRect; r->left = 0; r->top = 0; r->right = 1; r->bottom = 1; pWC = NULL; pMix = NULL; pGB = NULL; pVmr = NULL; pConfig = NULL; pMC = NULL; pMS = NULL; // create an instance of the Filter Graph Manager CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB); // create an instance of the VMR9 filter CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr); // add the VMR9 filter to the Graph Manager pGB->AddFilter(pVmr, L"Video"); // get a pointer to the IVMRFilterConfig9 interface pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig); // make sure VMR9 is in windowless mode pConfig->SetRenderingMode(VMR9Mode_Windowless); // get a pointer to the IVMRWindowlessControl9 interface pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC); // explicitly convert System::Drawing::Rectangle type to RECT type RECT rcDest = {0}; rcDest.bottom = rect.Bottom; rcDest.left = rect.Left; rcDest.right = rect.Right; rcDest.top = rect.Top; // set destination rectangle for the video pWC->SetVideoPosition(NULL, &rcDest); // specify the container window that the video should be clipped to pWC->SetVideoClippingWindow(hwnd); // IVMRMixerControl manipulates video streams pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix); // IMediaSeeking seeks to a position in the video stream pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS); // IMediaControl controls flow of data through the graph pGB->QueryInterface(IID_IMediaControl, (void **)&pMC); }
方法
HRESULT play() { pMC->Run(); return S_OK; } HRESULT pause() { pMC->Pause(); return S_OK; } HRESULT stop() { LONGLONG pos = 0; pMC->Stop(); pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, NULL,AM_SEEKING_NoPositioning); pMC->Pause(); return S_OK; } HRESULT close() { // make sure resources are freed SAFE_RELEASE(pWC); SAFE_RELEASE(pMix); SAFE_RELEASE(pGB); SAFE_RELEASE(pVmr); SAFE_RELEASE(pConfig); SAFE_RELEASE(pMC); SAFE_RELEASE(pMS); return S_OK; } HRESULT setAlpha(DWORD stream, float alpha) { // set alpha of specified video stream pMix->SetAlpha(stream, alpha); return S_OK; } HRESULT setX(DWORD stream, float x) { // video displacement along x-axis r->right = x + (r->right - r->left); r->left = x; pMix->SetOutputRect(stream, r); return S_OK; } HRESULT setY(DWORD stream, float y) { // video displacement along y-axis r->bottom = y + (r->bottom - r->top); r->top = y; pMix->SetOutputRect(stream, r); return S_OK; } HRESULT setW(DWORD stream, float w) { // video stretching/shrinking along x-axis r->right = r->left + w; pMix->SetOutputRect(stream, r); return S_OK; } HRESULT setH(DWORD stream, float h) { // video stretching/shrinking along y-axis r->bottom = r->top + h; pMix->SetOutputRect(stream, r); return S_OK; } HRESULT renderFiles(String* file1, String* file2) { // convert String type to LPCSTR type and render the videos LPCTSTR lFile; lFile = static_cast<LPCTSTR>(const_cast<void*>(static_cast<const void*> (System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(file1)))); pGB->RenderFile((LPCWSTR)lFile, NULL); lFile = static_cast<LPCTSTR>(const_cast<void*>(static_cast<const void*> (System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(file2)))); pGB->RenderFile((LPCWSTR)lFile, NULL); System::Runtime::InteropServices::Marshal::FreeHGlobal (static_cast<IntPtr>(const_cast<void*> (static_cast<const void*>(lFile)))); pMC->StopWhenReady(); return S_OK; }
现在 VMR9 的功能已与 GUI 分离,Button 和 TrackBar 处理程序可以简单地创建一个指向 myVMR9
对象的指针并调用所需的方法。
附加信息
- 第二个打开的视频流位于第一个视频流之上,即文件 2 视频渲染在文件 1 视频之上。 因此,如果第一个视频的 Alpha 值为 100%,第二个视频的 Alpha 值为 50%,则两个视频将同样 (50%) 可见。
- 应该注意的是,TrackBar 的宽度和高度值可能会变为负值。 因此,当视频流的宽度为 -100% 时,它会横向反转。 类似地,当视频流的高度为 -100% 时,视频是倒置的。