Alan Thomas
Alan Thomas

Reputation: 1034

Attach DirectShow video window to WPF Control

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);
        }

Here is an image of what is happening: DirectShow.NET Video Window and WPF MainWindow Control

Upvotes: 3

Views: 3365

Answers (2)

Roman Ryltsov
Roman Ryltsov

Reputation: 69724

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.

Upvotes: 2

Serge Semenov
Serge Semenov

Reputation: 10052

As far as I remember, the DirectShow uses direct video memory access to present a content on a screen for the best performance, so most likely the this.videoWindow.SetWindowPosition(0, 0, (int)this.Width, (int)this.Height); needs to be in screen coordinates.

I.e. you need to get position of the hosting WPF window on the screen and it's size (using WinApi), and pass to the SetWindowPosition method. And do that every single time when your window moves/resizes.

Sorry for incomplete answer (no exact code is provided to solve the problem), because I've done that many years ago in C++ with WinApi.

Upvotes: 0

Related Questions