2015-09-13 4 views
-1

Я реализовал этот ниже код. В основном я пытаюсь захватить привязку с камеры. Код хорошо работает для встроенного кулачка, но при подключении внешнего кулачка проблема начинается. Требуется только первая привязка, и вторая привязка никогда не наступает.Утечка памяти в ISampleGrabber

Код можно посмотреть на

public class ImageEventArgs : EventArgs 
{ 
    public Image CapturedImage { get; set; } 
} 

public class Camera 
{ 
    internal DsDevice Device { get; set; } 
    internal bool IsRunning { get; set; } 
    public string Name { get; set; } 
    public int Delay { get; set; } 
} 

public class DsCameraHelper : ISampleGrabberCB, IDisposable 
{ 

    public void Connect(Camera device) 
    { 
     if (runningCamera == null) 
      runningCamera = device; 
     if (runningCamera.Name != device.Name) 
     { 
      runningCamera.IsRunning = false; 
      runningCamera = device; 
     } 

     if (runningCamera == null) return; 
     if (runningCamera.IsRunning) 
      capFilter.Run(10); 
     else 
      PrepareCam(); 
     captured = false; 
     runningCamera.IsRunning = true; 

     int hr; 
     if (sampGrabber == null) 
      return; 

     if (savedArray == null) 
     { 
      int size = videoInfoHeader.BmiHeader.ImageSize; 
      if ((size < 1000) || (size > 16000000)) 
       return; 
      savedArray = new byte[size + 64000]; 
     } 

     hr = sampGrabber.SetCallback(this, 1); 
    } 

    public void Disconnect(Camera device) 
    { 
     int hr; 
     if (sampGrabber == null) 
      return; 
     hr = sampGrabber.SetCallback(null, 0); 
    } 

    public Bitmap TakeShot() 
    { 
     return LatestBitmapFrame; 
    } 

    private object _latestFrameLock = new object(); 
    private Bitmap _latestFrame = null; 
    public Bitmap LatestBitmapFrame 
    { 
     get 
     { 
      lock (_latestFrameLock) 
      { 
       return _latestFrame; 
      } 
     } 
     set 
     { 
      lock (_latestFrameLock) 
      { 
       _latestFrame = value; 
       if (value == null) 
       { 
        return; 
       } 
      } 
     } 
    } 

    #region private members 

    private Panel videoPanel; 

    /// <summary> flag to detect first Form appearance </summary> 
    private bool firstActive; 

    /// <summary> base filter of the actually used video devices. </summary> 
    private IBaseFilter capFilter; 

    /// <summary> graph builder interface. </summary> 
    private IGraphBuilder graphBuilder; 

    /// <summary> capture graph builder interface. </summary> 
    private ICaptureGraphBuilder2 capGraph; 
    private ISampleGrabber sampGrabber; 

    /// <summary> control interface. </summary> 
    private IMediaControl mediaCtrl; 

    /// <summary> event interface. </summary> 
    private IMediaEventEx mediaEvt; 

    /// <summary> video window interface. </summary> 
    private IVideoWindow videoWin; 

    /// <summary> grabber filter interface. </summary> 
    private IBaseFilter baseGrabFlt; 

    /// <summary> structure describing the bitmap to grab. </summary> 
    private VideoInfoHeader videoInfoHeader; 
    private bool captured = true; 
    private int bufferedSize; 

    /// <summary> buffer for bitmap data. </summary> 
    private byte[] savedArray; 

    /// <summary> list of installed video devices. </summary> 
    private ArrayList capDevices; 

    private const int WM_GRAPHNOTIFY = 0x00008001; // message from graph 

    private const int WS_CHILD = 0x40000000;  
    private const int WS_CLIPCHILDREN = 0x02000000; 
    private const int WS_CLIPSIBLINGS = 0x04000000; 


    private delegate void CaptureDone(); 

    #endregion 

    #region SampleGrabber 

    int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, 
    int BufferLen) 
    { 
     if (captured || (savedArray == null)) 
     { 
      return 0; 
     } 

     captured = true; 
     bufferedSize = BufferLen; 
     if ((pBuffer != IntPtr.Zero) && (BufferLen > 1000) && 
     (BufferLen <= savedArray.Length)) 
      Marshal.Copy(pBuffer, savedArray, 0, BufferLen); 
     OnCaptureDone(); 
     return 0; 
    } 

    int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) 
    { 
     return 0; 
    } 

    #endregion 

    public DsCameraHelper() 
    { 
     InitDevices(); 
     Cameras = new List<Camera>(); 
     videoPanel = new Panel(); 
     foreach (DsDevice cam in capDevices) 
     { 

      Cameras.Add(new Camera() { Device = cam, Name = cam.Name }); 
     } 
    } 

    public EventHandler<ImageEventArgs> OnSnapShotCompleted; 

    public List<Camera> Cameras { get; set; } 
    Camera runningCamera = null; 

    private void PrepareCam() 
    { 

     if (!StartupVideo(runningCamera.Device.Mon)) return; 


    } 
    /// <summary> handler for toolbar button clicks. </summary> 
    public void ClickImage(Camera device) 
    { 
     if (runningCamera == null) 
      runningCamera = device; 
     if(runningCamera.Name != device.Name) 
     { 
      runningCamera.IsRunning = false; 
      runningCamera = device; 
     } 

     if (runningCamera == null) return; 
     if (runningCamera.IsRunning) 
      capFilter.Run(10); 
     else 
      PrepareCam(); 
     captured = false; 
     runningCamera.IsRunning = true; 

     int hr; 
     if (sampGrabber == null) 
      return; 

     if (savedArray == null) 
     { 
      int size = videoInfoHeader.BmiHeader.ImageSize; 
      if ((size < 1000) || (size > 16000000)) 
       return; 
      savedArray = new byte[size + 64000]; 
     } 

     hr = sampGrabber.SetCallback(this, 1); 

    } 

    #region DS Implementation 

    private void InitDevices() 
    { 
     if (!DsUtils.IsCorrectDirectXVersion()) 
     { 
      return; 
     } 

     if (!DsDev.GetDevicesOfCat(FilterCategory.VideoInputDevice, 
      out capDevices)) 
     { 
      return; 
     } 
    } 

    /// <summary> capture event, triggered by buffer callback. </summary> 
    void OnCaptureDone() 
    { 
     try 
     { 
      int hr; 
      if (sampGrabber == null) 
       return; 
      //hr = sampGrabber.SetCallback(null, 0); 

      int w = videoInfoHeader.BmiHeader.Width; 
      int h = videoInfoHeader.BmiHeader.Height; 
      if (((w & 0x03) != 0) || (w < 32) || (w > 4096) 
      || (h < 32) || (h > 4096)) 
       return; 
      int stride = w * 3; 

      GCHandle handle = GCHandle.Alloc(savedArray, 
      GCHandleType.Pinned); 
      int scan0 = (int)handle.AddrOfPinnedObject(); 
      scan0 += (h - 1) * stride; 
      Bitmap b = new Bitmap(w, h, -stride, 
       PixelFormat.Format24bppRgb, (IntPtr)scan0); 
      handle.Free(); 
      savedArray = null; 
      lastFrame = b; 

      if (OnSnapShotCompleted != null) 
       OnSnapShotCompleted(this, 
      new ImageEventArgs() { CapturedImage = b }); 
      capFilter.Stop(); 

      //Dispose(); 
      //StartupVideo(device.Mon); 
     } 
     catch (Exception ee) 
     { 
     } 
    } 
    public Bitmap LastFrame { get { return lastFrame; } } 
    private Bitmap lastFrame; 
    bool StartupVideo(UCOMIMoniker mon) 
    { 
     int hr; 
     try 
     { 
      if (!CreateCaptureDevice(mon)) 
       return false; 

      if (!GetInterfaces()) 
       return false; 

      if (!SetupGraph()) 
       return false; 

      if (!SetupVideoWindow()) 
       return false; 


      hr = mediaCtrl.Run(); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 
      Thread.Sleep(runningCamera.Delay); 
      return true; 
     } 
     catch (Exception ee) 
     { 
      return false; 
     } 
    } 


    bool GetInterfaces() 
    { 
     Type comType = null; 
     object comObj = null; 
     try 
     { 
      comType = Type.GetTypeFromCLSID(Clsid.FilterGraph); 
      if (comType == null) 
       throw new NotImplementedException(
       @"DirectShow FilterGraph not installed/registered!"); 
      comObj = Activator.CreateInstance(comType); 
      graphBuilder = (IGraphBuilder)comObj; comObj = null; 

      Guid clsid = Clsid.CaptureGraphBuilder2; 
      Guid riid = typeof(ICaptureGraphBuilder2).GUID; 
      comObj = DsBugWO.CreateDsInstance(ref clsid, ref riid); 
      capGraph = (ICaptureGraphBuilder2)comObj; comObj = null; 

      comType = Type.GetTypeFromCLSID(Clsid.SampleGrabber); 
      if (comType == null) 
       throw new NotImplementedException(
       @"DirectShow SampleGrabber not installed/registered!"); 
      comObj = Activator.CreateInstance(comType); 
      sampGrabber = (ISampleGrabber)comObj; comObj = null; 

      mediaCtrl = (IMediaControl)graphBuilder; 
      videoWin = (IVideoWindow)graphBuilder; 
      mediaEvt = (IMediaEventEx)graphBuilder; 
      baseGrabFlt = (IBaseFilter)sampGrabber; 
      return true; 
     } 
     catch (Exception ee) 
     { 
      return false; 
     } 
     finally 
     { 
      if (comObj != null) 
       Marshal.ReleaseComObject(comObj); comObj = null; 
     } 
    } 

    /// <summary> create the user selected capture device. </summary> 
    bool CreateCaptureDevice(UCOMIMoniker mon) 
    { 
     object capObj = null; 
     try 
     { 
      Guid gbf = typeof(IBaseFilter).GUID; 
      mon.BindToObject(null, null, ref gbf, out capObj); 
      capFilter = (IBaseFilter)capObj; capObj = null; 
      return true; 
     } 
     catch (Exception ee) 
     { 
      return false; 
     } 
     finally 
     { 
      if (capObj != null) 
       Marshal.ReleaseComObject(capObj); capObj = null; 
     } 

    } 

    bool CloseAll() 
    { 
     videoWin.put_Owner(IntPtr.Zero); 
     mediaCtrl.Stop(); 
     baseGrabFlt = null; 
     if (sampGrabber != null) 
      Marshal.ReleaseComObject(sampGrabber); sampGrabber = null; 

     if (capGraph != null) 
      Marshal.ReleaseComObject(capGraph); capGraph = null; 

     if (graphBuilder != null) 
      Marshal.ReleaseComObject(graphBuilder); graphBuilder = null; 

     if (capFilter != null) 
      Marshal.ReleaseComObject(capFilter); capFilter = null; 
     return true; 
    } 


    bool SetupVideoWindow() 
    { 
     int hr; 
     try 
     { 
      // Set the video window to be a child of the main window 
      hr = videoWin.put_Owner(videoPanel.Handle); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      // Set video window style 
      hr = videoWin.put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      // Use helper function to position video 
      //window in client rect of owner window 
      //ResizeVideoWindow(); 

      // Make the video window visible, now that 
      //it is properly positioned 
      hr = videoWin.put_Visible(DsHlp.OAFALSE); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      hr = mediaEvt.SetNotifyWindow(videoPanel.Handle, 
      WM_GRAPHNOTIFY, IntPtr.Zero); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 
      return true; 
     } 
     catch (Exception ee) 
     { 
      return false; 
     } 
    } 

    /// <summary> build the capture graph for grabber. </summary> 
    bool SetupGraph() 
    { 
     int hr; 
     try 
     { 
      hr = capGraph.SetFiltergraph(graphBuilder); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      hr = graphBuilder.AddFilter(capFilter, 
      "Ds.NET Video Capture Device"); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      //DsUtils.ShowCapPinDialog(capGraph, capFilter, this.Handle); 

      AMMediaType media = new AMMediaType(); 
      media.majorType = MediaType.Video; 
      media.subType = MediaSubType.RGB24; 
      media.formatType = FormatType.VideoInfo;  // ??? 
      hr = sampGrabber.SetMediaType(media); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      hr = graphBuilder.AddFilter(baseGrabFlt, "Ds.NET Grabber"); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      Guid cat = PinCategory.Preview; 
      Guid med = MediaType.Video; 
      hr = capGraph.RenderStream(ref cat, ref med, 
      capFilter, null, null); // baseGrabFlt 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      cat = PinCategory.Capture; 
      med = MediaType.Video; 
      hr = capGraph.RenderStream(ref cat, 
      ref med, capFilter, null, baseGrabFlt); // baseGrabFlt 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      media = new AMMediaType(); 
      hr = sampGrabber.GetConnectedMediaType(media); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 
      if ((media.formatType != FormatType.VideoInfo) || 
       (media.formatPtr == IntPtr.Zero)) 
       throw new NotSupportedException(
       "Unknown Grabber Media Format"); 

      videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(
      media.formatPtr, typeof(VideoInfoHeader)); 
      Marshal.FreeCoTaskMem(media.formatPtr); 
      media.formatPtr = IntPtr.Zero; 

      hr = sampGrabber.SetBufferSamples(false); 
      if (hr == 0) 
       hr = sampGrabber.SetOneShot(false); 
      if (hr == 0) 
       hr = sampGrabber.SetCallback(null, 0); 
      if (hr < 0) 
       Marshal.ThrowExceptionForHR(hr); 

      return true; 
     } 
     catch (Exception ee) 
     { 
      return false; 
     } 
    } 

    #endregion 

    #region IDisposable Implementation 

    public void Dispose() 
    { 
     CloseInterfaces(); 
    } 

    private void CloseInterfaces() 
    { 
     int hr; 
     try 
     { 
      OnSnapShotCompleted = null; 
      lastFrame.Dispose(); 
      lastFrame = null; 
      if (graphBuilder != null) 
      { 
       hr = graphBuilder.RemoveFilter(capFilter); 
       Marshal.ThrowExceptionForHR(hr); 

       hr = graphBuilder.RemoveFilter(baseGrabFlt); 
       Marshal.ThrowExceptionForHR(hr); 

       Marshal.FinalReleaseComObject(graphBuilder); 
      } 

      if (mediaCtrl != null) 
      { 
       hr = mediaCtrl.Stop(); 
       Marshal.FinalReleaseComObject(mediaCtrl); 
       mediaCtrl = null; 
       Marshal.ThrowExceptionForHR(hr); 

      } 

      if (mediaEvt != null) 
      { 
       hr = mediaEvt.SetNotifyWindow(IntPtr.Zero, 
        WM_GRAPHNOTIFY, IntPtr.Zero); 
       Marshal.FinalReleaseComObject(mediaEvt); 
       mediaEvt = null; 
       Marshal.ThrowExceptionForHR(hr); 
      } 

      if (videoWin != null) 
      { 
       hr = videoWin.put_Visible(DsHlp.OAFALSE); 
       Marshal.ThrowExceptionForHR(hr); 
       hr = videoWin.put_Owner(IntPtr.Zero); 
       Marshal.ThrowExceptionForHR(hr); 

       Marshal.FinalReleaseComObject(videoWin); 
       videoWin = null; 

       videoPanel.Dispose(); 
       Marshal.FinalReleaseComObject(videoPanel); 
       videoPanel = null; 
      } 

      Marshal.FinalReleaseComObject(videoInfoHeader); 
      videoInfoHeader = null; 

      Marshal.FinalReleaseComObject(baseGrabFlt); 
      baseGrabFlt = null; 

      if (sampGrabber != null) 
       Marshal.FinalReleaseComObject(sampGrabber); 
      sampGrabber = null; 

      if (capGraph != null) 
       Marshal.FinalReleaseComObject(capGraph); capGraph = null; 

      if (graphBuilder != null) 
       Marshal.FinalReleaseComObject(graphBuilder); 
      graphBuilder = null; 

      if (capFilter != null) 
      { 
       hr = capFilter.Stop(); 
       Marshal.ThrowExceptionForHR(hr); 
       Marshal.FinalReleaseComObject(capFilter); capFilter = null; 
      } 

      if (capDevices != null) 
      { 
       foreach (DsDevice d in capDevices) 
       { 
        d.Dispose(); 
        Marshal.FinalReleaseComObject(d); ; 
       } 
       capDevices = null; 
      } 
      foreach (var cam in Cameras) 
      { 
       cam.Device.Dispose(); 
       Marshal.FinalReleaseComObject(cam.Device); 
      } 
      Cameras = null; 
      GC.Collect(); 
     } 
     catch 
     { } 
    } 

    #endregion 
} 

static void Main(string[] args) 
    { 
     DShowNET.DsCameraHelper c = new DShowNET.DsCameraHelper(); 
     Console.WriteLine("List of Attached Cams."); 
     var count = 1; 
     foreach (var cam in c.Cameras) 
     { 
      Console.WriteLine(string.Format("{0}. {1}", count++, cam.Name)); 
     } 

     Console.WriteLine(string.Format("{0}. {1}", count++, "Exit")); 

     int choosenCam = 0; 
     while (choosenCam != count) 
     { 
      Console.WriteLine("Please choose a camera to take snapshot"); 

      var key = Console.ReadLine(); 

      if (int.TryParse(key, out choosenCam) && choosenCam <= c.Cameras.Count) 
      { 
       //c.ClickImage(c.Cameras[choosenCam - 1]); 
       //var path = string.Format("img_{0}.png", DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff")); 
       //img.Save(path, ImageFormat.Png); 
       //Console.WriteLine("Image save successfully at " + path); 
       var task = GetSnap(c.Cameras[choosenCam - 1]); 
       var data = task.Result; 
       task.Dispose(); 
      } 
     } 
    } 
    private static async Task<Bitmap> GetSnap(Camera cam) 
    { 
     Bitmap img = null; 
     await System.Threading.Tasks.Task.Run(() => 
     { 
      DsCameraHelper helper = new DsCameraHelper(); 
      AutoResetEvent waitHandle = new AutoResetEvent(false); 
      EventHandler<ImageEventArgs> eventHandler = delegate(object sender, ImageEventArgs e) 
      { 
       //img = e.CapturedImage; 

       waitHandle.Set(); // signal that the finished event was raised 
      }; 
      helper.OnSnapShotCompleted += eventHandler; 
      Camera dev = null; 
      foreach (var camera in helper.Cameras) 
      { 
       Guid cId, coutId; 
       if (camera.Name.Equals(cam.Name)) 
        dev = camera; 
      } 

      if (dev != null) 
      { 
       helper.ClickImage(dev); 
      } 
      else 
       throw new Exception("Invalid Cam Selected"); 
      waitHandle.WaitOne(); 
      helper.OnSnapShotCompleted -= eventHandler; 
      helper.Dispose(); 
      waitHandle.Dispose(); 
      waitHandle = null; 
      helper = null; 
     }).ConfigureAwait(false); 
     return img; 
    } 
} 

https://onedrive.live.com/redir?resid=2B39C1B1D1F06A02!8546&authkey=!AGuDe-Q_6_sacM0&ithint=folder%2ccs

Спасибо.

+1

Вставьте свой код в вопрос. –

ответ

1

Вы не должны останавливать график фильтра из фрейма callack. Сделайте свое дело в обратном вызове и немедленно возвращайтесь (без OnCaptureDone и друзей), остановите захват из кода верхнего уровня, где вы создали и начали графа фильтров на первом месте.

+0

Спасибо, что это сработало. В методе closeInterface произошла ошибка, которая вызывала проблему. – Shivendra