private void SetupGraphInternal(DsDevice dev, SystemCodecEntry compressor, VideoFormatHelper.SupportedVideoFormat selectedFormat, ref float iFrameRate, ref int iWidth, ref int iHeight, string fileName)
        {
            filterGraph = (IFilterGraph2) new FilterGraph();
            mediaCtrl   = filterGraph as IMediaControl;

            capBuilder = (ICaptureGraphBuilder2) new CaptureGraphBuilder2();

            samplGrabber = (ISampleGrabber) new SampleGrabber();

            int hr = capBuilder.SetFiltergraph(filterGraph);

            DsError.ThrowExceptionForHR(hr);

            if (rot != null)
            {
                rot.Dispose();
                rot = null;
            }
            rot = new DsROTEntry(filterGraph);

            if (fileName != null)
            {
                deviceFilter = BuildFileCaptureGraph(dev, compressor.Device, selectedFormat, fileName, ref iFrameRate, ref iWidth, ref iHeight);
            }
            else
            {
                deviceFilter = BuildPreviewOnlyCaptureGraph(dev, selectedFormat, ref iFrameRate, ref iWidth, ref iHeight);
            }

            // Now that sizes are fixed/known, store the sizes
            SaveSizeInfo(samplGrabber);
        }
        private IBaseFilter BuildPreviewOnlyCaptureGraph(DsDevice dev, VideoFormatHelper.SupportedVideoFormat selectedFormat, ref float iFrameRate, ref int iWidth, ref int iHeight)
        {
            // Capture Source (Capture/Video) --> (Input) Sample Grabber (Output) --> (In) Null Renderer

            IBaseFilter nullRenderer = null;

            try
            {
                IBaseFilter capFilter;

                // Add the video device
                int hr = filterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
                DsError.ThrowExceptionForHR(hr);

                if (capFilter != null)
                {
                    SetConfigParms(capBuilder, capFilter, selectedFormat, ref iFrameRate, ref iWidth, ref iHeight);
                }

                IBaseFilter baseGrabFlt = (IBaseFilter)samplGrabber;
                ConfigureSampleGrabber(samplGrabber);

                hr = filterGraph.AddFilter(baseGrabFlt, "ASCOM Video Grabber");
                DsError.ThrowExceptionForHR(hr);

                // Connect the video device output to the sample grabber
                IPin videoCaptureOutputPin = FindPin(capFilter, PinDirection.Output, MediaType.Video, PinCategory.Capture, "Capture");
                IPin grabberInputPin       = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
                hr = filterGraph.Connect(videoCaptureOutputPin, grabberInputPin);
                DsError.ThrowExceptionForHR(hr);
                Marshal.ReleaseComObject(videoCaptureOutputPin);
                Marshal.ReleaseComObject(grabberInputPin);

                // Add the frame grabber to the graph
                nullRenderer = (IBaseFilter) new NullRenderer();
                hr           = filterGraph.AddFilter(nullRenderer, "ASCOM Video Null Renderer");
                DsError.ThrowExceptionForHR(hr);

                // Connect the sample grabber to the null renderer (so frame samples will be coming through)
                IPin grabberOutputPin = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
                IPin renderedInputPin = DsFindPin.ByDirection(nullRenderer, PinDirection.Input, 0);
                hr = filterGraph.Connect(grabberOutputPin, renderedInputPin);
                DsError.ThrowExceptionForHR(hr);
                Marshal.ReleaseComObject(grabberOutputPin);
                Marshal.ReleaseComObject(renderedInputPin);

                return(capFilter);
            }
            finally
            {
                if (nullRenderer != null)
                {
                    Marshal.ReleaseComObject(nullRenderer);
                }
            }
        }
        public void SetupPreviewOnlyGraph(DsDevice dev, VideoFormatHelper.SupportedVideoFormat selectedFormat, ref float iFrameRate, ref int iWidth, ref int iHeight)
        {
            try
            {
                SetupGraphInternal(dev, null, selectedFormat, ref iFrameRate, ref iWidth, ref iHeight, null);

                latestBitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
                fullRect     = new Rectangle(0, 0, latestBitmap.Width, latestBitmap.Height);
            }
            catch
            {
                CloseResources();
                throw;
            }
        }
        public void SetupFileRecorderGraph(DsDevice dev, SystemCodecEntry compressor, VideoFormatHelper.SupportedVideoFormat selectedFormat, ref float iFrameRate, ref int iWidth, ref int iHeight, string fileName)
        {
            try
            {
                SetupGraphInternal(dev, compressor, selectedFormat, ref iFrameRate, ref iWidth, ref iHeight, fileName);

                latestBitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb);
                fullRect     = new Rectangle(0, 0, latestBitmap.Width, latestBitmap.Height);
            }
            catch
            {
                CloseResources();
                throw;
            }
        }
        private void SetConfigParms(ICaptureGraphBuilder2 capBuilder, IBaseFilter capFilter, VideoFormatHelper.SupportedVideoFormat selectedFormat, ref float iFrameRate, ref int iWidth, ref int iHeight)
        {
            object          o;
            IAMStreamConfig videoStreamConfig;
            IAMVideoControl videoControl = capFilter as IAMVideoControl;

            int hr = capBuilder.FindInterface(PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out o);

            videoStreamConfig = o as IAMStreamConfig;
            try
            {
                if (videoStreamConfig == null)
                {
                    throw new Exception("Failed to get IAMStreamConfig");
                }

                int iCount = 0, iSize = 0;
                hr = videoStreamConfig.GetNumberOfCapabilities(out iCount, out iSize);
                DsError.ThrowExceptionForHR(hr);

                VideoInfoHeader vMatching = null;
                VideoFormatHelper.SupportedVideoFormat entry = null;

                IntPtr taskMemPointer     = Marshal.AllocCoTaskMem(iSize);

                AMMediaType pmtConfig = null;
                for (int iFormat = 0; iFormat < iCount; iFormat++)
                {
                    IntPtr ptr = IntPtr.Zero;

                    hr = videoStreamConfig.GetStreamCaps(iFormat, out pmtConfig, taskMemPointer);
                    DsError.ThrowExceptionForHR(hr);

                    vMatching = (VideoInfoHeader)Marshal.PtrToStructure(pmtConfig.formatPtr, typeof(VideoInfoHeader));

                    if (vMatching.BmiHeader.BitCount > 0)
                    {
                        entry = new VideoFormatHelper.SupportedVideoFormat()
                        {
                            Width     = vMatching.BmiHeader.Width,
                            Height    = vMatching.BmiHeader.Height,
                            BitCount  = vMatching.BmiHeader.BitCount,
                            FrameRate = 10000000.0 / vMatching.AvgTimePerFrame
                        };

                        if (entry.Matches(selectedFormat))
                        {
                            // WE FOUND IT !!!
                            break;
                        }
                    }

                    vMatching = null;
                }

                if (vMatching != null)
                {
                    hr = videoStreamConfig.SetFormat(pmtConfig);
                    DsError.ThrowExceptionForHR(hr);

                    iFrameRate = 10000000 / vMatching.AvgTimePerFrame;
                    iWidth     = vMatching.BmiHeader.Width;
                    iHeight    = vMatching.BmiHeader.Height;
                }
                else
                {
                    AMMediaType media;
                    hr = videoStreamConfig.GetFormat(out media);
                    DsError.ThrowExceptionForHR(hr);

                    // Copy out the videoinfoheader
                    VideoInfoHeader v = new VideoInfoHeader();
                    Marshal.PtrToStructure(media.formatPtr, v);

                    // If overriding the framerate, set the frame rate
                    if (iFrameRate > 0)
                    {
                        v.AvgTimePerFrame = (int)Math.Round(10000000 / iFrameRate);
                    }
                    else
                    {
                        iFrameRate = 10000000 / v.AvgTimePerFrame;
                    }

                    // If overriding the width, set the width
                    if (iWidth > 0)
                    {
                        v.BmiHeader.Width = iWidth;
                    }
                    else
                    {
                        iWidth = v.BmiHeader.Width;
                    }

                    // If overriding the Height, set the Height
                    if (iHeight > 0)
                    {
                        v.BmiHeader.Height = iHeight;
                    }
                    else
                    {
                        iHeight = v.BmiHeader.Height;
                    }

                    // Copy the media structure back
                    Marshal.StructureToPtr(v, media.formatPtr, false);

                    // Set the new format
                    hr = videoStreamConfig.SetFormat(media);
                    DsError.ThrowExceptionForHR(hr);

                    DsUtils.FreeAMMediaType(media);
                    media = null;
                }

                Marshal.FreeCoTaskMem(taskMemPointer);
                DsUtils.FreeAMMediaType(pmtConfig);
                pmtConfig = null;
            }
            finally
            {
                Marshal.ReleaseComObject(videoStreamConfig);
            }
        }
        private IBaseFilter BuildFileCaptureGraph(DsDevice dev, DsDevice compressor, VideoFormatHelper.SupportedVideoFormat selectedFormat, string fileName, ref float iFrameRate, ref int iWidth, ref int iHeight)
        {
            // Capture Source (Capture/Video) --> (Input) Sample Grabber (Output) --> (Input) Video Compressor (Output) --> (Input 01/Video/) AVI Mux (Output) --> (In) FileSink

            IBaseFilter     muxFilter        = null;
            IFileSinkFilter fileWriterFilter = null;
            IBaseFilter     compressorFilter = null;

            try
            {
                IBaseFilter capFilter;

                // Add the video device
                int hr = filterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
                DsError.ThrowExceptionForHR(hr);

                if (capFilter != null)
                {
                    SetConfigParms(capBuilder, capFilter, selectedFormat, ref iFrameRate, ref iWidth, ref iHeight);
                }

                IBaseFilter baseGrabFlt = (IBaseFilter)samplGrabber;
                ConfigureSampleGrabber(samplGrabber);

                hr = filterGraph.AddFilter(baseGrabFlt, "ASCOM Video Grabber");
                DsError.ThrowExceptionForHR(hr);

                // Connect the video device output to the sample grabber
                IPin videoCaptureOutputPin = FindPin(capFilter, PinDirection.Output, MediaType.Video, Guid.Empty, "Capture");
                IPin smartTeeInputPin      = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
                hr = filterGraph.Connect(videoCaptureOutputPin, smartTeeInputPin);
                DsError.ThrowExceptionForHR(hr);
                Marshal.ReleaseComObject(videoCaptureOutputPin);
                Marshal.ReleaseComObject(smartTeeInputPin);

                // Create the file writer and AVI Mux (already connected to each other)
                hr = capBuilder.SetOutputFileName(MediaSubType.Avi, fileName, out muxFilter, out fileWriterFilter);
                DsError.ThrowExceptionForHR(hr);

                if (compressor != null)
                {
                    // Create the compressor
                    compressorFilter = CreateFilter(FilterCategory.VideoCompressorCategory, compressor.Name);
                }

                if (compressorFilter != null)
                {
                    hr = filterGraph.AddFilter(compressorFilter, "ASCOM Video Compressor");
                    DsError.ThrowExceptionForHR(hr);

                    // Connect the sample grabber Output pin to the compressor
                    IPin grabberOutputPin   = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
                    IPin compressorInputPin = DsFindPin.ByDirection(compressorFilter, PinDirection.Input, 0);
                    hr = filterGraph.Connect(grabberOutputPin, compressorInputPin);
                    DsError.ThrowExceptionForHR(hr);
                    Marshal.ReleaseComObject(grabberOutputPin);
                    Marshal.ReleaseComObject(compressorInputPin);

                    // Connect the compressor output to the AVI Mux
                    IPin compressorOutputPin = DsFindPin.ByDirection(compressorFilter, PinDirection.Output, 0);
                    IPin aviMuxVideoInputPin = DsFindPin.ByDirection(muxFilter, PinDirection.Input, 0);
                    hr = filterGraph.Connect(compressorOutputPin, aviMuxVideoInputPin);
                    DsError.ThrowExceptionForHR(hr);
                    Marshal.ReleaseComObject(compressorOutputPin);
                    Marshal.ReleaseComObject(aviMuxVideoInputPin);
                }
                else
                {
                    // Connect the sample grabber Output pin to the AVI Mux
                    IPin grabberOutputPin    = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
                    IPin aviMuxVideoInputPin = DsFindPin.ByDirection(muxFilter, PinDirection.Input, 0);
                    hr = filterGraph.Connect(grabberOutputPin, aviMuxVideoInputPin);
                    DsError.ThrowExceptionForHR(hr);
                    Marshal.ReleaseComObject(grabberOutputPin);
                    Marshal.ReleaseComObject(aviMuxVideoInputPin);
                }

                return(capFilter);
            }
            finally
            {
                if (fileWriterFilter != null)
                {
                    Marshal.ReleaseComObject(fileWriterFilter);
                }

                if (muxFilter != null)
                {
                    Marshal.ReleaseComObject(muxFilter);
                }

                if (compressorFilter != null)
                {
                    Marshal.ReleaseComObject(compressorFilter);
                }
            }
        }