I'm using DirectShow.NET to create a web camera control for WPF. I've successfully created a graph and can get video from a camera to display on my screen. However, the video output is completely independent of the WPF control it's being created in.
I am setting the owner of the video window by calling videoWindow.put_owner(hWnd)
, where hWnd
is the window handle to the current WPF window. I get that window handle using the WindowInteropHelper
.
Here is the main routine:
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.");
}
}
And the code for 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);
}
Video renderers operating in windowed mode specifically (same applies to windowless) require that you provide a valid HWND
window handle so that video could be accurately integrated with standard UI. Your SetupVideoWindow
code snippet is doing exactly initialization of video "as a child control".
WPF is a sort of new UI concept which does not need to create a window handle for every UI control, and there is no clear and direct property to request handle in order to pass to VMR initialization. Hence, WindowInteropHelper
which you use correctly except that valid handle is available as soon as it is actually allocated, which is not the form constructor.
Using a zero handle instructs video renderer to send video to desktop window and behavior you are seeing is expected and understandable.
You need to check handle value with debugger, and if it's zero then move configuration code to some later stage of form construction. Non-zero valid window handle at setup time should put video in place.