context: /****************************************************************************
  While the underlying libraries are covered by LGPL, this sample is released 
  as public domain.  It is distributed in the hope that it will be useful, but 
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  or FITNESS FOR A PARTICULAR PURPOSE.  
  *****************************************************************************/
  
  using System;
  using System.Drawing;
  using System.Runtime.InteropServices;
  using System.Threading;
  using System.Diagnostics;
  using System.Windows.Forms;
  
  using DirectShowLib;
  
  
  namespace CmsCheckin
  {
      /// <summary> Summary description for MainForm. </summary>
      internal class Capture : ISampleGrabberCB, IDisposable
      {
          #region Member variables
  
          /// <summary> graph builder interface. </summary>
          private IFilterGraph2 m_FilterGraph = null;
  
          // Used to snap picture on Still pin
          private IAMVideoControl m_VidControl = null;
          private IPin m_pinStill = null;
  
          /// <summary> so we can wait for the async job to finish </summary>
          private ManualResetEvent m_PictureReady = null;
  
          private bool m_WantOne = false;
  
          /// <summary> Dimensions of the image, calculated once in constructor for perf. </summary>
          private int m_videoWidth;
          private int m_videoHeight;
          private int m_stride;
  
          /// <summary> buffer for bitmap data.  Always release by caller</summary>
          private IntPtr m_ipBuffer = IntPtr.Zero;
  
  #if DEBUG
          // Allow you to "Connect to remote graph" from GraphEdit
          DsROTEntry m_rot = null;
  #endif
          #endregion
  
          #region APIs
          [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
          private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);
          #endregion
  
          // Zero based device index and device params and output window
          public Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, Control hControl)
          {
              DsDevice[] capDevices;
  
              // Get the collection of video devices
              capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
  
              if (iDeviceNum + 1 > capDevices.Length)
              {
                  throw new Exception("No video capture devices found at that index!");
              }
  
              try
              {
                  DsDevice dev = capDevices[iDeviceNum];
                  // Set up the capture graph
                  SetupGraph(dev, iWidth, iHeight, iBPP, hControl);
                  //SetupProperties(dev, 12, 12,0);
  
                  // tell the callback to ignore new images
                  m_PictureReady = new ManualResetEvent(false);
              }
              catch
              {
                  Dispose();
                  throw;
              }
          }
  
          public void SetupProperties(int iDeviceNum, int brightness, int contrast, int backlightcompensation, int sharpness)
          {
              DsDevice[] capDevices;
              // Get the collection of video devices
              capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
              DsDevice dev = capDevices[iDeviceNum];
              // Set up the capture graph
              SetupProperties(dev, brightness, contrast, backlightcompensation, sharpness);
          }
  
          public void SetupProperties(DsDevice dev, int brightness, int contrast, int backlightcompensation, int sharpness)
          {
              object o;
              Guid IID_IBaseFilter = new Guid("56a86895-0ad4-11ce-b03a-0020af0ba770");
              dev.Mon.BindToObject(null, null, ref IID_IBaseFilter, out o);
              IAMVideoProcAmp vpa = (IAMVideoProcAmp)o;
  
              int pMin, pMax, pSteppingDelta, pDefault;
              int pMin2, pMax2, pSteppingDelta2, pDefault2;
              int pMin3, pMax3, pSteppingDelta3, pDefault3;
              int pMin4, pMax4, pSteppingDelta4, pDefault4;
              //int pMin5, pMax5, pSteppingDelta5, pDefault5;
              VideoProcAmpFlags pFlags, pFlags2, pFlags3, pFlags4;//, pFlags5;
  
              vpa.GetRange(
              VideoProcAmpProperty.Brightness,
              out pMin,
              out pMax,
              out pSteppingDelta,
              out pDefault,
              out pFlags);
  
              vpa.GetRange(
              VideoProcAmpProperty.Sharpness,
              out pMin2,
              out pMax2,
              out pSteppingDelta2,
              out pDefault2,
              out pFlags2);
  
              vpa.GetRange(
              VideoProcAmpProperty.BacklightCompensation,
              out pMin3,
              out pMax3,
              out pSteppingDelta3,
              out pDefault3,
              out pFlags3);
  
  
  
              vpa.GetRange(
              VideoProcAmpProperty.Contrast,
              out pMin4,
              out pMax4,
              out pSteppingDelta4,
              out pDefault4,
              out pFlags4);
  
              //vpa.GetRange(
              //VideoProcAmpProperty.ColorEnable,
              //out pMin5,
              //out pMax5,
              //out pSteppingDelta5,
              //out pDefault5,
              //out pFlags5);
  
              //Here I will change the settings of the camera!
  
              if (brightness >= pMin && brightness <= pMax)
              {
                  vpa.Set(VideoProcAmpProperty.Brightness, brightness, pFlags);
              }
              if (sharpness >= pMin2 && sharpness <= pMax2)
              {
                  vpa.Set(VideoProcAmpProperty.Sharpness, sharpness, pFlags2);
              }
              if (backlightcompensation >= pMin3 && backlightcompensation <= pMax3)
              {
                  vpa.Set(VideoProcAmpProperty.BacklightCompensation, backlightcompensation, pFlags3);
              }
              if (contrast >= pMin4 && contrast <= pMax)
              {
                  vpa.Set(VideoProcAmpProperty.Contrast, contrast, pFlags4);
              }
          }
  
          /// <summary> release everything. </summary>
          public void Dispose()
          {
  #if DEBUG
              if (m_rot != null)
              {
                  m_rot.Dispose();
              }
  #endif
              CloseInterfaces();
              if (m_PictureReady != null)
              {
                  m_PictureReady.Close();
              }
          }
          // Destructor
          ~Capture()
          {
              Dispose();
          }
  
          /// <summary>
          /// Get the image from the Still pin.  The returned image can turned into a bitmap with
          /// Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
          /// If the image is upside down, you can fix it with
          /// b.RotateFlip(RotateFlipType.RotateNoneFlipY);
          /// </summary>
          /// <returns>Returned pointer to be freed by caller with Marshal.FreeCoTaskMem</returns>
          public IntPtr Click()
          {
              int hr;
  
              // get ready to wait for new image
              m_PictureReady.Reset();
              m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);
  
              try
              {
                  m_WantOne = true;
  
                  // If we are using a still pin, ask for a picture
                  if (m_VidControl != null)
                  {
                      // Tell the camera to send an image
                      hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
                      DsError.ThrowExceptionForHR(hr);
                  }
  
                  // Start waiting
                  if (!m_PictureReady.WaitOne(9000, false))
                  {
                      return IntPtr.Zero;
                  }
              }
              catch(Exception)
              {
                  Marshal.FreeCoTaskMem(m_ipBuffer);
                  m_ipBuffer = IntPtr.Zero;
              }
  
              // Got one
              return m_ipBuffer;
          }
  
          public int Width
          {
              get
              {
                  return m_videoWidth;
              }
          }
          public int Height
          {
              get
              {
                  return m_videoHeight;
              }
          }
          public int Stride
          {
              get
              {
                  return m_stride;
              }
          }
  
  
          /// <summary> build the capture graph for grabber. </summary>
          private void SetupGraph(DsDevice dev, int iWidth, int iHeight, short iBPP, Control hControl)
          {
              int hr;
  
              ISampleGrabber sampGrabber = null;
              IBaseFilter capFilter = null;
              IPin pCaptureOut = null;
              IPin pSampleIn = null;
              IPin pRenderIn = null;
              IAMVideoProcAmp vpa = null;
  
              // Get the graphbuilder object
              m_FilterGraph = new FilterGraph() as IFilterGraph2;
  
              try
              {
  #if DEBUG
                  m_rot = new DsROTEntry(m_FilterGraph);
  #endif
                  // add the video input device
                  hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
                  DsError.ThrowExceptionForHR(hr);
  
                  // Find the still pin
                  m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);
  
                  // Didn't find one.  Is there a preview pin?
                  if (m_pinStill == null)
                  {
                      m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Preview, 0);
                  }
  
                  //test
                  ISpecifyPropertyPages pProp = capFilter as ISpecifyPropertyPages;
  
                  DsCAUUID caGUID;
                  hr = pProp.GetPages(out caGUID);
                  DsError.ThrowExceptionForHR(hr);
  
                  // Still haven't found one.  Need to put a splitter in so we have
                  // one stream to capture the bitmap from, and one to display.  Ok, we
                  // don't *have* to do it that way, but we are going to anyway.
                  if (m_pinStill == null)
                  {
                      IPin pRaw = null;
                      IPin pSmart = null;
  
                      // There is no still pin
                      m_VidControl = null;
  
                      // Add a splitter
                      IBaseFilter iSmartTee = (IBaseFilter)new SmartTee();
  
                      try
                      {
                          hr = m_FilterGraph.AddFilter(iSmartTee, "SmartTee");
                          DsError.ThrowExceptionForHR(hr);
  
                          // Find the find the capture pin from the video device and the
                          // input pin for the splitter, and connnect them
                          pRaw = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
                          pSmart = DsFindPin.ByDirection(iSmartTee, PinDirection.Input, 0);
  
                          hr = m_FilterGraph.Connect(pRaw, pSmart);
                          DsError.ThrowExceptionForHR(hr);
  
                          // Now set the capture and still pins (from the splitter)
                          m_pinStill = DsFindPin.ByName(iSmartTee, "Preview");
                          pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture");
  
                          // If any of the default config items are set, perform the config
                          // on the actual video device (rather than the splitter)
                          if (iHeight + iWidth + iBPP > 0)
                          {
                              SetConfigParms(pRaw, iWidth, iHeight, iBPP);
                          }
                      }
                      finally
                      {
                          if (pRaw != null)
                          {
                              Marshal.ReleaseComObject(pRaw);
                          }
                          if (pRaw != pSmart)
                          {
                              Marshal.ReleaseComObject(pSmart);
                          }
                          if (pRaw != iSmartTee)
                          {
                              Marshal.ReleaseComObject(iSmartTee);
                          }
                      }
                  }
                  else
                  {
                      // Get a control pointer (used in Click())
                      m_VidControl = capFilter as IAMVideoControl;
  
                      pCaptureOut = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
  
                      // If any of the default config items are set
                      if (iHeight + iWidth + iBPP > 0)
                      {
                          SetConfigParms(m_pinStill, iWidth, iHeight, iBPP);
                      }
                  }
  
                  // Get the SampleGrabber interface
                  sampGrabber = new SampleGrabber() as ISampleGrabber;
  
                  // Configure the sample grabber
                  IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;
                  ConfigureSampleGrabber(sampGrabber);
                  pSampleIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
  
                  // Get the default video renderer
                  IBaseFilter pRenderer = new VideoRendererDefault() as IBaseFilter;
                  hr = m_FilterGraph.AddFilter(pRenderer, "Renderer");
                  DsError.ThrowExceptionForHR(hr);
  
                  pRenderIn = DsFindPin.ByDirection(pRenderer, PinDirection.Input, 0);
  
                  // Add the sample grabber to the graph
                  hr = m_FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
                  DsError.ThrowExceptionForHR(hr);
  
                  if (m_VidControl == null)
                  {
                      // Connect the Still pin to the sample grabber
  
gt:                     hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);