/// <summary> /// Disconnect and remove all filters except the device /// and compressor filters. This is the opposite of /// renderGraph(). Soem properties such as FrameRate /// can only be set when the device output pins are not /// connected. /// </summary> protected void DerenderGraph() { // Stop the graph if it is running (ignore errors) MediaControl?.Stop(); // Free the preview window (ignore errors) if (VideoWindow != null) { VideoWindow.put_Visible(CoreStreaming.DsHlp.OAFALSE); VideoWindow.put_Owner(IntPtr.Zero); VideoWindow = null; } // Remove the Resize event handler if (PreviewWindow != null) { PreviewWindow.SizeChanged -= OnPreviewWindowResize; } if ((int)ActualGraphState >= (int)GraphState.Rendered) { // Update the state ActualGraphState = GraphState.Created; IsPreviewRendered = false; // Disconnect all filters downstream of the // video and audio devices. If we have a compressor // then disconnect it, but don't remove it if (VideoDeviceFilter != null) { RemoveDownstream(VideoDeviceFilter, VideoCompressor == null); } } }
/// <summary> /// Completely tear down a filter graph and /// release all associated resources. /// </summary> protected void DestroyGraph() { // Derender the graph (This will stop the graph // and release preview window. It also destroys // half of the graph which is unnecessary but // harmless here.) (ignore errors) try { DerenderGraph(); } catch { } // Update the state after derender because it // depends on correct status. But we also want to // update the state as early as possible in case // of error. ActualGraphState = GraphState.Null; IsPreviewRendered = false; // Remove filters from the graph // This should be unnecessary but the Nvidia WDM // video driver cannot be used by this application // again unless we remove it. Ideally, we should // simply enumerate all the filters in the graph // and remove them. (ignore errors) if (VideoCompressorFilter != null) { GraphBuilder.RemoveFilter(VideoCompressorFilter); } if (VideoDeviceFilter != null) { GraphBuilder.RemoveFilter(VideoDeviceFilter); } // Cleanup if (GraphBuilder != null) { Marshal.ReleaseComObject(GraphBuilder); } GraphBuilder = null; if (CaptureGraphBuilder != null) { Marshal.ReleaseComObject(CaptureGraphBuilder); } CaptureGraphBuilder = null; if (VideoDeviceFilter != null) { Marshal.ReleaseComObject(VideoDeviceFilter); } VideoDeviceFilter = null; if (VideoCompressorFilter != null) { Marshal.ReleaseComObject(VideoCompressorFilter); } VideoCompressorFilter = null; // These are copies of graphBuilder MediaControl = null; VideoWindow = null; // For unmanaged objects we haven't released explicitly GC.Collect(); }
/// <summary> /// Connects the filters of a previously created graph /// (created by CreateGraph()). Once rendered the graph /// is ready to be used. This method may also destroy /// streams if we have streams we no longer want. /// </summary> protected void RenderGraph() { var didSomething = false; const int WS_CHILD = 0x40000000; const int WS_CLIPCHILDREN = 0x02000000; const int WS_CLIPSIBLINGS = 0x04000000; // Stop the graph MediaControl?.Stop(); // Create the graph if needed (group should already be created) CreateGraph(); // Derender the graph if we have a capture or preview stream // that we no longer want. We can't derender the capture and // preview streams seperately. // Notice the second case will leave a capture stream intact // even if we no longer want it. This allows the user that is // not using the preview to Stop() and Start() without // rerendering the graph. if (!WantPreviewRendered && IsPreviewRendered) { DerenderGraph(); } // Render preview stream (only if necessary) if (WantPreviewRendered && !IsPreviewRendered) { // Render preview (video -> renderer) var cat = Uuid.PinCategory.Preview; var med = Uuid.MediaType.Video; var hr = CaptureGraphBuilder.RenderStream(ref cat, ref med, VideoDeviceFilter, _baseGrabFlt, null); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // Get the IVideoWindow interface VideoWindow = (ControlStreaming.IVideoWindow)GraphBuilder; // Set the video window to be a child of the main window var source = PresentationSource.FromVisual(PreviewWindow) as HwndSource; hr = VideoWindow.put_Owner(source.Handle); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // Set video window style hr = VideoWindow.put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // Position video window in client rect of owner window PreviewWindow.SizeChanged += OnPreviewWindowResize; OnPreviewWindowResize(this, null); // Make the video window visible, now that it is properly positioned hr = VideoWindow.put_Visible(CoreStreaming.DsHlp.OATRUE); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } IsPreviewRendered = true; didSomething = true; var media = new CoreStreaming.AMMediaType(); hr = SampGrabber.GetConnectedMediaType(media); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } if ((media.formatType != Uuid.FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero)) { throw new NotSupportedException("Unknown Grabber Media Format"); } _videoInfoHeader = (EditStreaming.VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(EditStreaming.VideoInfoHeader)); Marshal.FreeCoTaskMem(media.formatPtr); media.formatPtr = IntPtr.Zero; } if (didSomething) { ActualGraphState = GraphState.Rendered; } }
/// <summary> /// Completely tear down a filter graph and /// release all associated resources. /// </summary> protected void DestroyGraph() { // Derender the graph (This will stop the graph // and release preview window. It also destroys // half of the graph which is unnecessary but // harmless here.) (ignore errors) try { DerenderGraph(); } catch { } // Update the state after derender because it // depends on correct status. But we also want to // update the state as early as possible in case // of error. ActualGraphState = GraphState.Null; IsPreviewRendered = false; // Remove filters from the graph // This should be unnecessary but the Nvidia WDM // video driver cannot be used by this application // again unless we remove it. Ideally, we should // simply enumerate all the filters in the graph // and remove them. (ignore errors) if (VideoCompressorFilter != null) GraphBuilder.RemoveFilter(VideoCompressorFilter); if (VideoDeviceFilter != null) GraphBuilder.RemoveFilter(VideoDeviceFilter); // Cleanup if (GraphBuilder != null) Marshal.ReleaseComObject(GraphBuilder); GraphBuilder = null; if (CaptureGraphBuilder != null) Marshal.ReleaseComObject(CaptureGraphBuilder); CaptureGraphBuilder = null; if (VideoDeviceFilter != null) Marshal.ReleaseComObject(VideoDeviceFilter); VideoDeviceFilter = null; if (VideoCompressorFilter != null) Marshal.ReleaseComObject(VideoCompressorFilter); VideoCompressorFilter = null; // These are copies of graphBuilder MediaControl = null; VideoWindow = null; // For unmanaged objects we haven't released explicitly GC.Collect(); }
/// <summary> /// Connects the filters of a previously created graph /// (created by CreateGraph()). Once rendered the graph /// is ready to be used. This method may also destroy /// streams if we have streams we no longer want. /// </summary> protected void RenderGraph() { Guid cat; Guid med; int hr; bool didSomething = false; const int WS_CHILD = 0x40000000; const int WS_CLIPCHILDREN = 0x02000000; const int WS_CLIPSIBLINGS = 0x04000000; // Stop the graph if (MediaControl != null) MediaControl.Stop(); // Create the graph if needed (group should already be created) CreateGraph(); // Derender the graph if we have a capture or preview stream // that we no longer want. We can't derender the capture and // preview streams seperately. // Notice the second case will leave a capture stream intact // even if we no longer want it. This allows the user that is // not using the preview to Stop() and Start() without // rerendering the graph. if (!WantPreviewRendered && IsPreviewRendered) DerenderGraph(); // Render preview stream (only if necessary) if (WantPreviewRendered && !IsPreviewRendered) { // Render preview (video -> renderer) cat = Uuid.PinCategory.Preview; med = Uuid.MediaType.Video; hr = CaptureGraphBuilder.RenderStream(ref cat, ref med, VideoDeviceFilter, _baseGrabFlt, null); if (hr < 0) Marshal.ThrowExceptionForHR(hr); // Get the IVideoWindow interface VideoWindow = (ControlStreaming.IVideoWindow)GraphBuilder; // Set the video window to be a child of the main window var source = PresentationSource.FromVisual(PreviewWindow) as HwndSource; hr = VideoWindow.put_Owner(source.Handle); if (hr < 0) Marshal.ThrowExceptionForHR(hr); // Set video window style hr = VideoWindow.put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); if (hr < 0) Marshal.ThrowExceptionForHR(hr); // Position video window in client rect of owner window PreviewWindow.SizeChanged += OnPreviewWindowResize; OnPreviewWindowResize(this, null); // Make the video window visible, now that it is properly positioned hr = VideoWindow.put_Visible(CoreStreaming.DsHlp.OATRUE); if (hr < 0) Marshal.ThrowExceptionForHR(hr); IsPreviewRendered = true; didSomething = true; var media = new CoreStreaming.AMMediaType(); hr = SampGrabber.GetConnectedMediaType(media); if (hr < 0) Marshal.ThrowExceptionForHR(hr); if ((media.formatType != Uuid.FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero)) throw new NotSupportedException("Unknown Grabber Media Format"); _videoInfoHeader = (EditStreaming.VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(EditStreaming.VideoInfoHeader)); Marshal.FreeCoTaskMem(media.formatPtr); media.formatPtr = IntPtr.Zero; } if (didSomething) ActualGraphState = GraphState.Rendered; }
/// <summary> /// Disconnect and remove all filters except the device /// and compressor filters. This is the opposite of /// renderGraph(). Soem properties such as FrameRate /// can only be set when the device output pins are not /// connected. /// </summary> protected void DerenderGraph() { // Stop the graph if it is running (ignore errors) if (MediaControl != null) MediaControl.Stop(); // Free the preview window (ignore errors) if (VideoWindow != null) { VideoWindow.put_Visible(CoreStreaming.DsHlp.OAFALSE); VideoWindow.put_Owner(IntPtr.Zero); VideoWindow = null; } // Remove the Resize event handler if (PreviewWindow != null) PreviewWindow.SizeChanged -= new SizeChangedEventHandler(OnPreviewWindowResize); if ((int)ActualGraphState >= (int)GraphState.Rendered) { // Update the state ActualGraphState = GraphState.Created; IsPreviewRendered = false; // Disconnect all filters downstream of the // video and audio devices. If we have a compressor // then disconnect it, but don't remove it if (VideoDeviceFilter != null) RemoveDownstream(VideoDeviceFilter, (VideoCompressor == null)); } }