使用窗口模式

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

注意

旧版 视频呈现器筛选器 始终使用窗口模式。 VMR-7 和 VMR-9 筛选器默认使用窗口模式,但也支持无窗口模式。

 

在窗口模式中,视频呈现器创建自己的窗口,在其中绘制视频帧。 除非另行指定,否则此窗口是具有其自己的边框和标题栏的顶级窗口。 但是,大多数情况下,你会将视频窗口附加到应用程序窗口,以便将视频集成到应用程序 UI 中。 这需要执行以下步骤:

  1. 查询 IVideoWindow
  2. 设置父窗口。
  3. 设置新窗口样式。
  4. 将视频窗口置于所有者窗口内。
  5. 通知视频窗口WM_MOVE消息。

查询 IVideoWindow

在开始播放之前,请查询 IVideoWindow 接口的 Filter Graph 管理器:

IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);

设置父窗口

若要设置父窗口,请使用应用程序窗口的句柄调用 IVideoWindow::p ut_Owner 方法。 此方法采用 OAHWND 类型的变量,因此将句柄强制转换为此类型:

pVidWin->put_Owner((OAHWND)hwnd);

设置新窗口样式

通过调用 IVideoWindow::p ut_WindowStyle 方法更改视频窗口的样式:

pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

WS_CHILD标志将窗口设置为子窗口,WS_CLIPSIBLINGS标志阻止窗口在另一个子窗口的工作区内绘制。

定位视频窗口

若要设置视频相对于应用程序窗口的工作区的位置,请调用 IVideoWindow::SetWindowPosition 方法。 此方法采用一个矩形,该矩形指定视频窗口的左边缘、上边缘、宽度和高度。 例如,以下代码拉伸视频窗口以适应父窗口的整个工作区:

RECT rc;
GetClientRect(hwnd, &rc);
pVidWin->SetWindowPosition(0, 0, rc.right, rc.bottom);

若要获取视频的本机大小,请在 Filter Graph 管理器上调用 IBasicVideo::GetVideoSize 方法。 可以使用该信息来缩放视频并保持正确的纵横比。

响应WM_MOVE消息

为了获得最佳性能,每当窗口在图表暂停时移动时,都应通知视频呈现器。 调用 IVideoWindow::NotifyOwnerMessage 方法以转发WM_MOVE消息:

// (Inside your WindowProc)
case WM_MOVE:
    pVidWin->NotifyOwnerMessage((OAHWND)hWnd, msg, wParam, lParam);
    break;

如果呈现器使用硬件覆盖,则此通知会导致呈现器更新覆盖位置。 (VMR-9 不使用覆盖,因此,如果使用 VMR-9.)

清理

在应用程序退出之前,请停止图形并将视频窗口的所有者重置为 NULL。 否则,窗口消息可能会发送到错误的窗口,这可能会导致错误。 此外,隐藏视频窗口,否则可能会在屏幕上看到视频图像暂时闪烁:

pControl->Stop(); 
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);  

注意

如果视频窗口的父级是 (main应用程序窗口的子窗口,换句话说,如果视频窗口是子) 的子窗口,则应使用 CoCreateInstance 创建视频窗口并将其添加到图形,而不是让筛选器关系图管理器在智能连接期间添加视频呈现器。 这可确保同时重新绘制视频窗口和子窗口。 否则,子窗口可能会在视频窗口上绘制。

 

视频渲染