VMR 无窗口模式

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

无窗口模式是应用程序在应用程序窗口中呈现视频的首选方式。 在无窗口模式下,视频混合呈现器不会加载其窗口管理器组件,因此不支持 IBasicVideoIVideoWindow 接口。 相反,应用程序会提供播放窗口,并在 VMR 的工作区中设置一个目标矩形来绘制视频。 VMR 使用 DirectDraw 剪辑器对象来确保视频已剪辑到应用程序的窗口,并且不会显示在任何其他窗口中。 VMR 不会对应用程序的窗口进行子类化,也不会安装任何系统/进程挂钩。

在无窗口模式下,连接和转换到运行状态期间的事件序列如下所示:

  • 上游筛选器建议 VMR 接受或拒绝的媒体类型。
  • 如果媒体类型被接受,VMR 会调用分配器呈现器来获取 DirectDraw 图面。 如果成功创建图面,则引脚会连接,VMR 已准备好转换为运行状态。
  • 筛选器图运行时,解码器会调用 GetBuffer 从分配器获取媒体样本。 VMR 查询分配器演示者,以确保其 DirectDraw 图面上的像素深度、矩形大小和其他参数与传入视频兼容。 如果它们兼容,VMR 会将 DirectDraw 图面返回到解码器。 解码器解码到图面后,VMR 的核心同步单元将验证时间戳。 本单元阻止 接收 调用,直到演示时间到达。 此时,VMR 在分配器表示器上调用 PresentImage,它将图面呈现给图形卡。

下图显示了具有多个输入流的无窗口模式下的 VMR。

vmr 处于无窗口模式

为无窗口模式配置 VMR-7

若要将 VMR-7 配置为无窗口模式,请在连接 VMR 的任何输入引脚之前执行以下步骤:

  1. 创建筛选器并将其添加到图形中。

  2. 使用 VMRMode_Windowless 标志调用 IVMRFilterConfig::SetRenderingMode 方法。

  3. (可选)通过调用 IVMRFilterConfig::SetNumberOfStreams 为多个输入流配置 VMR。 VMR 为每个流创建一个输入引脚。 使用 IVMRMixerControl 接口设置流的 Z 顺序和其他参数。 有关详细信息,请参阅 具有多个流的 VMR (混合模式)

    如果不调用 SetNumberOfStreams,则 VMR-7 默认为一个输入引脚。 连接输入引脚后,无法更改引脚数。

  4. 调用 IVMRWindowlessControl::SetVideoClippingWindow 以指定呈现的视频将出现在其中的窗口。

完成这些步骤后,可以连接 VMR 筛选器的输入引脚。 生成图形的方法有多种,例如直接连接引脚、使用 IGraphBuilder::RenderFile 等智能连接方法,或使用捕获图形生成器的 ICaptureGraphBuilder2::RenderStream 方法。 有关详细信息,请参阅 常规Graph-Building技术

若要设置视频在应用程序窗口中的位置,请调用 IVMRWindowlessControl::SetVideoPosition 方法。 IVMRWindowlessControl::GetNativeVideoSize 方法返回本机视频大小。 在播放期间,应用程序应通知 VMR 以下 Windows 消息:

注意

MFC 应用程序必须定义空WM_ERASEBKGND消息处理程序,否则视频显示区域将无法正确重新绘制。

 

为无窗口模式配置 VMR-9

若要为无窗口模式配置 VMR-9,请使用针对无窗口模式的 VMR-7 所述的步骤,但使用 IVMRFilterConfig9IVMRWindowlessControl9 接口。 唯一的显著区别是 VMR-9 默认创建四个输入引脚,而不是一个输入引脚。 因此,只需在混合四个以上的视频流时调用 SetNumberOfStreams

示例代码

以下代码演示如何创建 VMR-7 筛选器,将其添加到 DirectShow 筛选器图,然后将 VMR 置于无窗口模式。 对于 VMR-9,请在 CoCreateInstance 中使用CLSID_VideoMixingRenderer9和相应的 VMR-9 接口。

HRESULT InitializeWindowlessVMR(
    HWND hwndApp,         // Application window.
    IFilterGraph* pFG,    // Pointer to the Filter Graph Manager.
    IVMRWindowlessControl** ppWc,  // Receives the interface.
    DWORD dwNumStreams,  // Number of streams to use.
    BOOL fBlendAppImage  // Are we alpha-blending a bitmap?
    )
{
    IBaseFilter* pVmr = NULL;
    IVMRWindowlessControl* pWc = NULL;
    *ppWc = NULL;

    // Create the VMR and add it to the filter graph.
    HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
       CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pFG->AddFilter(pVmr, L"Video Mixing Renderer");
    if (FAILED(hr))
    {
        pVmr->Release();
        return hr;
    }

    // Set the rendering mode and number of streams.  
    IVMRFilterConfig* pConfig;
    hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
    if (SUCCEEDED(hr)) 
    {
        pConfig->SetRenderingMode(VMRMode_Windowless);

        // Set the VMR-7 to mixing mode if you want more than one video
        // stream, or you want to mix a static bitmap over the video.
        // (The VMR-9 defaults to mixing mode with four inputs.)
        if (dwNumStreams > 1 || fBlendAppImage) 
        {
            pConfig->SetNumberOfStreams(dwNumStreams);
        }
        pConfig->Release();

        hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
        if (SUCCEEDED(hr)) 
        {
            pWc->SetVideoClippingWindow(hwndApp);
            *ppWc = pWc;  // The caller must release this interface.
        }
    }
    pVmr->Release();

    // Now the VMR can be connected to other filters.
    return hr;
}

使用无窗口模式