将 DirectShow 视频 window 附加到 WPF 控件

Attach DirectShow video window to WPF Control

我正在使用 DirectShow.NET 为 WPF 创建网络摄像头控件。我已经成功地创建了一个图表,并且可以从摄像头获取视频以显示在我的屏幕上。但是,视频输出完全独立于创建它的 WPF 控件。

我正在通过调用 videoWindow.put_owner(hWnd) 设置视频 window 的所有者,其中 hWnd 是当前 WPF window 的 window 句柄。我使用 WindowInteropHelper 得到 window 句柄。

这里是主要例程:

public void CaptureVideo()
        {
            int hr = 0;
            IBaseFilter sourceFilter = null;

            try
            {
                hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
                DsError.ThrowExceptionForHR(hr);

                sourceFilter = FindCaptureDevice();

                hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
                DsError.ThrowExceptionForHR(hr);

                hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null);
                DsError.ThrowExceptionForHR(hr);

                Marshal.ReleaseComObject(sourceFilter);

                SetupVideoWindow();

                hr = this.mediaControl.Run();
                DsError.ThrowExceptionForHR(hr);
            }
            catch
            {
                Console.WriteLine("An unrecoverable DirectShow error has occurred.");
            }
        }

以及 SetupVideoWindow() 的代码:

public void SetupVideoWindow()
        {
            int hr = 0;

            Window window = Window.GetWindow(this);
            var wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;

            hr = this.videoWindow.put_Owner(hWnd);
            DsError.ThrowExceptionForHR(hr);

            hr = this.videoWindow.put_WindowStyle(DirectShowLib.WindowStyle.Child | DirectShowLib.WindowStyle.ClipChildren);
            DsError.ThrowExceptionForHR(hr);

            this.videoWindow.SetWindowPosition(0, 0, (int)this.Width, (int)this.Height);

            hr = this.videoWindow.put_Visible(OABool.True);
            DsError.ThrowExceptionForHR(hr);
        }

这是正在发生的事情的图像:

据我所知,DirectShow 使用直接视频内存访问在屏幕上呈现内容以获得最佳性能,因此很可能 this.videoWindow.SetWindowPosition(0, 0, (int)this.Width, (int)this.Height); 需要在屏幕坐标中。

即您需要获取宿主 WPF window 在屏幕上的位置及其大小(使用 WinApi),然后传递给 SetWindowPosition 方法。每次 window moves/resizes.

时都这样做

很抱歉回答不完整(没有提供确切的代码来解决问题),因为我多年前在 C++ 中用 WinApi 做过。

专门在 windowed 模式下运行的视频渲染器(同样适用于 windowless)要求您提供有效的 HWND window 句柄,以便视频可以与标准准确集成 UI。您的 SetupVideoWindow 代码片段正在对视频 "as a child control" 进行精确初始化。

WPF是一种新的UI概念,不需要为每个UI控件创建一个window句柄,也没有明确直接的属性 请求句柄以传递给 VMR 初始化。因此,WindowInteropHelper 您正确使用了它,除了有效句柄在实际分配后立即可用,这不是表单构造函数。

使用零句柄指示视频渲染器将视频发送到桌面 window 并且您看到的行为是预期且可以理解的。

您需要使用调试器检查句柄值,如果它为零,则将配置代码移至表单构造的后期阶段。设置时的非零有效 window 句柄应将视频放置到位。