65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 DirectShow Video Mixing Renderer 9 过滤器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (28投票s)

2005年1月3日

2分钟阅读

viewsIcon

829498

downloadIcon

11392

本文介绍了如何动态混合两个视频文件(.mpeg、.mpg、.avi 和 .dat)。混合包括使用 DirectShow 的 VMR9 过滤器,对两个视频流分别进行 Alpha 混合、拉伸/缩小和定位。

Sample Image - DirectShowVMR91.jpg

引言

本文介绍了创建和配置 DirectShow 的 Video Mixing Renderer Filter 9 (VMR9) 的步骤。两个视频流,一个在另一个之上,渲染在单个表面上。 在我们的例子中,这个表面是一个 PictureBox 控件。每个流的 Alpha 值、位置和高度/宽度都可以在运行时调整。

VMR9 的不同之处

以下图表显示了使用 VMR9 和不使用 VMR9 渲染两个视频的区别。

不使用 VMR9

Rendering without VMR9

我们注意到,简单地渲染两个视频会导致两个单独的视频渲染器,这意味着视频是在两个单独的表面上播放的。

使用 VMR9

Rendering with 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 对象的指针并调用所需的方法。

Sample screenshot

附加信息

  • 第二个打开的视频流位于第一个视频流之上,即文件 2 视频渲染在文件 1 视频之上。 因此,如果第一个视频的 Alpha 值为 100%,第二个视频的 Alpha 值为 50%,则两个视频将同样 (50%) 可见。
  • 应该注意的是,TrackBar 的宽度和高度值可能会变为负值。 因此,当视频流的宽度为 -100% 时,它会横向反转。 类似地,当视频流的高度为 -100% 时,视频是倒置的。
© . All rights reserved.