c# 呼叫攝像頭進行視訊錄製和壓縮等
阿新 • • 發佈:2019-02-15
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; using System.IO; namespace Basic { public class VideoAPI //視訊API類 { // 視訊API呼叫 [DllImport("avicap32.dll")]//包含了執行視訊捕獲的函式,它給AVI檔案I/O和視訊、音訊裝置驅動程式提供一個高階介面 public static extern IntPtr capCreateCaptureWindow(string lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hwndParent, int nID); [DllImport("AVICAP32.dll", CharSet = CharSet.Unicode)] public static extern bool capGetDriverDescription(int wDriverIndex, StringBuilder lpszName, int cbName, StringBuilder lpszVer, int cbVer); [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); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); [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); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPDRIVERCAPS lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPTUREPARMS lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPSTATUS lParam); [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); // 常量 // public const int WM_USER = 0x400; 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_DRIVER_CONNECT = WM_USER + 10; // public const int WM_CAP_DRIVER_DISCONNECT = WM_USER + 11; public const int WM_CAP_SET_CALLBACK_FRAME = WM_USER + 5; // public const int WM_CAP_SET_PREVIEW = WM_USER + 50; // public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52; // public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45; // public const int WM_CAP_START = WM_USER; public const int WM_CAP_SAVEDIB = WM_CAP_START + 25; public const string avicap32 = "avicap32.dll"; public const int WM_USER = 1024; /// <summary> ///WM_CAP_START=WM_USER=1024 /// </summary> public const int WM_CAP_START = WM_USER; // start of unicode messages /// <summary> /// 開始 WM_USER + 100=1124 /// </summary> public const int WM_CAP_UNICODE_START = WM_USER + 100; //開始 1124 /// <summary> /// /獲得 CAPSTR EAMPTR /// WM_CAP_START + 1=1025 /// </summary> public const int WM_CAP_GET_CAPSTREAMPTR = (WM_CAP_START + 1); //獲得 CAPSTR EAMPTR /// <summary> /// 設定收回錯誤 WM_CAP_START + 2=1026 /// </summary> public const int WM_CAP_SET_CALLBACK_ERROR = (WM_CAP_START + 2); //設定收回錯誤 /// <summary> /// 設定收回狀態 WM_CAP_START + 3=1027 /// </summary> public const int WM_CAP_SET_CALLBACK_STATUS = (WM_CAP_START + 3); //設定收回狀態 /// <summary> /// 設定收回出產 WM_CAP_START + 4=1028 /// </summary> public const int WM_CAP_SET_CALLBACK_YIELD = (WM_CAP_START + 4); //設定收回出產 /// <summary> /// 設定收回結構 WM_CAP_START + 5=1029 /// </summary> public const int WM_CAP_SET_CALLBACK_FRame = (WM_CAP_START + 5); //設定收回結構 /// <summary> /// 設定收回視訊流 WM_CAP_START + 6=1030 /// </summary> public const int WM_CAP_SET_CALLBACK_VIDEOSTREAM = (WM_CAP_START + 6); //設定收回視訊流 /// <summary> /// 設定收回視訊波流 WM_CAP_START +7=1031 /// </summary> public const int WM_CAP_SET_CALLBACK_WAVESTREAM = (WM_CAP_START + 7); //設定收回視訊波流 /// <summary> /// 獲得使用者資料 WM_CAP_START + 8=1032 /// </summary> public const int WM_CAP_GET_USER_DATA = (WM_CAP_START + 8); //獲得使用者資料 /// <summary> /// 設定使用者資料 WM_CAP_START + 9=1033 /// </summary> public const int WM_CAP_SET_USER_DATA = (WM_CAP_START + 9); //設定使用者資料 /// <summary> /// 驅動程式連線 WM_CAP_START + 10=1034 /// </summary> public const int WM_CAP_DRIVER_CONNECT = (WM_CAP_START + 10); //驅動程式連線 /// <summary> /// 斷開啟動程式連線 WM_CAP_START + 11=1035 /// </summary> public const int WM_CAP_DRIVER_DISCONNECT = (WM_CAP_START + 11); //斷開啟動程式連線 /// <summary> /// 獲得驅動程式名字 WM_CAP_START + 12=1036 /// </summary> public const int WM_CAP_DRIVER_GET_NAME = (WM_CAP_START + 12); //獲得驅動程式名字 /// <summary> /// 獲得驅動程式版本 WM_CAP_START + 13=1037 /// </summary> public const int WM_CAP_DRIVER_GET_VERSION = (WM_CAP_START + 13); //獲得驅動程式版本 /// <summary> /// 獲得驅動程式帽子 WM_CAP_START + 14=1038 /// </summary> public const int WM_CAP_DRIVER_GET_CAPS = (WM_CAP_START + 14); //獲得驅動程式帽子 /// <summary> /// 設定捕獲檔案 WM_CAP_START + 20=1044 /// </summary> public const int WM_CAP_FILE_SET_CAPTURE_FILE = (WM_CAP_START + 20); //設定捕獲檔案 /// <summary> /// 獲得捕獲檔案 WM_CAP_START + 21=1045 /// </summary> public const int WM_CAP_FILE_GET_CAPTURE_FILE = (WM_CAP_START + 21); //獲得捕獲檔案 /// <summary> /// 另存檔案為 WM_CAP_START + 23=1047 /// </summary> public const int WM_CAP_FILE_SAVEAS = (WM_CAP_START + 23); //另存檔案為 /// <summary> /// 儲存檔案 WM_CAP_START + 25=1049 /// </summary> public const int WM_CAP_FILE_SAVEDIB = (WM_CAP_START + 25); //儲存檔案 // out of order to save on ifdefs /// <summary> /// 分派檔案 WM_CAP_START + 22=1044 /// </summary> public const int WM_CAP_FILE_ALLOCATE = (WM_CAP_START + 22); //分派檔案 /// <summary> /// 設定開始檔案 WM_CAP_START + 24=1046 /// </summary> public const int WM_CAP_FILE_SET_INFOCHUNK = (WM_CAP_START + 24); //設定開始檔案 /// <summary> /// 編輯複製 WM_CAP_START + 30=1054 /// </summary> public const int WM_CAP_EDIT_COPY = (WM_CAP_START + 30); //編輯複製 /// <summary> /// 設定音訊格式 WM_CAP_START + 35=1059 /// </summary> public const int WM_CAP_SET_AUDIOFORMAT = (WM_CAP_START + 35); //設定音訊格式 /// <summary> /// 捕獲音訊格式 WM_CAP_START + 36=1060 /// </summary> public const int WM_CAP_GET_AUDIOFORMAT = (WM_CAP_START + 36); //捕獲音訊格式 /// <summary> /// 開啟視訊格式設定對話方塊 WM_CAP_START + 41=1065 /// </summary> public const int WM_CAP_DLG_VIDEOFORMAT = (WM_CAP_START + 41); //1065 開啟視訊格式設定對話方塊 /// <summary> /// 開啟屬性設定對話方塊,設定對比度、亮度等 WM_CAP_START + 42=1066 /// </summary> public const int WM_CAP_DLG_VIDEOSOURCE = (WM_CAP_START + 42); //1066 開啟屬性設定對話方塊,設定對比度、亮度等。 /// <summary> /// 開啟視訊顯示 WM_CAP_START + 43=1067 /// </summary> public const int WM_CAP_DLG_VIDEODISPLAY = (WM_CAP_START + 43); //1067 開啟視訊顯示 /// <summary> /// 獲得視訊格式 WM_CAP_START + 44=1068 /// </summary> public const int WM_CAP_GET_VIDEOFORMAT = (WM_CAP_START + 44); //1068 獲得視訊格式 /// <summary> /// 設定視訊格式 WM_CAP_START + 45=1069 /// </summary> public const int WM_CAP_SET_VIDEOFORMAT = (WM_CAP_START + 45); //1069 設定視訊格式 /// <summary> /// 開啟壓縮設定對話方塊 WM_CAP_START + 46=1070 /// </summary> public const int WM_CAP_DLG_VIDEOCOMPRESSION = (WM_CAP_START + 46); //1070 開啟壓縮設定對話方塊 /// <summary> /// 設定預覽 WM_CAP_START + 50=1074 /// </summary> public const int WM_CAP_SET_PREVIEW = (WM_CAP_START + 50); //設定預覽 /// <summary> /// 設定覆蓋 WM_CAP_START + 51=1075 /// </summary> public const int WM_CAP_SET_OVERLAY = (WM_CAP_START + 51); //設定覆蓋 /// <summary> /// 設定預覽比例 WM_CAP_START + 52=1076 /// </summary> public const int WM_CAP_SET_PREVIEWRATE = (WM_CAP_START + 52); //設定預覽比例 /// <summary> /// 設定刻度 WM_CAP_START + 53=1077 /// </summary> public const int WM_CAP_SET_SCALE = (WM_CAP_START + 53); //設定刻度 /// <summary> /// 獲得狀態 WM_CAP_START + 54=1078 /// </summary> public const int WM_CAP_GET_STATUS = (WM_CAP_START + 54); //獲得狀態 /// <summary> /// 設定卷 WM_CAP_START + 55=1079 /// </summary> public const int WM_CAP_SET_SCROLL = (WM_CAP_START + 55); //設定卷 /// <summary> /// 逮捕結構 WM_CAP_START + 60=1084 /// </summary> public const int WM_CAP_GRAB_FRame = (WM_CAP_START + 60); //逮捕結構 /// <summary> /// 停止逮捕結構 WM_CAP_START + 61=1085 /// </summary> public const int WM_CAP_GRAB_FRame_NOSTOP = (WM_CAP_START + 61); //停止逮捕結構 /// <summary> /// 次序 WM_CAP_START + 62=1086 /// </summary> public const int WM_CAP_SEQUENCE = (WM_CAP_START + 62); //次序 /// <summary> /// 沒有檔案 WM_CAP_START + 63=1087 /// </summary> public const int WM_CAP_SEQUENCE_NOFILE = (WM_CAP_START + 63); //沒有檔案 /// <summary> /// 設定安裝次序 WM_CAP_START + 64=1088 /// </summary> public const int WM_CAP_SET_SEQUENCE_SETUP = (WM_CAP_START + 64); //設定安裝次序 /// <summary> /// 獲得安裝次序 WM_CAP_START + 65=1089 /// </summary> public const int WM_CAP_GET_SEQUENCE_SETUP = (WM_CAP_START + 65); //獲得安裝次序 /// <summary> /// 設定媒體控制介面 WM_CAP_START + 66=1090 /// </summary> public const int WM_CAP_SET_MCI_DEVICE = (WM_CAP_START + 66); //設定媒體控制介面 /// <summary> /// 獲得媒體控制介面 WM_CAP_START + 67=1091 /// </summary> public const int WM_CAP_GET_MCI_DEVICE = (WM_CAP_START + 67); //獲得媒體控制介面 /// <summary> /// 停止 WM_CAP_START + 68=1092 /// </summary> public const int WM_CAP_STOP = (WM_CAP_START + 68); //停止 /// <summary> /// 異常中斷 WM_CAP_START + 69=1093 /// </summary> public const int WM_CAP_ABORT = (WM_CAP_START + 69); //異常中斷 /// <summary> /// 開啟單一的結構 WM_CAP_START + 68=1094 /// </summary> public const int WM_CAP_SINGLE_FRame_OPEN = (WM_CAP_START + 70); //開啟單一的結構 /// <summary> /// 關閉單一的結構 WM_CAP_START + 71=1095 /// </summary> public const int WM_CAP_SINGLE_FRame_CLOSE = (WM_CAP_START + 71); //關閉單一的結構 /// <summary> /// 單一的結構 WM_CAP_START + 72=1096 /// </summary> public const int WM_CAP_SINGLE_FRame = (WM_CAP_START + 72); //單一的結構 /// <summary> /// 開啟視訊 WM_CAP_START + 80=1104 /// </summary> public const int WM_CAP_PAL_OPEN = (WM_CAP_START + 80); //開啟視訊 /// <summary> /// 儲存視訊 WM_CAP_START + 81=1105 /// </summary> public const int WM_CAP_PAL_SAVE = (WM_CAP_START + 81); //儲存視訊 /// <summary> /// 貼上視訊 WM_CAP_START + 82=1106 /// </summary> public const int WM_CAP_PAL_PASTE = (WM_CAP_START + 82); //貼上視訊 /// <summary> /// 自動創造 WM_CAP_START + 83=1107 /// </summary> public const int WM_CAP_PAL_AUTOCREATE = (WM_CAP_START + 83); //自動創造 /// <summary> /// 手動創造 WM_CAP_START + 84=1108 /// </summary> public const int WM_CAP_PAL_MANUALCREATE = (WM_CAP_START + 84); //手動創造 // Following added post VFW 1.1 /// <summary> /// 設定收回的錯誤 WM_CAP_START + 85=1109 /// </summary> public const int WM_CAP_SET_CALLBACK_CAPCONTROL = (WM_CAP_START + 85); // 設定收回的錯誤 public const int WM_CAP_END = WM_CAP_SET_CALLBACK_CAPCONTROL; public delegate void FrameEventHandler(IntPtr lwnd, IntPtr lpVHdr); #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 公共函式 #region 結構 VIDEOHDR|BITMAPINFOHEADER|BITMAPINFO|CAPTUREPARMS|CAPDRIVERCAPS|CAPSTATUS //========================================================VideoHdr 結構===================================================================== //VideoHdr 結構 定義了視訊資料塊的頭資訊,在編寫回調函式時常用到其資料成員lpData(指向資料快取的指標)和dwBufferLength(資料快取的大小)。 //視訊幀到快取的捕獲則需要應用回撥函式和相應的資料塊結構 VIDEOHDR [StructLayout(LayoutKind.Sequential)] public struct VIDEOHDR { public IntPtr lpData; /* 指向資料快取的指標 */ public int dwBufferLength; /* 資料快取的大小 */ public int dwBytesUsed; /* Bytes actually used */ public int dwTimeCaptured; /* Milliseconds from start of stream */ public int dwUser; /* for client's use */ public int dwFlags; /* assorted flags (see defines) */ public int dwReserved; /* reserved for driver */ } //=======================================================BitmapInfoHeader結構=================================================================== //BitmapInfoHeader定義了點陣圖的頭部資訊 [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFOHEADER { public int biSize; public int biWidth; public int biHeight; public short biPlanes; public short biBitCount; public int biCompression; public int biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public int biClrUsed; public int biClrImportant; } //========================================================================================================================================= //======================================================BitmapInfo結構===================================================================== //BitmapInfo 點陣圖資訊 [StructLayout(LayoutKind.Sequential)] public struct BITMAPINFO { public BITMAPINFOHEADER bmiHeader; public int bmiColors; } //=====================================================CAPTUREPARMS結構====================================================================== //CAPTUREPARMS 包含控制視訊流捕獲過程的引數,如捕獲幀頻、指定鍵盤或滑鼠鍵以終止捕獲、捕獲時間限制等; [StructLayout(LayoutKind.Sequential)] public struct CAPTUREPARMS { public int dwRequestMicroSecPerFrame; // 期望的楨播放率,以毫秒為單位,預設為66667,相當於15楨每秒。 public bool fMakeUserHitOKToCapture; // Show "Hit OK to cap" dlg?開始捕獲標誌位,如果值為真,則在開始捕獲前要產生一個詢問對話方塊,預設為假。 public uint wPercentDropForError; //所允許的最大丟楨百分比,可以從0變化到100,預設值為10。 public bool fYield; /*另起執行緒標誌位,如果為真,則程式重新啟動一個執行緒用於視訊流的捕獲,預設值是假。 但是如果你是為了真,你必須要在程式中處理一些潛在的操作,因為當視訊捕獲時,其他操作並沒有被遮蔽。*/ public int dwIndexSize; // 在AVI檔案中所允許的最大數目的索引項(32K) public uint wChunkGranularity; // AVI檔案的邏輯尺寸,以位元組為單位。如果值是0,則說明該尺寸漸增 在 Win32程式中無用。(2K) public bool fUsingDOSMemory; // Use DOS buffers? public uint wNumVideoRequested; // 所被允許分配的最大視訊快取 public bool fCaptureAudio; // 音訊標誌位,如果音訊流正在捕獲,則該值為真。 public uint wNumAudioRequested; // 最大數量的音訊快取,預設值為10。 public uint vKeyAbort; // 終止流捕獲的虛擬鍵盤碼,預設值為VK_ESCAPE [MarshalAs(UnmanagedType.Bool)] public bool fAbortLeftMouse; // 終止滑鼠左鍵標誌位,如果該值為真,則在流捕獲過程中如果點選滑鼠左鍵則該捕獲終止,預設值為真。 public bool fAbortRightMouse; // Abort on right mouse? public bool fLimitEnabled; // 捕獲操作時間限制,如果為真,則時間到了以後捕獲操作終止,預設為假 public uint wTimeLimit; // 具體終止時間,只有 fLimitEnabled是真時.該位才有效 public bool fMCIControl; // Use MCI video source? public bool fStepMCIDevice; // Step MCI device?MCI 裝置標誌。 public int dwMCIStartTime; // Time to start in MS public int dwMCIStopTime; // Time to stop in MS public bool fStepCaptureAt2x; // Perform spatial averaging 2x public int wStepCaptureAverageFrames; // 當基於平均取樣來建立楨時,楨的取樣時間,典型值是5 public int dwAudioBufferSize; // 音訊快取的尺寸,如果用預設值0,快取尺寸是最大0.5秒,或10k位元組。 public int fDisableWriteCache; // Attempt to disable write cache public int AVStreamMaster; //音視訊同步標誌。 } //========================================================================================================================================= //=================================================CAPDRIVERCAPS結構======================================================================= //CAPDRIVERCAPS定義了捕獲驅動器的能力,如有無視訊疊加能力、有無控制視訊源、視訊格式的對話方塊等; [StructLayout(LayoutKind.Sequential)] public struct CAPDRIVERCAPS { [MarshalAs(UnmanagedType.U2)] public UInt16 wDeviceIndex; //捕獲驅動器的索引值,該值可以由0到9變化。 [MarshalAs(UnmanagedType.Bool)] public bool fHasOverlay; // 視訊疊加標誌,如果裝置支援視訊疊加這該位是真。 [MarshalAs(UnmanagedType.Bool)] public bool fHasDlgVideoSource; //視訊資源對話方塊標誌位,如果裝置支援視訊選擇、控制對話方塊,該值為真。 [MarshalAs(UnmanagedType.Bool)] public bool fHasDlgVideoFormat; //視訊格式對話方塊標誌位,如果裝置支援對視訊格式對話方塊的選擇,該位真。 [MarshalAs(UnmanagedType.Bool)] public bool fHasDlgVideoDisplay; //視訊展示對話方塊標誌位,如果裝置支援對視訊捕獲快取區的重新播放,該位是真。 [MarshalAs(UnmanagedType.Bool)] public bool fCaptureInitialized; //捕獲安裝標誌位,如果捕獲驅動器已經成功連線,該值為真。 //[MarshalAs(UnmanagedType.Bool)] public bool fDriverSuppliesPalettes; //驅動器調色盤標誌位,如果驅動器能建立調色盤,則該位是真。 [MarshalAs(UnmanagedType.I4)] public int hVideoIn; [MarshalAs(UnmanagedType.I4)] public int hVideoOut; [MarshalAs(UnmanagedType.I4)] public int hVideoExtIn; [MarshalAs(UnmanagedType.I4)] public int hVideoExtOut; } //========================================================================================================================================= //=====================================================CAPSTATUS結構======================================================================== //CAPSTATUS定義了捕獲視窗的當前狀態,如影象的寬、高等; [StructLayout(LayoutKind.Sequential)] public struct CAPSTATUS { public int uiImageWidth; //影象寬度 public int uiImageHeight; //影象高度 public bool fLiveWindow; //活動視窗標記,如果視窗正以預覽的方式展示影象,那麼該值為真 public bool fOverlayWindow; //疊加視窗標誌位,如果正在使用硬體疊加,則該位是真。 public bool fScale; //輸入所放標誌位,如果視窗是正在縮放視訊到客戶區,那麼該位是真。當使用硬體疊加時,改位無效。 public Point ptScroll; //被展示在視窗客戶區左上角的那個象素的x、y座標偏移量。 public bool fUsingDefaultPalette; //預設調色盤標誌位,如果捕獲視窗正在使用當前預設調色盤,該值為真 public bool fAudioHardware; // 音訊硬體標誌位,如果系統已經安裝了音訊硬體,該值為真。 public bool fCapFileExists; //捕獲檔案標誌位,如果一個捕獲檔案已經被建立,該值為真 public int dwCurrentVideoFrame; // 當前或最近流捕獲過程中,所處理的楨的數目。包括丟棄的楨。 public int dwCurrentVideoFramesDropped;//當前流捕獲過程中丟棄的楨的數目。 public int dwCurrentWaveSamples; // # of wave samples cap'td public int dwCurrentTimeElapsedMS; // 從當前流捕獲開始計算,程式所用的時間,以毫秒為單位。 public IntPtr hPalCurrent; // 當前剪下板的控制代碼。 public bool fCapturingNow; // 捕獲標誌位,當捕獲是正在進行時,改位是真 public int dwReturn; // 錯誤返回值,當你的應用程式不支援錯誤回撥函式時可以應用改位 public int wNumVideoAllocated; // 被分配的視訊快取的數目。 public int wNumAudioAllocated; // 被分配的音訊快取的數目。 } //========================================================================================================================================= #endregion 結構 VIDEOHDR|BITMAPINFOHEADER|BITMAPINFO|CAPTUREPARMS|CAPDRIVERCAPS|CAPSTATUS } public class cVideo //視訊類 { public bool flag = true; private IntPtr lwndC; //儲存無符號控制代碼 private IntPtr mControlPtr; //儲存管理指示器 private int mWidth; private int mHeight; public delegate void RecievedFrameEventHandler(byte[] data); public event RecievedFrameEventHandler RecievedFrame; public VideoAPI.CAPTUREPARMS Capparms; private VideoAPI.FrameEventHandler mFrameEventHandler; public VideoAPI.CAPDRIVERCAPS CapDriverCAPS;//捕獲驅動器的能力,如有無視訊疊加能力、有無控制視訊源、視訊格式的對話方塊等; public VideoAPI.CAPSTATUS CapStatus;//該結構用於儲存視訊裝置捕獲視窗的當前狀態,如影象的寬、高等 string strFileName; public cVideo(IntPtr handle, int width, int height) { CapDriverCAPS = new VideoAPI.CAPDRIVERCAPS();//捕獲驅動器的能力,如有無視訊疊加能力、有無控制視訊源、視訊格式的對話方塊等; CapStatus = new VideoAPI.CAPSTATUS();//該結構用於儲存視訊裝置捕獲視窗的當前狀態,如影象的寬、高等 mControlPtr = handle; //顯示視訊控制元件的控制代碼 mWidth = width; //視訊寬度 mHeight = height; //視訊高度 } /// <summary> /// 開啟視訊裝置 /// </summary> public bool StartWebCam() { //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); // return true; //} //else //{ // return false; //} this.lwndC = VideoAPI.capCreateCaptureWindow("", VideoAPI.WS_CHILD | VideoAPI.WS_VISIBLE, 0, 0, mWidth, mHeight, mControlPtr, 0);//AVICap類的捕捉視窗 VideoAPI.FrameEventHandler FrameEventHandler = new VideoAPI.FrameEventHandler(FrameCallback); VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_CALLBACK_ERROR, 0, 0);//註冊錯誤回撥函式 VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_CALLBACK_STATUS, 0, 0);//註冊狀態回撥函式 VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);//註冊視訊流回調函式 VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_CALLBACK_FRAME, 0, FrameEventHandler);//註冊幀回撥函式 //if (!CapDriverCAPS.fCaptureInitialized)//判斷當前裝置是否被其他裝置連線已經連線 //{ if (VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_DRIVER_CONNECT, 0, 0)) { //----------------------------------------------------------------------- VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_DRIVER_GET_CAPS, VideoAPI.SizeOf(CapDriverCAPS), ref CapDriverCAPS);//獲得當前視訊 CAPDRIVERCAPS定義了捕獲驅動器的能力,如有無視訊疊加能力、有無控制視訊源、視訊格式的對話方塊等; VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_GET_STATUS, VideoAPI.SizeOf(CapStatus), ref CapStatus);//獲得當前視訊流的尺寸 存入CapStatus結構 VideoAPI.BITMAPINFO bitmapInfo = new VideoAPI.BITMAPINFO();//設定視訊格式 (height and width in pixels, bits per frame). bitmapInfo.bmiHeader = new VideoAPI.BITMAPINFOHEADER(); bitmapInfo.bmiHeader.biSize = VideoAPI.SizeOf(bitmapInfo.bmiHeader); bitmapInfo.bmiHeader.biWidth = mWidth; bitmapInfo.bmiHeader.biHeight = mHeight; bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 24; VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_PREVIEWRATE, 40, 0);//設定在PREVIEW模式下設定視訊視窗的重新整理率 設定每40毫秒顯示一幀,即顯示幀速為每秒25幀 VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_SCALE, 1, 0);//開啟預覽視訊的縮放比例 VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_VIDEOFORMAT, VideoAPI.SizeOf(bitmapInfo), ref bitmapInfo); this.mFrameEventHandler = new VideoAPI.FrameEventHandler(FrameCallback); this.capSetCallbackOnFrame(this.lwndC, this.mFrameEventHandler); VideoAPI.CAPTUREPARMS captureparms = new VideoAPI.CAPTUREPARMS(); VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_GET_SEQUENCE_SETUP, VideoAPI.SizeOf(captureparms), ref captureparms); if (CapDriverCAPS.fHasOverlay) { VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_OVERLAY, 1, 0);//啟用疊加 注:據說啟用此項可以加快渲染速度 } VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_PREVIEW, 1, 0);//設定顯示影象啟動預覽模式 PREVIEW VideoAPI.SetWindowPos(this.lwndC, 0, 0, 0, mWidth, mHeight, VideoAPI.SWP_NOZORDER | VideoAPI.SWP_NOMOVE);//使捕獲視窗與進來的視訊流尺寸保持一致 return true; } else { flag = false; return false; } } public void get() { VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_GET_SEQUENCE_SETUP, VideoAPI.SizeOf(Capparms), ref Capparms); } public void set() { VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_SEQUENCE_SETUP, VideoAPI.SizeOf(Capparms), ref Capparms); } private bool capSetCallbackOnFrame(IntPtr lwnd, VideoAPI.FrameEventHandler lpProc) { return VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SET_CALLBACK_FRAME, 0, lpProc); } /// <summary> /// 關閉視訊裝置 /// </summary> public void CloseWebcam() { VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_DRIVER_DISCONNECT, 0, 0); } /// <summary> /// 拍照 /// </summary> /// <param name="path">要儲存bmp檔案的路徑</param> public void GrabImage(IntPtr hWndC, string path) { IntPtr hBmp = Marshal.StringToHGlobalAnsi(path); VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_SAVEDIB, 0, hBmp.ToInt32()); } public void StarKinescope(string path) { strFileName = path; string dir=path.Remove(path.LastIndexOf("//")); if (!File.Exists(dir)) { Directory.CreateDirectory(dir); } int hBmp = Marshal.StringToHGlobalAnsi(path).ToInt32(); bool b= VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_FILE_SET_CAPTURE_FILE, 0, hBmp); b= VideoAPI.SendMessage(this.lwndC, VideoAPI.WM_CAP_SEQUENCE, 0, 0); } /// <summary> /// 停止錄影 /// </summary> public void StopKinescope() { VideoAPI.SendMessage(lwndC, VideoAPI.WM_CAP_STOP, 0, 0); } private void FrameCallback(IntPtr lwnd, IntPtr lpvhdr) { VideoAPI.VIDEOHDR videoHeader = new VideoAPI.VIDEOHDR(); byte[] VideoData; videoHeader = (VideoAPI.VIDEOHDR)VideoAPI.GetStructure(lpvhdr, videoHeader); VideoData = new byte[videoHeader.dwBytesUsed]; VideoAPI.Copy(videoHeader.lpData, VideoData); if (this.RecievedFrame != null) this.RecievedFrame(VideoData); } private Thread myThread; public void CompressVideoFfmpeg() { //myThread = new Thread(new ThreadStart(testfn)); //myThread.Start(); testfn(); } private void testfn() // 壓縮視訊 { string file_name = strFileName; string command_line = " -i " + file_name + " -vcodec libx264 -cqp 25 -y " + file_name.Replace(".avi", "_264") + ".avi"; System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.StartInfo.WorkingDirectory = Application.StartupPath; proc.StartInfo.UseShellExecute = false; //use false if you want to hide the window proc.StartInfo.CreateNoWindow = true; proc.StartInfo.FileName = "ffmpeg"; proc.StartInfo.Arguments = command_line; proc.Start(); proc.WaitForExit(); proc.Close(); // 刪除原始avi檔案 FileInfo file = new FileInfo(file_name); if (file.Exists) { try { file.Delete(); //刪除單個檔案 } catch(Exception e) { Common.writeLog("刪除視訊檔案“"+file_name+"”出錯!"+e.Message); } } //myThread.Abort(); } } } 用到的壓縮軟體http://download.csdn.net/source/2453028 呼叫: cVideo video = new cVideo(picCapture.Handle, 640, 480); //開啟視訊 if (video.StartWebCam(320, 240)) { video.get(); video.Capparms.fYield = true; video.Capparms.fAbortLeftMouse = false; video.Capparms.fAbortRightMouse = false; video.Capparms.fCaptureAudio = false; video.Capparms.dwRequestMicroSecPerFrame = 0x9C40; // 設定幀率25fps: 1*1000000/25 = 0x9C40 video.set(); setCap(); VideoStart = true; } //開始錄影 video.StarKinescope(System.IO.Path.Combine(Record.VideoDir, System.DateTime.Now.ToString("yyyy-MM-dd(HH.mm.ss)") + ".avi"))) //停止錄影 video.StopKinescope(); //壓縮(壓縮效率還是很低,不要用於實際開發) video.CompressVideoFfmpeg();