将DirectShow视频窗口附加到WPF控件

3
我正在使用DirectShow.NET为WPF创建一个Web摄像头控件。我成功地创建了一个图形,并且可以从摄像头获取视频并在屏幕上显示。然而,视频输出与创建它的WPF控件完全独立。
我通过调用videoWindow.put_owner(hWnd)来设置视频窗口的所有者,其中hWnd是当前WPF窗口的窗口句柄。我使用WindowInteropHelper获取该窗口句柄。
以下是主要程序:
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.NET视频窗口和WPF MainWindow控件

最后一个RenderStream调用参数没有意义。同时,你的hWnd可能为零/空,这可以解释这种行为。 - Roman R.
@RomanR。啊,是的,我只是在尝试一些东西,似乎我复制了错误的代码。我编辑了它以反映我正在使用的实际代码来产生上述结果。因为我正在使用WPF,hWnd是否为零/ null是可能的吗?这似乎是我在网上找到的唯一其他答案。 - Alan Thomas
那么,你能调试并确保 hWnd 是非零的吗?对于零,行为是相当预期的(尽管不是你想要的)。也许你在句柄甚至不存在(已分配)之前就设置它了。 - Roman R.
@RomanR。你说得完全正确。句柄还不存在 - 我在窗口的构造函数中进行调用。将逻辑移动到窗口加载后使其完美运行。谢谢!如果您想使用该信息创建答案,我会将其标记为已接受。 - Alan Thomas
2个回答

2

在窗口模式下,视频渲染器(无论是窗口模式还是无窗口模式)需要您提供有效的 HWND 窗口句柄,以便将视频准确地集成到标准 UI 中。您的 SetupVideoWindow 代码片段正好是将视频“作为子控件”进行初始化。

WPF 是一种新的 UI 概念,不需要为每个 UI 控件创建窗口句柄,并且没有清晰和直接的属性来请求句柄以便传递给 VMR 初始化。因此,您正确使用了 WindowInteropHelper,但是只有在实际分配句柄后才会有有效句柄可用,而这并不是表单构造函数。

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

您需要使用调试器检查句柄值,如果为零,则将配置代码移动到表单构造的某个较晚阶段。设置时具有非零有效窗口句柄应该能够使视频显示在正确位置。


0
据我所记,DirectShow使用直接视频内存访问来呈现屏幕上的内容以获得最佳性能,因此最可能需要在屏幕坐标中设置this.videoWindow.SetWindowPosition(0, 0, (int)this.Width, (int)this.Height);
也就是说,您需要获取托管WPF窗口在屏幕上的位置和大小(使用WinApi),并将其传递给SetWindowPosition方法。每当窗口移动/调整大小时都要这样做。
很抱歉没有提供确切的代码来解决问题,因为我多年前用WinApi在C++中完成了这个任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接