关于 web cam 使用自家的摄像头实现 视频捕捉技术 高级篇


网络上一大堆的视频捕捉代码,比如:

代码
public class WebCameraEngine
    {
        
//  showVideo  calls
        [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, 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 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);

        
//  constants
        public const int WM_USER = 0x400;

        
public const int WS_CHILD = 0x40000000;
        
public const int WS_VISIBLE = 0x10000000;

        
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_START = WM_USER;
        
public const int WM_CAP_STOP = WM_CAP_START + 68;

        
public const int WM_CAP_SAVEDIB = WM_CAP_START + 25;
        
public const int WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
        
public const int WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;
        
public const int WM_CAP_SEQUENCE = WM_CAP_START + 62;
        
public const int WM_CAP_SEQUENCE_NOFILE = WM_CAP_START + 63;


        
public const int WM_CAP_SET_OVERLAY = WM_CAP_START + 51;
        
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_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6;
        
public const int WM_CAP_SET_CALLBACK_ERROR = WM_CAP_START + 2;
        
public const int WM_CAP_SET_CALLBACK_STATUSA = WM_CAP_START + 3;
        
public const int WM_CAP_SET_SCALE = WM_CAP_START + 53;
        
public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45;

        
public const int SWP_NOMOVE = 0x2;
        
public const int SWP_NOZORDER = 0x4;





        
//  Structures
        [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;
        }

        [StructLayout(LayoutKind.Sequential)]
        
public struct BitMapInfo
        {
            [MarshalAs(UnmanagedType.Struct, SizeConst 
= 40)]
            
public BitMapInfoHeader bmiHeader;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst 
= 1024)]
            
public Int32[] bmiColors;
        }

        
public delegate void FrameEventHandler(IntPtr lwnd, IntPtr lpVHdr);

        
//  Public  methods
        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);
        }
    }


但是使用的例子却没有,特别关于视频流的问题。因此我特地查看了msdn。现在把研究过程写下来:

http://msdn.microsoft.com/en-us/library/ms713477(VS.85).aspx

在c#里面的例子,实际上使用了AVICap这个c++的类库。 他的功能包括:

1. 捕捉视频音频到avi文件

2. 动态链接、断开捕捉设备

3. 查看实时的视频信号

4. 设置捕捉率

5. 显示设置对话框、palettes

6. 拷贝图像到剪贴板

7. 对单个图像进行截图+保存为DIB

8.  Specify a file to use when capturing and copy the contents of the capture file to another file.(这个没太理解)

现在对avicap所有方法进行说明:

1.  建立一个捕捉窗口:

代码
hWndC = capCreateCaptureWindow (
    (LPSTR) 
"My Capture Window"// window name if pop-up 
    WS_CHILD | WS_VISIBLE,       // window style 
    00160120,              // window position and dimensions
    (HWND) hwndParent, 
    (
int) nID /* child ID *

2. 链接捕捉设备

代码
fOK = SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 00L); 
// 
// Or, use the macro to connect to the MSVIDEO driver: 
// fOK = capDriverConnect(hWndC, 0); 
// 
// Place code to set up and capture video here. 
// 
capDriverDisconnect (hWndC); 

3. 枚举可以使用的捕捉设备:

char szDeviceName[80];
char szDeviceVersion[80];

for (wIndex = 0; wIndex < 10; wIndex++
{
    
if (capGetDriverDescription(
            wIndex, 
            szDeviceName, 
            
sizeof (szDeviceName), 
            szDeviceVersion, 
            
sizeof (szDeviceVersion)
        )) 
    {
        
// Append name to list of installed capture drivers
        
// and then let the user select a driver to use.
    }

4. 获取捕捉设备的能力

代码
CAPDRIVERCAPS CapDrvCaps; 

SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, 
    
sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDrvCaps); 

// Or, use the macro to retrieve the driver capabilities. 
// capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS)); 

 5. 获取捕捉窗口的状态

 CAPSTATUS CapStatus;


capGetStatus(hWndC, 
&CapStatus, sizeof (CAPSTATUS)); 

SetWindowPos(hWndC, NULL, 
00, CapStatus.uiImageWidth, 
    CapStatus.uiImageHeight, SWP_NOZORDER 
| SWP_NOMOVE)

 6. 显示设置捕捉窗口

 代码

CAPDRIVERCAPS CapDrvCaps; 

capDriverGetCaps(hWndC, 
&CapDrvCaps, sizeof (CAPDRIVERCAPS)); 
 
// Video source dialog box. 
if (CapDriverCaps.fHasDlgVideoSource)
    capDlgVideoSource(hWndC); 
 
// Video format dialog box. 
if (CapDriverCaps.fHasDlgVideoFormat) 
{
    capDlgVideoFormat(hWndC); 

    
// Are there new image dimensions?
    capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));

    
// If so, notify the parent of a size change.

 
// Video display dialog box. 
if (CapDriverCaps.fHasDlgVideoDisplay)
    capDlgVideoDisplay(hWndC); 

 7. 预览图像

capPreviewRate(hWndC, 66);     // rate, in milliseconds
capPreview(hWndC, TRUE);       // starts preview 

// Preview

capPreview(hWnd, FALSE);        
// disables preview 

 8. 判断是否允许图像叠加(overlay)

 CAPDRIVERCAPS CapDrvCaps; 


capDriverGetCaps(hWndC, 
&CapDrvCaps, sizeof (CAPDRIVERCAPS)); 

if (CapDrvCaps.fHasOverlay) 
    capOverlay(hWndC, TRUE);
 

 9. 对视频捕捉文件命名

 char szCaptureFile[] = "MYCAP.AVI";


capFileSetCaptureFile( hWndC, szCaptureFile); 
capFileAlloc( hWndC, (
1024L * 1024L * 5)); 

10.  设置声音捕捉

代码
WAVEFORMATEX wfex;

wfex.wFormatTag 
= WAVE_FORMAT_PCM;
wfex.nChannels 
= 2;                // Use stereo
wfex.nSamplesPerSec = 11025;
wfex.nAvgBytesPerSec 
= 22050;
wfex.nBlockAlign 
= 2;
wfex.wBitsPerSample 
= 8;
wfex.cbSize 
= 0;

capSetAudioFormat(hWndC, 
&wfex, sizeof(WAVEFORMATEX)); 

 11. 改变视频捕捉设置

代码
CAPTUREPARMS CaptureParms;
float FramesPerSec = 10.0;

capCaptureGetSetup(hWndC, 
&CaptureParms, sizeof(CAPTUREPARMS));

CaptureParms.dwRequestMicroSecPerFrame 
= (DWORD) (1.0e6 / 
    FramesPerSec);
capCaptureSetSetup(hWndC, 
&CaptureParms, sizeof (CAPTUREPARMS)); 

 12. 捕捉数据并保存

char szNewName[] = "NEWFILE.AVI";

// Set up the capture operation.

capCaptureSequence(hWndC); 

// Capture.

capFileSaveAs(hWndC, szNewName); 
 

 13. 在视频文件中叠加信息

代码
//  This example assumes the application controls 
//  the video source for preroll and postroll. 
CAPINFOCHUNK cic;
// . 
// . 
// . 
cic.fccInfoID = infotypeSMPTE_TIME;
cic.lpData 
= "00:20:30:12"
cic.cbData 
= strlen (cic.lpData) + 1;
capFileSetInfoChunk (hwndC, 
&cic); 

14.  添加一个帧回调函数

代码
TCHAR gachBuffer[100];  // Global buffer.

DWORD gdwFrameNum 
= 0;

// FrameCallbackProc: frame callback function.

// hWnd:              capture window handle.

// lpVHdr:            pointer to structure containing captured

//                        frame information.

//

LRESULT PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)

{

    
if (!hWnd)

        
return FALSE;

 

    _stprintf_s(gachBuffer, TEXT(
"Preview frame# %ld "), gdwFrameNum++);

    SetWindowText(hWnd, gachBuffer);

    
return (LRESULT) TRUE ;

}

15. Adding Callback Functions to an Application

16.  Creating a Status Callback Function

17.  Creating an Error Callback Function

reference

asic Capture Operations

capCreateCaptureWindow
WM_CAP_ABORT
WM_CAP_DRIVER_CONNECT
WM_CAP_SEQUENCE
WM_CAP_STOP

Capture Windows

CAPSTATUS
capGetDriverDescription
WM_CAP_DRIVER_CONNECT
WM_CAP_DRIVER_DISCONNECT
WM_CAP_GET_STATUS

Capture Drivers

CAPDRIVERCAPS
WM_CAP_DRIVER_GET_CAPS
WM_CAP_DRIVER_GET_NAME
WM_CAP_DRIVER_GET_VERSION
WM_CAP_GET_AUDIOFORMAT
WM_CAP_GET_VIDEOFORMAT
WM_CAP_SET_AUDIOFORMAT
WM_CAP_SET_VIDEOFORMAT

Capture Driver Preview and Overlay Modes

WM_CAP_SET_OVERLAY
WM_CAP_SET_PREVIEW
WM_CAP_SET_PREVIEWRATE
WM_CAP_SET_SCALE
WM_CAP_SET_SCROLL

Capture Driver Video Dialog Boxes

WM_CAP_DLG_VIDEOCOMPRESSION
WM_CAP_DLG_VIDEODISPLAY
WM_CAP_DLG_VIDEOFORMAT
WM_CAP_DLG_VIDEOSOURCE

Audio Format

WM_CAP_GET_AUDIOFORMAT
WM_CAP_SET_AUDIOFORMAT

Video Capture Settings

CAPTUREPARMS
WM_CAP_GET_SEQUENCE_SETUP
WM_CAP_SET_SEQUENCE_SETUP

Capture File and Buffers

CAPTUREPARMS
WM_CAP_FILE_ALLOCATE
WM_CAP_FILE_GET_CAPTURE_FILE
WM_CAP_FILE_SAVEAS
WM_CAP_FILE_SET_CAPTURE_FILE

Directly Using Capture Data

WM_CAP_SEQUENCE_NOFILE

Capture from MCI Device

WM_CAP_SET_MCI_DEVICE

Manual Frame Capture

WM_CAP_SINGLE_FRAME
WM_CAP_SINGLE_FRAME_CLOSE
WM_CAP_SINGLE_FRAME_OPEN

Still-Image Capture

WM_CAP_EDIT_COPY
WM_CAP_FILE_SAVEDIB
WM_CAP_GRAB_FRAME
WM_CAP_GRAB_FRAME_NOSTOP

Advanced Capture Options

WM_CAP_FILE_SET_INFOCHUNK
WM_CAP_GET_USER_DATA
WM_CAP_SET_USER_DATA

Working with Palettes

WM_CAP_EDIT_COPY
WM_CAP_PAL_AUTOCREATE
WM_CAP_PAL_MANUALCREATE
WM_CAP_PAL_OPEN
WM_CAP_PAL_PASTE
WM_CAP_PAL_SAVE

Yielding to Other Applications

WM_CAP_GET_SEQUENCE_SETUP
WM_CAP_SET_CALLBACK_YIELD
WM_CAP_SET_SEQUENCE_SETUP

AVICap Callback Functions

capControlCallback
capErrorCallback
capStatusCallback
capVideoStreamCallback
capWaveStreamCallback
capYieldCallback
WM_CAP_SET_CALLBACK_CAPCONTROL
WM_CAP_SET_CALLBACK_ERROR
WM_CAP_SET_CALLBACK_FRAME
WM_CAP_SET_CALLBACK_STATUS
WM_CAP_SET_CALLBACK_VIDEOSTREAM
WM_CAP_SET_CALLBACK_WAVESTREAM
WM_CAP_SET_CALLBACK_YIELD

基本上可以看到,网上那个非常简单的c#封装实际上还有很多方法没有实现。

原文地址:https://www.cnblogs.com/zc22/p/1618086.html