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