2

I'm creating a webcam control using DirectShow.NET. I want to render the video of the camera into a WPF window. What is happening currently is that the IVMRWindowlessControl9 doesn't seem to be going into windowless mode and is not being parented to the window that I'm specifying, even though I'm calling the appropriate methods.

Why are these methods not being invoked? Is there something else that I'm not doing?

Below is a snippet of the relevant code:

IGraphBuilder graphBuilder = (IGraphBuilder) new FilterGraph();
ICaptureGraphBuilder2 captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();            
IMediaControl mediaControl = (IMediaControl) this.graphBuilder;
IBaseFilter renderFilter = (IBaseFilter) new VideoMixingRenderer9();

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

IBaseFilter sourceFilter = FindCaptureDevice();

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

SetCaptureResolution();

IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)renderFilter;

hr = filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);

hr = filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);

windowlessControl = (IVMRWindowlessControl9)renderFilter;

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

Window window = Window.GetWindow(this);
var wih = new WindowInteropHelper(window);
IntPtr hWnd = wih.Handle;
hr = windowlessControl.SetVideoClippingWindow(hWnd);
DsError.ThrowExceptionForHR(hr);

hr = windowlessControl.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
DsError.ThrowExceptionForHR(hr);

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

Marshal.ReleaseComObject(sourceFilter);

hr = this.mediaControl.Run();
DsError.ThrowExceptionForHR(hr);

Here is an image of what is happening (I made the background green to make it easier to see): WPF & IVMRWindowlessControl9

This is a diagram of the filter graph: enter image description here

To answer a potential question (because I've had this issue previously), yes, hWnd is getting set/has a value - so the windowlessControl does have a pointer to the window.

Alan Thomas
  • 1,006
  • 2
  • 14
  • 31
  • `SetNumberOfStreams` might be too early, `SetRenderingMode` should [go first](https://msdn.microsoft.com/en-us/library/windows/desktop/dd407299). ActiveMovie Window is an indication that video renderer is not set up. Your effective filter graph might be not the one you expect to have. See [Understanding Your DirectShow Filter Graph](http://alax.info/blog/1678). Specifically, your effective graph might have two renderers. – Roman R. Sep 23 '16 at 19:57
  • @RomanR. http://imgur.com/a/wjjm5 - Here is a link to the filter graph image I captured during runtime of the application. Does this seem normal? – Alan Thomas Sep 23 '16 at 21:14

1 Answers1

1

A popup "ActiveMovie Window" created when you run a filter graph is a symptom of video renderer filter inserted into pipeline and running in default mode, without being configured to be a part of other UI: embedded as a child window etc.

Your reversing your graph sheds light on what is going on:

You insert and set up one video renderer filter, then there is another one added by the API and connected to your input. While embedded into your UI is the first one, it remains idle and the other one renders video into popup.

The code line which gives the problem is:

hr = this.captureGraphBuilder.RenderStream(PinCategory.Capture,
    MediaType.Video, sourceFilter, null, null);

The problem is quite typical for those who build graphs by inserting a video renderer and expecting them to be picked up and connected, especially that it sometimes works and such code snippets might be found online.

MSDN says:

If the pSink parameter is NULL, the method tries to use a default renderer. For video it uses the Video Renderer, and for audio it uses the DirectSound Renderer.

The call added another instance and you expected your existing one to be connected. While RenderStream is a powerful call and does filter magic to get things connected, it is easy to end up having it done something in wrong way.

If you already have your video renderer, you could use it as a sink argument in this call. Or, you could avoid doing RenderStream and incrementally add filters you need to make sure everything is built following your expectations. Or, another option is IFilterGraph2::RenderEx call instead with AM_RENDEREX_RENDERTOEXISTINGRENDERERS flag:

...the method attempts to use renderers already in the filter graph. It will not add new renderers to the graph. (It will add intermediate transform filters, if needed.) For the method to succeed, the graph must contain the appropriate renderers, and they must have unconnected input pins.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • I used the render filter as the sink parameter. It seems to have created the intended graph, however, I don't get video displaying in the window. There is no `ActiveMovie Window` anymore, but the webcam video is not appearing in the window. This is how I added the render filter: `hr = this.captureGraphBuilder.RenderStream(PinCategory.Capture, MediaType.Video, sourceFilter, null, renderFilter);` This is an image of what the window looks like: http://imgur.com/a/ljMPS. This is an image of the new capture graph: http://imgur.com/a/FiLOU. – Alan Thomas Sep 26 '16 at 16:30
  • 1
    Do you position the renderer using [`IVMRWindowlessControl9::SetVideoPosition`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd390550)? I don't see this in code above. Also, you can update your question (esp. to insert images) – Roman R. Sep 26 '16 at 16:59
  • Excellent. For some reason, I didn't think SetVideoPosition() was needed for `IVMRWindowlessControl9`. But that did the trick. So in the end, it was a combination of my filter graph being set up incorrectly, and needing to set the video position. – Alan Thomas Sep 26 '16 at 17:37