将 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 句柄应将视频放置到位。
我正在使用 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 句柄应将视频放置到位。