VMR 无窗口模式

[与此页面关联的功能(DirectShow)是一项旧功能。 它已被 MediaPlayerIMFMediaEngine取代,并在媒体基金会 音频/视频捕获。 这些功能已针对 Windows 10 和 Windows 11 进行了优化。 Microsoft强烈建议新代码尽可能使用 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获,而不是 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)或使用 Capture Graph Builder 的 ICaptureGraphBuilder2::RenderStream 方法生成图形,例如直接连接图钉。 有关详细信息,请参阅 常规 Graph-Building 技术

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

注意

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

 

为无窗口模式配置 VMR-9

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

示例代码

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

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;
}

使用无窗口模式