局域网摄像头抓图程序
[此贴子已经被作者于2007-8-21 16:48:39编辑过]
[此贴子已经被作者于2007-8-21 16:48:39编辑过]
VFW(Video For Windows) For VB编程初步
首先,所有的视频捕捉过程都将开始于建立一个捕捉窗口。这里我们使用了capCreateCaptureWindowA函数。当它调用后,将会返回一个新窗体的句柄(在使用时,你可以自行设定参数来设置这个新窗体的风格)例如:
lwndC = capCreateCaptureWindowA("My Capture Window", WS_CHILD or WS_VISIBLE, 0, 0, 160, 120, Me.hwnd, 0)
操作视频捕捉的执行方法有2种:一般来说,所有对于窗体的操作将使用发送一个窗体消息来执行。所以视频捕捉的窗体也不例外。例如需要连接到一个捕捉驱动上时,可以使用WM_CAP_DRIVER_CONNECT消息,它将绑定第一个被搜索到的驱动源到你指定的窗体。当然,你可以把这个消息发送给任何窗体。但是要记住,只有特定的窗体才能识别你的WM_CAP_DRIVER_CONNECT消息:
SendMessage lwnd, WM_CAP_DRIVER_CONNECT, 0, 0
初此之外,你还可以使用capDriverConnect lwnd, 0来代替SendMessage API。这在功能上是完全相同的。
此外,为了能够更好的使用消息驱动来控制视频捕捉,在这里还需要深入讨论一下SendMessage得几种特殊的使用技巧。
1.通过SendMessage来传递一个字符串
一般来说,SendMessage总是使用4个参数来发送消息的。他们是一个窗体或对象的句柄;一个消息的名称,一个“短参数“(wParam)和一个“长参数“(lParam)。按照api的定义如下:
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Long) As Long
如果需要lParam来传递字符串,则必须定义它为String.但是这样做的话会导致一个dll的错误产生。这可是个大问题。但是,实际上,如果你把一个字符串放在一个变量中,那么将会产生一个32位的long型指针。这样,通过SendMessage来传递字符就是一个很简单的问题了。为此,我们将SendMessage的新定义如下:
Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As String) As Long
2.通过SendMessage来传递一个结构体(自定义类型)
结构体也不可以直接通过函数来传递,这是显而易见的。如果按照字符串的形式按位传递也不是一个最佳的方案。为此,可以使用VARPTR()函数。VARPTR函数返回一个内存中的定位(即指针),这样就成为了一个long型变量,可以轻易的通过SendMessage等api来传递。这里我们将快速演示一下它的用法。
Dim CAP_PARAMS As CAPTUREPARMS
capCaptureGetSetup lwndC, VarPtr(CAP_PARAMS), Len(CAP_PARAMS)
视频流的图像处理
现在,最重要的一个问题就是:我应该如何处理一个视频流中的图像呢?或者说我该如何从一个视频流中捕捉图像数据呢?答案是使用callback函数:capSetCallbackonFrame 可以处理在预览中的每一帧画面。而capSetCallbackOnVideoStream可以处理捕捉中的帧,例子如下:
capSetCallbackOnFrame lwndC, AddressOf MyFrameCallback
其中MyFrameCallback函数是你需要建立的一个函数,它一般存在于模块中,而不是一个窗体。这样,每次产生一个新的帧的时候它都可以从视频驱动中接受到。它将通过一个VIDEOHDR结构来获取数据。定义如下:
Type VIDEOHDR
lpData As Long '// address of video buffer
dwBufferLength As Long '// size, in bytes, of the Data buffer
dwBytesUsed As Long '// see below
dwTimeCaptured As Long '// see below
dwUser As Long '// user-specific data
dwFlags As Long '// see below
dwReserved(3) As Long '// reserved; do not use
End Type
其中lpData存放着实际的视频流数据,这样,你就可以熟练的操作VIDEOHDR结构来取得数据了
Function MyFrameCallback(ByVal lwnd As Long, ByVal lpVHdr As Long) As Long
Debug.Print "FrameCallBack"
Dim VideoHeader As VIDEOHDR
Dim VideoData() As Byte
'//Fill VideoHeader with data at lpVHdr
RtlMoveMemory VarPtr(VideoHeader), lpVHdr, Len(VideoHeader)
'// Make room for data
ReDim VideoData(VideoHeader.dwBytesUsed)
'//Copy data into the array
RtlMoveMemory VarPtr(VideoData(0)), VideoHeader.lpData, VideoHeader.dwBytesUsed
Debug.Print VideoHeader.dwBytesUsed
Debug.Print VideoData
End Function
在上面的例子中,RtlMoveMemory api定义如下:
Declare Sub RtlMoveMemory Lib "kernel32" (ByVal hpvDest As Long, ByVal hpvSource
As Long, ByVal cbCopy As Long)
保留地址信息 dev-club.esnai.com/club/bbs/showEssence.asp?id=20434
网络上搜索到的,你看看吧。