AviCap
代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
//namespace AviCap
//{
public class AviCap
{
#region 外部方法
[DllImport("avicap32.dll")]
public static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);
[DllImport("avicap32.dll")]
public static extern bool capGetDriverDescriptionA(short wDriver, byte[] lpszName, int cbName, byte[] lpszVer, int cbVer);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, int lParam);
public delegate void FrameEventHandler(IntPtr lwnd, IntPtr lpVHdr);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, FrameEventHandler lParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref BITMAPINFO lParam);
/// <summary>
/// 该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。
/// </summary>
[DllImport("User32.dll")]
public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
[DllImport("avicap32.dll")]
public static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize);
#endregion
#region 消息常量(向窗口发送消息的指令)
//消息常量 --------------------------------------------
public const int WM_START = 0x400; //此并非摄像头消息0x400表示的就是1024
public const int WS_CHILD = 0x40000000;
public const int WS_VISIBLE = 0x10000000;
public const int SWP_NOMOVE = 0x2;
public const int SWP_NOZORDER = 0x4;
public const int WM_CAP_GET_CAPSTREAMPTR = WM_START + 1;
public const int WM_CAP_SET_CALLBACK_ERROR = WM_START + 2;//设置收回错误
public const int WM_CAP_SET_CALLBACK_STATUS = WM_START + 3;//设置收回状态
public const int WM_CAP_SET_CALLBACK_YIELD = WM_START + 4;//设置收回出产
public const int WM_CAP_SET_CALLBACK_FRAME = WM_START + 5;//设置收回结构
public const int WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_START + 6;//设置收回视频流
public const int WM_CAP_SET_CALLBACK_WAVESTREAM = WM_START + 7;//设置收回视频波流
public const int WM_CAP_GET_USER_DATA = WM_START + 8;//获得使用者数据
public const int WM_CAP_SET_USER_DATA = WM_START + 9;//设置使用者数据
public const int WM_CAP_DRIVER_CONNECT = WM_START + 10;//驱动程序连接
public const int WM_CAP_DRIVER_DISCONNECT = WM_START + 11;//断开启动程序连接
public const int WM_CAP_DRIVER_GET_NAME = WM_START + 12;//获得驱动程序名字
public const int WM_CAP_DRIVER_GET_VERSION = WM_START + 13;//获得驱动程序版本
public const int WM_CAP_DRIVER_GET_CAPS = WM_START + 14;//获得驱动程序帽子
public const int WM_CAP_FILE_SET_CAPTURE_FILE = WM_START + 20;//设置捕获文件
public const int WM_CAP_FILE_GET_CAPTURE_FILE = WM_START + 21;//获得捕获文件
public const int WM_CAP_FILE_ALLOCATE = WM_START + 22;//分派文件
public const int WM_CAP_FILE_SAVEAS = WM_START + 23;//另存文件为
public const int WM_CAP_FILE_SET_INFOCHUNK = WM_START + 24;//设置开始文件
public const int WM_CAP_FILE_SAVEDIB = WM_START + 25;//保存文件
public const int WM_CAP_EDIT_COPY = WM_START + 30;//编辑复制
public const int WM_CAP_SET_AUDIOFORMAT = WM_START + 35;//设置音频格式
public const int WM_CAP_GET_AUDIOFORMAT = WM_START + 36;//捕获音频格式
public const int WM_CAP_DLG_VIDEOFORMAT = WM_START + 41;//1065 打开视频格式设置对话框
public const int WM_CAP_DLG_VIDEOSOURCE = WM_START + 42;//1066 打开属性设置对话框,设置对比度亮度等
public const int WM_CAP_DLG_VIDEODISPLAY = WM_START + 43;//1067 打开视频显示
public const int WM_CAP_GET_VIDEOFORMAT = WM_START + 44;//1068 获得视频格式
public const int WM_CAP_SET_VIDEOFORMAT = WM_START + 45;//1069 设置视频格式
public const int WM_CAP_DLG_VIDEOCOMPRESSION = WM_START + 46;//1070 打开压缩设置对话框
public const int WM_CAP_SET_PREVIEW = WM_START + 50;//设置预览
public const int WM_CAP_SET_OVERLAY = WM_START + 51;//设置覆盖
public const int WM_CAP_SET_PREVIEWRATE = WM_START + 52;//设置预览比例
public const int WM_CAP_SET_SCALE = WM_START + 53;//设置刻度
public const int WM_CAP_GET_STATUS = WM_START + 54;//获得状态
public const int WM_CAP_SET_SCROLL = WM_START + 55;//设置卷
public const int WM_CAP_GRAB_FRAME = WM_START + 60;//逮捕结构
public const int WM_CAP_GRAB_FRAME_NOSTOP = WM_START + 61;//停止逮捕结构
public const int WM_CAP_SEQUENCE = WM_START + 62;//次序
public const int WM_CAP_SEQUENCE_NOFILE = WM_START + 63;//使用WM_CAP_SEUENCE_NOFILE消息(capCaptureSequenceNoFile宏),可以不向磁盘文件写入数据。该消息仅在配合回调函数时有用,它允许你的应用程序直接使用音视频数据。
public const int WM_CAP_SET_SEQUENCE_SETUP = WM_START + 64;//设置安装次序
public const int WM_CAP_GET_SEQUENCE_SETUP = WM_START + 65;//获得安装次序
public const int WM_CAP_SET_MCI_DEVICE = WM_START + 66;//设置媒体控制接口
public const int WM_CAP_GET_MCI_DEVICE = WM_START + 67;//获得媒体控制接口
public const int WM_CAP_STOP = WM_START + 68;//停止
public const int WM_CAP_ABORT = WM_START + 69;//异常中断
public const int WM_CAP_SINGLE_FRAME_OPEN = WM_START + 70;//打开单一的结构
public const int WM_CAP_SINGLE_FRAME_CLOSE = WM_START + 71;//关闭单一的结构
public const int WM_CAP_SINGLE_FRAME = WM_START + 72;//单一的结构
public const int WM_CAP_PAL_OPEN = WM_START + 80;//打开视频
public const int WM_CAP_PAL_SAVE = WM_START + 81;//保存视频
public const int WM_CAP_PAL_PASTE = WM_START + 82;//粘贴视频
public const int WM_CAP_PAL_AUTOCREATE = WM_START + 83; //自动创造
public const int WM_CAP_PAL_MANUALCREATE = WM_START + 84;//手动创造
public const int WM_CAP_SET_CALLBACK_CAPCONTROL = WM_START + 85;// 设置收回的错误
//其它
public const int WM_CAP_SAVEDIB = WM_CAP_START + 25;
public const int WM_USER = 0x400;//1024
public const int WM_CAP_START = WM_USER;
public const int WM_CAP_UNICODE_START = WM_USER + 100; //开始
public const int WM_CAP_GRAB_FRame = (WM_CAP_START + 60); //逮捕结构
public const int WM_CAP_GRAB_FRame_NOSTOP = (WM_CAP_START + 61); //停止逮捕结构
public const int WM_CAP_SINGLE_FRame_OPEN = (WM_CAP_START + 70); //打开单一的结构
public const int WM_CAP_SINGLE_FRame_CLOSE = (WM_CAP_START + 71); //关闭单一的结构
public const int WM_CAP_SINGLE_FRame = (WM_CAP_START + 72); //单一的结构
// Following added post VFW 1.1
public const int WM_CAP_END = WM_CAP_SET_CALLBACK_CAPCONTROL;
#endregion
#region 结构体
[StructLayout(LayoutKind.Sequential)]
public struct VIDEOHDR
{
[MarshalAs(UnmanagedType.I4)]
public int lpData;
[MarshalAs(UnmanagedType.I4)]
public int dwBufferLength;
[MarshalAs(UnmanagedType.I4)]
public int dwBytesUsed;
[MarshalAs(UnmanagedType.I4)]
public int dwTimeCaptured;
[MarshalAs(UnmanagedType.I4)]
public int dwUser;
[MarshalAs(UnmanagedType.I4)]
public int dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
[MarshalAs(UnmanagedType.I4)]
public Int32 biSize;
[MarshalAs(UnmanagedType.I4)]
public Int32 biWidth;
[MarshalAs(UnmanagedType.I4)]
public Int32 biHeight;
[MarshalAs(UnmanagedType.I2)]
public short biPlanes;
[MarshalAs(UnmanagedType.I2)]
public short biBitCount;
[MarshalAs(UnmanagedType.I4)]
public Int32 biCompression;
[MarshalAs(UnmanagedType.I4)]
public Int32 biSizeImage;
[MarshalAs(UnmanagedType.I4)]
public Int32 biXPelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public Int32 biYPelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public Int32 biClrUsed;
[MarshalAs(UnmanagedType.I4)]
public Int32 biClrImportant;
}
#region BITMAPINFO结构
//BITMAPINFO结构具有如下形式:
//typedef struct tagBITMAPINFO
//{
// BITMAPINFOHEADER bmiHeader;
// RGBQUAD bmiColors[1];
//} BITMAPINFO;
//BITMAPINFO结构定义了Windows设备无关位图(DIB)的度量和颜色信息。
//成员:
//bmiHeader 指定了一个BITMAPINFOHEADER结构,包含了有关设备相关位图的度量和颜色格式的信息。
//bmiColors 指定了一个RGBQUAD或DWORD数据类型的数组,定义了位图中的颜色。
//注释:
//设备无关位图由两个部分组成:
//(1) 一个BITMAPINFO结构,描述了位图的度量和颜色信息;
//(2) 一个字节数组,定义了位图的像素。数组中的字节被组合在一起,但是每个扫描行必须用零填补,在一个LONG边界结束。如果高度为正的,位图的起始位置在左下角。如果高度为负,起始位置在左上角。
//(3) BITMAPINFOHEADER结构中的biBitCount成员决定了定义像素的位数以及位图中的最大颜色数。这个成员可以是下列值之一:
//· 位图是单色的,bmiColors成员包含两个入口。位图数组中的每一位代表一个像素。如果该位被清除,则用bmiColors表中的第一种颜色显示该像素。如果该位被置位,则用表中的第二种颜色显示该像素。
//· 位图最多有16种颜色,bmiColors成员中包含了最多可达16个入口。位图中的每个像素用一个4位的值来表示,该值用作颜色表的索引。例如,如果位图中的第一个字节是0x1F,这个字节代表两个像素。第一个像素包含了颜色表中第二种颜色,第二个像素包含了颜色表中第十六种颜色。
//· 位图最多有256种颜色,bmiColors成员包含了多达256个入口。在这种情况下,数组中的每个字节代表一个像素。
//· 位图最多有216种颜色。BITMAPINFOHEADER的biCompression成员必须是BI_BITFIELDS。bmiColors成员包含了3个DWORD型颜色掩码,分别代表了每个像素中的红,绿和蓝色成分。DWORD型掩码中的位必须是连续的,不能与其它掩码重叠。并非像素中的所有位都必须被使用。数组中的每个WORD值代表一个像素。
//· 位图最多具有224种颜色,bmiColors成员为NULL。位图数组中的每个三字节组合分别代表像素中蓝,绿红的深度。
//· 位图中最多具有232种颜色。BITMAPINFOHEADER中的biCompression成员必须是BI_BITFIELDS。bmiColors成员中包含了三个DWORD颜色掩码,分别指定了像素的红,绿和蓝成分。DWORD掩码中的位必须是连续的,并且不能与其它掩码重叠。并非像素中的所有位都必须被使用。数组中的每个DWORD值代表一个像素。
//BITMAPINFOHEADER结构中的biClrUsed成员指定了颜色表中实际使用的索引的数目。如果biClrUsed成员被设为0,位图将使用biBitCount成员中指定的最大颜色数。
//bmiColors表中的颜色应当按照其重要性的顺序出现。另一种情况是,对于使用DIB函数,bmiColors成员可以是一个16位无符号整数的数组,指定了当前实现的逻辑调色板中的索引,而不是确切的RGB值。在这种情况下,使用位图的应用程序必须调用Windows的DIB函数(CreateDIBitmap,CreateDIBPatternBrush和CreateDIBSection),iUsage参数应被设为DIB_PAL_COLORS。
//如果位图是一个压缩位图(这意味着,这种位图的数组直接跟在一个指针所引用的BITMAPINFO头的后面),在使用DIB_PAL_COLORS模式的时候,biClrUsed成员必须被设为偶数,以便使DIB位图数组从DWORD边界开始。
//注意:
//如果位图被保存在文件中,或者要被传送到另一个应用程序,bmiColors成员不能包含调色板索引。除非应用程序独占地使用和控制位图,位图的颜色表中应当包含准确的RGB值。
#endregion
/// <summary>
/// BITMAPINFO结构定义了Windows设备无关位图(DIB)的度量和颜色信息。
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFO
{
/// <summary>
/// 指定了一个BITMAPINFOHEADER结构,包含了有关设备相关位图的度量和颜色格式的信息。
/// </summary>
[MarshalAs(UnmanagedType.Struct, SizeConst = 40)]
public BITMAPINFOHEADER bmiHeader;
/// <summary>
/// 指定了一个RGBQUAD或DWORD数据类型的数组,定义了位图中的颜色。
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public Int32[] bmiColors;
}
#endregion
#region 属性
private IntPtr lwndC; // 保存无符号句柄
private IntPtr mControlPtr; //保存管理指示器 用于显示视频内容的控件地址指针
private int mWidth;
private int mHeight;
//委托 祯 回调事件定义
public delegate void RecievedFrameEventHandler(byte[] data);
public event RecievedFrameEventHandler RecievedFrame;
private FrameEventHandler mFrameEventHandler; // Delegate instance for the frame callback - must keep alive! gc should NOT collect it
#endregion
/// <summary>
/// 构造方法
/// </summary>
/// <param name="handle">显示视频控件的句柄</param>
/// <param name="width">视频宽度</param>
/// <param name="height">视频高度</param>
public AviCap(IntPtr handle, int width, int height)
{
mControlPtr = handle;
mWidth = width;
mHeight = height;
}
#region 静态方法
public static object GetStructure(IntPtr ptr, ValueType structure)
{
return Marshal.PtrToStructure(ptr, structure.GetType());
}
public static object GetStructure(int ptr, ValueType structure)
{
return GetStructure(new IntPtr(ptr), structure);
}
public static void Copy(IntPtr ptr, byte[] data)
{
Marshal.Copy(ptr, data, 0, data.Length);
}
public static void Copy(int ptr, byte[] data)
{
Copy(new IntPtr(ptr), data);
}
public static int SizeOf(object structure)
{
return Marshal.SizeOf(structure);
}
#endregion
//开启摄像头方法
public void StartWebCam()
{
byte[] lpszName = new byte[100];//名字
byte[] lpszVer = new byte[100];//版本号
AviCap.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);
this.lwndC = AviCap.capCreateCaptureWindowA(lpszName, WS_VISIBLE + WS_CHILD, 0, 0, mWidth, mHeight, mControlPtr, 0);
if (this.DriverConnect(0))
{
this.PreviewRate(66);
this.Preview(true);
BITMAPINFO bitmapinfo = new BITMAPINFO();
bitmapinfo.bmiHeader.biSize = AviCap.SizeOf(bitmapinfo.bmiHeader);
//bitmapinfo.bmiHeader.biWidth = 352;
//bitmapinfo.bmiHeader.biHeight = 288;
bitmapinfo.bmiHeader.biWidth = mWidth;
bitmapinfo.bmiHeader.biHeight = mHeight;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 24;
//this.SetVideoFormat(ref bitmapinfo, AviCap.SizeOf(bitmapinfo));
//this.mFrameEventHandler = new AviCap.FrameEventHandler(FrameCallBack);
this.SetCallbackOnFrame(this.mFrameEventHandler);
AviCap.SetWindowPos(this.lwndC, 0, 0, 0, mWidth, mHeight, 6);
}
//byte[] lpszName = new byte[100];
//byte[] lpszVer = new byte[100];
//VideoAPI.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);
//this.lwndC = VideoAPI.capCreateCaptureWindowA(lpszName, VideoAPI.WS_CHILD | VideoAPI.WS_VISIBLE, 0, 0, mWidth, mHeight, mControlPtr, 0);
//if (VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_DRIVER_CONNECT, 0, 0))
//{
// VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEWRATE, 100, 0);
// VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEW, true, 0);
//}
}
//关闭摄像头方法
public void CloseWebcam()
{
this.DriverDisconnect();
}
/// <summary>
/// 拍照
/// </summary>
/// <param name="path">BMP路由</param>
public void GrabImage(string path)
{
IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);
SendMessage(this.lwndC, WM_CAP_SAVEDIB, 0, hBmp.ToInt32());
}
public bool DriverConnect(short nCameraID)
{
return SendMessage(this.lwndC, WM_CAP_DRIVER_CONNECT, nCameraID, 0);
}
/// <summary>
/// 驱动断开
/// </summary>
/// <param name="lwnd"></param>
/// <returns></returns>
public bool DriverDisconnect()
{
return SendMessage(this.lwndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
}
/// <summary>
/// 预览
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public bool Preview(bool f)
{
return SendMessage(this.lwndC, WM_CAP_SET_PREVIEW, f, 0);
}
/// <summary>
/// 设置预览比例
/// </summary>
/// <param name="wMS"></param>
/// <returns></returns>
public bool PreviewRate(short wMS)
{
return SendMessage(this.lwndC, WM_CAP_SET_PREVIEWRATE, wMS, 0);
}
/// <summary>
/// 设置回调事件
/// </summary>
private bool SetCallbackOnFrame(FrameEventHandler lpProc)
{
return SendMessage(this.lwndC, WM_CAP_SET_CALLBACK_FRAME, 0, lpProc);
}
/// <summary>
/// 设置视频格式
/// </summary>
/// <param name="hCapWnd"></param>
/// <param name="BmpFormat"></param>
/// <param name="CapFormatSize"></param>
/// <returns></returns>
public bool SetVideoFormat(ref BITMAPINFO BmpFormat, int CapFormatSize)
{
return SendMessage(this.lwndC, WM_CAP_SET_VIDEOFORMAT, CapFormatSize, ref BmpFormat);
}
private void FrameCallBack(IntPtr lwnd, IntPtr lpVHdr)
{
VIDEOHDR videoHeader = new VIDEOHDR();
byte[] VideoData;
videoHeader = (VIDEOHDR)GetStructure(lpVHdr, videoHeader);
VideoData = new byte[videoHeader.dwBytesUsed];
Copy(videoHeader.lpData, VideoData);
if (this.RecievedFrame != null)
this.RecievedFrame(VideoData);
}
}
//}
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
//namespace AviCap
//{
public class AviCap
{
#region 外部方法
[DllImport("avicap32.dll")]
public static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, int nID);
[DllImport("avicap32.dll")]
public static extern bool capGetDriverDescriptionA(short wDriver, byte[] lpszName, int cbName, byte[] lpszVer, int cbVer);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, int lParam);
public delegate void FrameEventHandler(IntPtr lwnd, IntPtr lpVHdr);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, FrameEventHandler lParam);
[DllImport("User32.dll")]
public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref BITMAPINFO lParam);
/// <summary>
/// 该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。
/// </summary>
[DllImport("User32.dll")]
public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
[DllImport("avicap32.dll")]
public static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize);
#endregion
#region 消息常量(向窗口发送消息的指令)
//消息常量 --------------------------------------------
public const int WM_START = 0x400; //此并非摄像头消息0x400表示的就是1024
public const int WS_CHILD = 0x40000000;
public const int WS_VISIBLE = 0x10000000;
public const int SWP_NOMOVE = 0x2;
public const int SWP_NOZORDER = 0x4;
public const int WM_CAP_GET_CAPSTREAMPTR = WM_START + 1;
public const int WM_CAP_SET_CALLBACK_ERROR = WM_START + 2;//设置收回错误
public const int WM_CAP_SET_CALLBACK_STATUS = WM_START + 3;//设置收回状态
public const int WM_CAP_SET_CALLBACK_YIELD = WM_START + 4;//设置收回出产
public const int WM_CAP_SET_CALLBACK_FRAME = WM_START + 5;//设置收回结构
public const int WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_START + 6;//设置收回视频流
public const int WM_CAP_SET_CALLBACK_WAVESTREAM = WM_START + 7;//设置收回视频波流
public const int WM_CAP_GET_USER_DATA = WM_START + 8;//获得使用者数据
public const int WM_CAP_SET_USER_DATA = WM_START + 9;//设置使用者数据
public const int WM_CAP_DRIVER_CONNECT = WM_START + 10;//驱动程序连接
public const int WM_CAP_DRIVER_DISCONNECT = WM_START + 11;//断开启动程序连接
public const int WM_CAP_DRIVER_GET_NAME = WM_START + 12;//获得驱动程序名字
public const int WM_CAP_DRIVER_GET_VERSION = WM_START + 13;//获得驱动程序版本
public const int WM_CAP_DRIVER_GET_CAPS = WM_START + 14;//获得驱动程序帽子
public const int WM_CAP_FILE_SET_CAPTURE_FILE = WM_START + 20;//设置捕获文件
public const int WM_CAP_FILE_GET_CAPTURE_FILE = WM_START + 21;//获得捕获文件
public const int WM_CAP_FILE_ALLOCATE = WM_START + 22;//分派文件
public const int WM_CAP_FILE_SAVEAS = WM_START + 23;//另存文件为
public const int WM_CAP_FILE_SET_INFOCHUNK = WM_START + 24;//设置开始文件
public const int WM_CAP_FILE_SAVEDIB = WM_START + 25;//保存文件
public const int WM_CAP_EDIT_COPY = WM_START + 30;//编辑复制
public const int WM_CAP_SET_AUDIOFORMAT = WM_START + 35;//设置音频格式
public const int WM_CAP_GET_AUDIOFORMAT = WM_START + 36;//捕获音频格式
public const int WM_CAP_DLG_VIDEOFORMAT = WM_START + 41;//1065 打开视频格式设置对话框
public const int WM_CAP_DLG_VIDEOSOURCE = WM_START + 42;//1066 打开属性设置对话框,设置对比度亮度等
public const int WM_CAP_DLG_VIDEODISPLAY = WM_START + 43;//1067 打开视频显示
public const int WM_CAP_GET_VIDEOFORMAT = WM_START + 44;//1068 获得视频格式
public const int WM_CAP_SET_VIDEOFORMAT = WM_START + 45;//1069 设置视频格式
public const int WM_CAP_DLG_VIDEOCOMPRESSION = WM_START + 46;//1070 打开压缩设置对话框
public const int WM_CAP_SET_PREVIEW = WM_START + 50;//设置预览
public const int WM_CAP_SET_OVERLAY = WM_START + 51;//设置覆盖
public const int WM_CAP_SET_PREVIEWRATE = WM_START + 52;//设置预览比例
public const int WM_CAP_SET_SCALE = WM_START + 53;//设置刻度
public const int WM_CAP_GET_STATUS = WM_START + 54;//获得状态
public const int WM_CAP_SET_SCROLL = WM_START + 55;//设置卷
public const int WM_CAP_GRAB_FRAME = WM_START + 60;//逮捕结构
public const int WM_CAP_GRAB_FRAME_NOSTOP = WM_START + 61;//停止逮捕结构
public const int WM_CAP_SEQUENCE = WM_START + 62;//次序
public const int WM_CAP_SEQUENCE_NOFILE = WM_START + 63;//使用WM_CAP_SEUENCE_NOFILE消息(capCaptureSequenceNoFile宏),可以不向磁盘文件写入数据。该消息仅在配合回调函数时有用,它允许你的应用程序直接使用音视频数据。
public const int WM_CAP_SET_SEQUENCE_SETUP = WM_START + 64;//设置安装次序
public const int WM_CAP_GET_SEQUENCE_SETUP = WM_START + 65;//获得安装次序
public const int WM_CAP_SET_MCI_DEVICE = WM_START + 66;//设置媒体控制接口
public const int WM_CAP_GET_MCI_DEVICE = WM_START + 67;//获得媒体控制接口
public const int WM_CAP_STOP = WM_START + 68;//停止
public const int WM_CAP_ABORT = WM_START + 69;//异常中断
public const int WM_CAP_SINGLE_FRAME_OPEN = WM_START + 70;//打开单一的结构
public const int WM_CAP_SINGLE_FRAME_CLOSE = WM_START + 71;//关闭单一的结构
public const int WM_CAP_SINGLE_FRAME = WM_START + 72;//单一的结构
public const int WM_CAP_PAL_OPEN = WM_START + 80;//打开视频
public const int WM_CAP_PAL_SAVE = WM_START + 81;//保存视频
public const int WM_CAP_PAL_PASTE = WM_START + 82;//粘贴视频
public const int WM_CAP_PAL_AUTOCREATE = WM_START + 83; //自动创造
public const int WM_CAP_PAL_MANUALCREATE = WM_START + 84;//手动创造
public const int WM_CAP_SET_CALLBACK_CAPCONTROL = WM_START + 85;// 设置收回的错误
//其它
public const int WM_CAP_SAVEDIB = WM_CAP_START + 25;
public const int WM_USER = 0x400;//1024
public const int WM_CAP_START = WM_USER;
public const int WM_CAP_UNICODE_START = WM_USER + 100; //开始
public const int WM_CAP_GRAB_FRame = (WM_CAP_START + 60); //逮捕结构
public const int WM_CAP_GRAB_FRame_NOSTOP = (WM_CAP_START + 61); //停止逮捕结构
public const int WM_CAP_SINGLE_FRame_OPEN = (WM_CAP_START + 70); //打开单一的结构
public const int WM_CAP_SINGLE_FRame_CLOSE = (WM_CAP_START + 71); //关闭单一的结构
public const int WM_CAP_SINGLE_FRame = (WM_CAP_START + 72); //单一的结构
// Following added post VFW 1.1
public const int WM_CAP_END = WM_CAP_SET_CALLBACK_CAPCONTROL;
#endregion
#region 结构体
[StructLayout(LayoutKind.Sequential)]
public struct VIDEOHDR
{
[MarshalAs(UnmanagedType.I4)]
public int lpData;
[MarshalAs(UnmanagedType.I4)]
public int dwBufferLength;
[MarshalAs(UnmanagedType.I4)]
public int dwBytesUsed;
[MarshalAs(UnmanagedType.I4)]
public int dwTimeCaptured;
[MarshalAs(UnmanagedType.I4)]
public int dwUser;
[MarshalAs(UnmanagedType.I4)]
public int dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
[MarshalAs(UnmanagedType.I4)]
public Int32 biSize;
[MarshalAs(UnmanagedType.I4)]
public Int32 biWidth;
[MarshalAs(UnmanagedType.I4)]
public Int32 biHeight;
[MarshalAs(UnmanagedType.I2)]
public short biPlanes;
[MarshalAs(UnmanagedType.I2)]
public short biBitCount;
[MarshalAs(UnmanagedType.I4)]
public Int32 biCompression;
[MarshalAs(UnmanagedType.I4)]
public Int32 biSizeImage;
[MarshalAs(UnmanagedType.I4)]
public Int32 biXPelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public Int32 biYPelsPerMeter;
[MarshalAs(UnmanagedType.I4)]
public Int32 biClrUsed;
[MarshalAs(UnmanagedType.I4)]
public Int32 biClrImportant;
}
#region BITMAPINFO结构
//BITMAPINFO结构具有如下形式:
//typedef struct tagBITMAPINFO
//{
// BITMAPINFOHEADER bmiHeader;
// RGBQUAD bmiColors[1];
//} BITMAPINFO;
//BITMAPINFO结构定义了Windows设备无关位图(DIB)的度量和颜色信息。
//成员:
//bmiHeader 指定了一个BITMAPINFOHEADER结构,包含了有关设备相关位图的度量和颜色格式的信息。
//bmiColors 指定了一个RGBQUAD或DWORD数据类型的数组,定义了位图中的颜色。
//注释:
//设备无关位图由两个部分组成:
//(1) 一个BITMAPINFO结构,描述了位图的度量和颜色信息;
//(2) 一个字节数组,定义了位图的像素。数组中的字节被组合在一起,但是每个扫描行必须用零填补,在一个LONG边界结束。如果高度为正的,位图的起始位置在左下角。如果高度为负,起始位置在左上角。
//(3) BITMAPINFOHEADER结构中的biBitCount成员决定了定义像素的位数以及位图中的最大颜色数。这个成员可以是下列值之一:
//· 位图是单色的,bmiColors成员包含两个入口。位图数组中的每一位代表一个像素。如果该位被清除,则用bmiColors表中的第一种颜色显示该像素。如果该位被置位,则用表中的第二种颜色显示该像素。
//· 位图最多有16种颜色,bmiColors成员中包含了最多可达16个入口。位图中的每个像素用一个4位的值来表示,该值用作颜色表的索引。例如,如果位图中的第一个字节是0x1F,这个字节代表两个像素。第一个像素包含了颜色表中第二种颜色,第二个像素包含了颜色表中第十六种颜色。
//· 位图最多有256种颜色,bmiColors成员包含了多达256个入口。在这种情况下,数组中的每个字节代表一个像素。
//· 位图最多有216种颜色。BITMAPINFOHEADER的biCompression成员必须是BI_BITFIELDS。bmiColors成员包含了3个DWORD型颜色掩码,分别代表了每个像素中的红,绿和蓝色成分。DWORD型掩码中的位必须是连续的,不能与其它掩码重叠。并非像素中的所有位都必须被使用。数组中的每个WORD值代表一个像素。
//· 位图最多具有224种颜色,bmiColors成员为NULL。位图数组中的每个三字节组合分别代表像素中蓝,绿红的深度。
//· 位图中最多具有232种颜色。BITMAPINFOHEADER中的biCompression成员必须是BI_BITFIELDS。bmiColors成员中包含了三个DWORD颜色掩码,分别指定了像素的红,绿和蓝成分。DWORD掩码中的位必须是连续的,并且不能与其它掩码重叠。并非像素中的所有位都必须被使用。数组中的每个DWORD值代表一个像素。
//BITMAPINFOHEADER结构中的biClrUsed成员指定了颜色表中实际使用的索引的数目。如果biClrUsed成员被设为0,位图将使用biBitCount成员中指定的最大颜色数。
//bmiColors表中的颜色应当按照其重要性的顺序出现。另一种情况是,对于使用DIB函数,bmiColors成员可以是一个16位无符号整数的数组,指定了当前实现的逻辑调色板中的索引,而不是确切的RGB值。在这种情况下,使用位图的应用程序必须调用Windows的DIB函数(CreateDIBitmap,CreateDIBPatternBrush和CreateDIBSection),iUsage参数应被设为DIB_PAL_COLORS。
//如果位图是一个压缩位图(这意味着,这种位图的数组直接跟在一个指针所引用的BITMAPINFO头的后面),在使用DIB_PAL_COLORS模式的时候,biClrUsed成员必须被设为偶数,以便使DIB位图数组从DWORD边界开始。
//注意:
//如果位图被保存在文件中,或者要被传送到另一个应用程序,bmiColors成员不能包含调色板索引。除非应用程序独占地使用和控制位图,位图的颜色表中应当包含准确的RGB值。
#endregion
/// <summary>
/// BITMAPINFO结构定义了Windows设备无关位图(DIB)的度量和颜色信息。
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFO
{
/// <summary>
/// 指定了一个BITMAPINFOHEADER结构,包含了有关设备相关位图的度量和颜色格式的信息。
/// </summary>
[MarshalAs(UnmanagedType.Struct, SizeConst = 40)]
public BITMAPINFOHEADER bmiHeader;
/// <summary>
/// 指定了一个RGBQUAD或DWORD数据类型的数组,定义了位图中的颜色。
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public Int32[] bmiColors;
}
#endregion
#region 属性
private IntPtr lwndC; // 保存无符号句柄
private IntPtr mControlPtr; //保存管理指示器 用于显示视频内容的控件地址指针
private int mWidth;
private int mHeight;
//委托 祯 回调事件定义
public delegate void RecievedFrameEventHandler(byte[] data);
public event RecievedFrameEventHandler RecievedFrame;
private FrameEventHandler mFrameEventHandler; // Delegate instance for the frame callback - must keep alive! gc should NOT collect it
#endregion
/// <summary>
/// 构造方法
/// </summary>
/// <param name="handle">显示视频控件的句柄</param>
/// <param name="width">视频宽度</param>
/// <param name="height">视频高度</param>
public AviCap(IntPtr handle, int width, int height)
{
mControlPtr = handle;
mWidth = width;
mHeight = height;
}
#region 静态方法
public static object GetStructure(IntPtr ptr, ValueType structure)
{
return Marshal.PtrToStructure(ptr, structure.GetType());
}
public static object GetStructure(int ptr, ValueType structure)
{
return GetStructure(new IntPtr(ptr), structure);
}
public static void Copy(IntPtr ptr, byte[] data)
{
Marshal.Copy(ptr, data, 0, data.Length);
}
public static void Copy(int ptr, byte[] data)
{
Copy(new IntPtr(ptr), data);
}
public static int SizeOf(object structure)
{
return Marshal.SizeOf(structure);
}
#endregion
//开启摄像头方法
public void StartWebCam()
{
byte[] lpszName = new byte[100];//名字
byte[] lpszVer = new byte[100];//版本号
AviCap.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);
this.lwndC = AviCap.capCreateCaptureWindowA(lpszName, WS_VISIBLE + WS_CHILD, 0, 0, mWidth, mHeight, mControlPtr, 0);
if (this.DriverConnect(0))
{
this.PreviewRate(66);
this.Preview(true);
BITMAPINFO bitmapinfo = new BITMAPINFO();
bitmapinfo.bmiHeader.biSize = AviCap.SizeOf(bitmapinfo.bmiHeader);
//bitmapinfo.bmiHeader.biWidth = 352;
//bitmapinfo.bmiHeader.biHeight = 288;
bitmapinfo.bmiHeader.biWidth = mWidth;
bitmapinfo.bmiHeader.biHeight = mHeight;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 24;
//this.SetVideoFormat(ref bitmapinfo, AviCap.SizeOf(bitmapinfo));
//this.mFrameEventHandler = new AviCap.FrameEventHandler(FrameCallBack);
this.SetCallbackOnFrame(this.mFrameEventHandler);
AviCap.SetWindowPos(this.lwndC, 0, 0, 0, mWidth, mHeight, 6);
}
//byte[] lpszName = new byte[100];
//byte[] lpszVer = new byte[100];
//VideoAPI.capGetDriverDescriptionA(0, lpszName, 100, lpszVer, 100);
//this.lwndC = VideoAPI.capCreateCaptureWindowA(lpszName, VideoAPI.WS_CHILD | VideoAPI.WS_VISIBLE, 0, 0, mWidth, mHeight, mControlPtr, 0);
//if (VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_DRIVER_CONNECT, 0, 0))
//{
// VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEWRATE, 100, 0);
// VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SET_PREVIEW, true, 0);
//}
}
//关闭摄像头方法
public void CloseWebcam()
{
this.DriverDisconnect();
}
/// <summary>
/// 拍照
/// </summary>
/// <param name="path">BMP路由</param>
public void GrabImage(string path)
{
IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);
SendMessage(this.lwndC, WM_CAP_SAVEDIB, 0, hBmp.ToInt32());
}
public bool DriverConnect(short nCameraID)
{
return SendMessage(this.lwndC, WM_CAP_DRIVER_CONNECT, nCameraID, 0);
}
/// <summary>
/// 驱动断开
/// </summary>
/// <param name="lwnd"></param>
/// <returns></returns>
public bool DriverDisconnect()
{
return SendMessage(this.lwndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
}
/// <summary>
/// 预览
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public bool Preview(bool f)
{
return SendMessage(this.lwndC, WM_CAP_SET_PREVIEW, f, 0);
}
/// <summary>
/// 设置预览比例
/// </summary>
/// <param name="wMS"></param>
/// <returns></returns>
public bool PreviewRate(short wMS)
{
return SendMessage(this.lwndC, WM_CAP_SET_PREVIEWRATE, wMS, 0);
}
/// <summary>
/// 设置回调事件
/// </summary>
private bool SetCallbackOnFrame(FrameEventHandler lpProc)
{
return SendMessage(this.lwndC, WM_CAP_SET_CALLBACK_FRAME, 0, lpProc);
}
/// <summary>
/// 设置视频格式
/// </summary>
/// <param name="hCapWnd"></param>
/// <param name="BmpFormat"></param>
/// <param name="CapFormatSize"></param>
/// <returns></returns>
public bool SetVideoFormat(ref BITMAPINFO BmpFormat, int CapFormatSize)
{
return SendMessage(this.lwndC, WM_CAP_SET_VIDEOFORMAT, CapFormatSize, ref BmpFormat);
}
private void FrameCallBack(IntPtr lwnd, IntPtr lpVHdr)
{
VIDEOHDR videoHeader = new VIDEOHDR();
byte[] VideoData;
videoHeader = (VIDEOHDR)GetStructure(lpVHdr, videoHeader);
VideoData = new byte[videoHeader.dwBytesUsed];
Copy(videoHeader.lpData, VideoData);
if (this.RecievedFrame != null)
this.RecievedFrame(VideoData);
}
}
//}