ISampleGrabber 中的内存泄漏
Memory Leak in 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;
}
}
谢谢。
你不应该从帧回调中停止过滤图。在回调中做你的事情并立即 return(没有 OnCaptureDone
和朋友),停止从你首先构建和启动过滤器图的顶级代码中捕获。
我已经实现了下面的代码。基本上我正在尝试从相机中抓取快照。该代码适用于集成凸轮,但当连接外部凸轮时,问题就开始了。它只需要第一次拍摄,第二次拍摄永远不会到来。
代码可以在
查看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;
}
}
谢谢。
你不应该从帧回调中停止过滤图。在回调中做你的事情并立即 return(没有 OnCaptureDone
和朋友),停止从你首先构建和启动过滤器图的顶级代码中捕获。