|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using HuizhongLibrary.Log;
|
|
|
|
|
using DirectShowLib;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Drawing.Imaging;
|
|
|
|
|
|
|
|
|
|
namespace HuizhongLibrary
|
|
|
|
|
{
|
|
|
|
|
public class Camera : ISampleGrabberCB, IDisposable
|
|
|
|
|
{
|
|
|
|
|
#region Member variables
|
|
|
|
|
|
|
|
|
|
/// <summary> graph builder interface. </summary>
|
|
|
|
|
private IFilterGraph2 m_FilterGraph = null;
|
|
|
|
|
private IMediaControl m_mediaCtrl = null;
|
|
|
|
|
|
|
|
|
|
/// <summary> so we can wait for the async job to finish </summary>
|
|
|
|
|
private ManualResetEvent m_PictureReady = null;
|
|
|
|
|
|
|
|
|
|
/// <summary> Set by async routine when it captures an image </summary>
|
|
|
|
|
private volatile bool m_bGotOne = false;
|
|
|
|
|
|
|
|
|
|
/// <summary> Indicates the status of the graph </summary>
|
|
|
|
|
private bool m_bRunning = false;
|
|
|
|
|
|
|
|
|
|
/// <summary> Dimensions of the image, calculated once in constructor. </summary>
|
|
|
|
|
private IntPtr m_handle = IntPtr.Zero;
|
|
|
|
|
private int m_videoWidth;
|
|
|
|
|
private int m_videoHeight;
|
|
|
|
|
private int m_stride;
|
|
|
|
|
public int m_Dropped = 0;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region API
|
|
|
|
|
|
|
|
|
|
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
|
|
|
|
|
private static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary> Use capture device zero, default frame rate and size</summary>
|
|
|
|
|
public Camera()
|
|
|
|
|
{
|
|
|
|
|
_Capture(0, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
/// <summary> Use specified capture device, default frame rate and size</summary>
|
|
|
|
|
public Camera(int iDeviceNum)
|
|
|
|
|
{
|
|
|
|
|
_Capture(iDeviceNum, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
/// <summary> Use specified capture device, specified frame rate and default size</summary>
|
|
|
|
|
public Camera(int iDeviceNum, int iFrameRate)
|
|
|
|
|
{
|
|
|
|
|
_Capture(iDeviceNum, iFrameRate, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
/// <summary> Use specified capture device, specified frame rate and size</summary>
|
|
|
|
|
public Camera(int iDeviceNum, int iFrameRate, int iWidth, int iHeight)
|
|
|
|
|
{
|
|
|
|
|
_Capture(iDeviceNum, iFrameRate, iWidth, iHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 初始化线程
|
|
|
|
|
private AutoResetEvent AutoReset = new AutoResetEvent(false);
|
|
|
|
|
Thread CameraThread = null;
|
|
|
|
|
public bool IsScreenImage = false;
|
|
|
|
|
public event Action<Bitmap> OutImage;
|
|
|
|
|
public void StartScreenImage()
|
|
|
|
|
{
|
|
|
|
|
CameraThread = new Thread(ScreenImage);
|
|
|
|
|
CameraThread.Start();
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 停止录像
|
|
|
|
|
public void StopScreenImage()
|
|
|
|
|
{
|
|
|
|
|
IsScreenImage = false;
|
|
|
|
|
if (CameraThread == null) return;
|
|
|
|
|
while (CameraThread.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
System.Threading.Thread.Sleep(500);
|
|
|
|
|
}
|
|
|
|
|
//System.Threading.Thread.Sleep(1000);
|
|
|
|
|
//CameraThread.Abort();
|
|
|
|
|
//CameraThread = null;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 录像
|
|
|
|
|
void ScreenImage()
|
|
|
|
|
{
|
|
|
|
|
IsScreenImage = true;
|
|
|
|
|
while (this.IsScreenImage)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Bitmap image = null;
|
|
|
|
|
IntPtr ip = IntPtr.Zero;
|
|
|
|
|
ip = this.GetBitMap();
|
|
|
|
|
image = new Bitmap(this.Width, this.Height, this.Stride, PixelFormat.Format24bppRgb, ip);
|
|
|
|
|
//旋转
|
|
|
|
|
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
|
|
|
|
//释放指针ip
|
|
|
|
|
Marshal.FreeCoTaskMem(ip);
|
|
|
|
|
//回收垃圾
|
|
|
|
|
GC.Collect();
|
|
|
|
|
//不安全的刷新
|
|
|
|
|
if (this.OutImage != null) this.OutImage(image);
|
|
|
|
|
AutoReset.WaitOne(100);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ErrorFollow.TraceWrite(ex.TargetSite.Name, ex.StackTrace, ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 截图
|
|
|
|
|
public Bitmap GrabImage()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
StopScreenImage();
|
|
|
|
|
Bitmap image = null;
|
|
|
|
|
IntPtr ip = IntPtr.Zero;
|
|
|
|
|
ip = this.GetBitMap();
|
|
|
|
|
image = new Bitmap(this.Width, this.Height, this.Stride, PixelFormat.Format24bppRgb, ip);
|
|
|
|
|
//旋转
|
|
|
|
|
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
|
|
|
|
//释放指针ip
|
|
|
|
|
Marshal.FreeCoTaskMem(ip);
|
|
|
|
|
//回收垃圾
|
|
|
|
|
GC.Collect();
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ErrorFollow.TraceWrite(ex.TargetSite.Name, ex.StackTrace, ex.Message);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 截图
|
|
|
|
|
public void GrabImage(string filePath)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
StopScreenImage();
|
|
|
|
|
Bitmap image = null;
|
|
|
|
|
IntPtr ip = IntPtr.Zero;
|
|
|
|
|
ip = this.GetBitMap();
|
|
|
|
|
image = new Bitmap(this.Width, this.Height, this.Stride, PixelFormat.Format24bppRgb, ip);
|
|
|
|
|
//旋转
|
|
|
|
|
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
|
|
|
|
//释放指针ip
|
|
|
|
|
Marshal.FreeCoTaskMem(ip);
|
|
|
|
|
//回收垃圾
|
|
|
|
|
GC.Collect();
|
|
|
|
|
image.Save(filePath, ImageFormat.Jpeg);
|
|
|
|
|
StartScreenImage();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ErrorFollow.TraceWrite(ex.TargetSite.Name, ex.StackTrace, ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 截图并转成数组
|
|
|
|
|
public byte[] GrabImageToByte()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
StopScreenImage();
|
|
|
|
|
Bitmap image = null;
|
|
|
|
|
IntPtr ip = IntPtr.Zero;
|
|
|
|
|
ip = this.GetBitMap();
|
|
|
|
|
image = new Bitmap(this.Width, this.Height, this.Stride, PixelFormat.Format24bppRgb, ip);
|
|
|
|
|
//旋转
|
|
|
|
|
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
|
|
|
|
//释放指针ip
|
|
|
|
|
Marshal.FreeCoTaskMem(ip);
|
|
|
|
|
//回收垃圾
|
|
|
|
|
GC.Collect();
|
|
|
|
|
byte[] bytes=CustomIO.GetPhoto(image);
|
|
|
|
|
image.Dispose();
|
|
|
|
|
image = null;
|
|
|
|
|
StartScreenImage();
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ErrorFollow.TraceWrite(ex.TargetSite.Name, ex.StackTrace, ex.Message);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 读取所有摄像头设备
|
|
|
|
|
public static DsDevice[] GetDevices()
|
|
|
|
|
{
|
|
|
|
|
DsDevice[] capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
|
|
|
|
|
return capDevices;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
#region 是否存在摄像头
|
|
|
|
|
public static bool IsCamera()
|
|
|
|
|
{
|
|
|
|
|
DsDevice[] capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
|
|
|
|
|
if (capDevices.Length == 0) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> release everything. </summary>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
this.m_bRunning = false;
|
|
|
|
|
CloseInterfaces();
|
|
|
|
|
if (m_PictureReady != null)
|
|
|
|
|
{
|
|
|
|
|
m_PictureReady.Close();
|
|
|
|
|
m_PictureReady = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Destructor
|
|
|
|
|
~Camera()
|
|
|
|
|
{
|
|
|
|
|
Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Width
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return m_videoWidth;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public int Height
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return m_videoHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public int Stride
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return m_stride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary> capture the next image </summary>
|
|
|
|
|
public IntPtr GetBitMap()
|
|
|
|
|
{
|
|
|
|
|
m_handle = Marshal.AllocCoTaskMem(m_stride * m_videoHeight);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// get ready to wait for new image
|
|
|
|
|
m_PictureReady.Reset();
|
|
|
|
|
m_bGotOne = false;
|
|
|
|
|
|
|
|
|
|
// If the graph hasn't been started, start it.
|
|
|
|
|
Start();
|
|
|
|
|
|
|
|
|
|
// Start waiting
|
|
|
|
|
if (!m_PictureReady.WaitOne(5000, false))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Timeout waiting to get picture");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
Marshal.FreeCoTaskMem(m_handle);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
return m_handle;
|
|
|
|
|
}
|
|
|
|
|
// Start the capture graph
|
|
|
|
|
public void Start()
|
|
|
|
|
{
|
|
|
|
|
if (!m_bRunning)
|
|
|
|
|
{
|
|
|
|
|
int hr = m_mediaCtrl.Run();
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
m_bRunning = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Pause the capture graph.
|
|
|
|
|
// Running the graph takes up a lot of resources. Pause it when it
|
|
|
|
|
// isn't needed.
|
|
|
|
|
public void Pause()
|
|
|
|
|
{
|
|
|
|
|
if (m_bRunning)
|
|
|
|
|
{
|
|
|
|
|
int hr = m_mediaCtrl.Pause();
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
m_bRunning = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Internal capture
|
|
|
|
|
private void _Capture(int iDeviceNum, int iFrameRate, int iWidth, int iHeight)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
// Set up the capture graph
|
|
|
|
|
SetupGraph(capDevices[iDeviceNum], iFrameRate, iWidth, iHeight);
|
|
|
|
|
|
|
|
|
|
// tell the callback to ignore new images
|
|
|
|
|
m_PictureReady = new ManualResetEvent(false);
|
|
|
|
|
m_bGotOne = true;
|
|
|
|
|
m_bRunning = false;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
Dispose();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary> build the capture graph for grabber. </summary>
|
|
|
|
|
private void SetupGraph(DsDevice dev, int iFrameRate, int iWidth, int iHeight)
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
ISampleGrabber sampGrabber = null;
|
|
|
|
|
IBaseFilter capFilter = null;
|
|
|
|
|
ICaptureGraphBuilder2 capGraph = null;
|
|
|
|
|
|
|
|
|
|
// Get the graphbuilder object
|
|
|
|
|
m_FilterGraph = (IFilterGraph2)new FilterGraph();
|
|
|
|
|
m_mediaCtrl = m_FilterGraph as IMediaControl;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Get the ICaptureGraphBuilder2
|
|
|
|
|
capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
|
|
|
|
|
|
|
|
|
|
// Get the SampleGrabber interface
|
|
|
|
|
sampGrabber = (ISampleGrabber)new SampleGrabber();
|
|
|
|
|
|
|
|
|
|
// Start building the graph
|
|
|
|
|
hr = capGraph.SetFiltergraph(m_FilterGraph);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// Add the video device
|
|
|
|
|
hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, "Video input", out capFilter);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
IBaseFilter baseGrabFlt = (IBaseFilter)sampGrabber;
|
|
|
|
|
ConfigureSampleGrabber(sampGrabber);
|
|
|
|
|
|
|
|
|
|
// Add the frame grabber to the graph
|
|
|
|
|
hr = m_FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
// If any of the default config items are set
|
|
|
|
|
if (iFrameRate + iHeight + iWidth > 0)
|
|
|
|
|
{
|
|
|
|
|
SetConfigParms(capGraph, capFilter, iFrameRate, iWidth, iHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = capGraph.RenderStream(PinCategory.Capture, MediaType.Video, capFilter, null, baseGrabFlt);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
SaveSizeInfo(sampGrabber);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (capFilter != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(capFilter);
|
|
|
|
|
capFilter = null;
|
|
|
|
|
}
|
|
|
|
|
if (sampGrabber != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(sampGrabber);
|
|
|
|
|
sampGrabber = null;
|
|
|
|
|
}
|
|
|
|
|
if (capGraph != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(capGraph);
|
|
|
|
|
capGraph = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SaveSizeInfo(ISampleGrabber sampGrabber)
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
// Get the media type from the SampleGrabber
|
|
|
|
|
AMMediaType media = new AMMediaType();
|
|
|
|
|
hr = sampGrabber.GetConnectedMediaType(media);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException("Unknown Grabber Media Format");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grab the size info
|
|
|
|
|
VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
|
|
|
|
|
m_videoWidth = videoInfoHeader.BmiHeader.Width;
|
|
|
|
|
m_videoHeight = videoInfoHeader.BmiHeader.Height;
|
|
|
|
|
m_stride = m_videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
|
|
|
|
|
|
|
|
|
|
DsUtils.FreeAMMediaType(media);
|
|
|
|
|
media = null;
|
|
|
|
|
}
|
|
|
|
|
private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
|
|
|
|
|
{
|
|
|
|
|
AMMediaType media;
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
// Set the media type to Video/RBG24
|
|
|
|
|
media = new AMMediaType();
|
|
|
|
|
media.majorType = MediaType.Video;
|
|
|
|
|
media.subType = MediaSubType.RGB24;
|
|
|
|
|
media.formatType = FormatType.VideoInfo;
|
|
|
|
|
hr = sampGrabber.SetMediaType(media);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
|
|
|
|
|
DsUtils.FreeAMMediaType(media);
|
|
|
|
|
media = null;
|
|
|
|
|
|
|
|
|
|
// Configure the samplegrabber
|
|
|
|
|
hr = sampGrabber.SetCallback(this, 1);
|
|
|
|
|
DsError.ThrowExceptionForHR(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the Framerate, and video size
|
|
|
|
|
private void SetConfigParms(ICaptureGraphBuilder2 capGraph, IBaseFilter capFilter, int iFrameRate, int iWidth, int iHeight)
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
object o;
|
|
|
|
|
AMMediaType media;
|
|
|
|
|
|
|
|
|
|
// Find the stream config interface
|
|
|
|
|
hr = capGraph.FindInterface(
|
|
|
|
|
PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out o);
|
|
|
|
|
|
|
|
|
|
IAMStreamConfig videoStreamConfig = o as IAMStreamConfig;
|
|
|
|
|
if (videoStreamConfig == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Failed to get IAMStreamConfig");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the existing format block
|
|
|
|
|
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 = 10000000 / iFrameRate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if overriding the width, set the width
|
|
|
|
|
if (iWidth > 0)
|
|
|
|
|
{
|
|
|
|
|
v.BmiHeader.Width = iWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if overriding the Height, set the Height
|
|
|
|
|
if (iHeight > 0)
|
|
|
|
|
{
|
|
|
|
|
v.BmiHeader.Height = iHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary> Shut down capture </summary>
|
|
|
|
|
private void CloseInterfaces()
|
|
|
|
|
{
|
|
|
|
|
int hr;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (m_mediaCtrl != null)
|
|
|
|
|
{
|
|
|
|
|
// Stop the graph
|
|
|
|
|
hr = m_mediaCtrl.Stop();
|
|
|
|
|
m_bRunning = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
ErrorFollow.TraceWrite(ex.TargetSite.Name, ex.StackTrace, ex.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_FilterGraph != null)
|
|
|
|
|
{
|
|
|
|
|
Marshal.ReleaseComObject(m_FilterGraph);
|
|
|
|
|
m_FilterGraph = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary> sample callback, NOT USED. </summary>
|
|
|
|
|
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)
|
|
|
|
|
{
|
|
|
|
|
if (!m_bGotOne)
|
|
|
|
|
{
|
|
|
|
|
// Set bGotOne to prevent further calls until we
|
|
|
|
|
// request a new bitmap.
|
|
|
|
|
m_bGotOne = true;
|
|
|
|
|
IntPtr pBuffer;
|
|
|
|
|
|
|
|
|
|
pSample.GetPointer(out pBuffer);
|
|
|
|
|
int iBufferLen = pSample.GetSize();
|
|
|
|
|
|
|
|
|
|
if (pSample.GetSize() > m_stride * m_videoHeight)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Buffer is wrong size");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CopyMemory(m_handle, pBuffer, m_stride * m_videoHeight);
|
|
|
|
|
|
|
|
|
|
// Picture is ready.
|
|
|
|
|
m_PictureReady.Set();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Marshal.ReleaseComObject(pSample);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
|
|
|
|
|
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
|
|
|
|
|
{
|
|
|
|
|
if (!m_bGotOne)
|
|
|
|
|
{
|
|
|
|
|
// The buffer should be long enought
|
|
|
|
|
if (BufferLen <= m_stride * m_videoHeight)
|
|
|
|
|
{
|
|
|
|
|
// Copy the frame to the buffer
|
|
|
|
|
CopyMemory(m_handle, pBuffer, m_stride * m_videoHeight);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Buffer is wrong size");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set bGotOne to prevent further calls until we
|
|
|
|
|
// request a new bitmap.
|
|
|
|
|
m_bGotOne = true;
|
|
|
|
|
|
|
|
|
|
// Picture is ready.
|
|
|
|
|
m_PictureReady.Set();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_Dropped++;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|