一、前言
在本实验室所开发的基于Internet的实时视频通信系统中,本人主要负责视频的采集和压缩编码部分。其中,视频源是由摄像头直接捕获获得的。根据当前的视频采集设备的发展趋势和实验条件,我们选用的是USB接口,支持VFW,纯软件采集,无硬件支持的摄像头,这种摄像头已成为目前视频采集设备中的主流。在开发应用的过程中,本人在程序中使用了AVICap窗口类来实现视频的采集,这部分是后续的视频压缩处理和通信传输的基础。在工作中,本人对AVICap的使用进行了一定的学习和尝试,由于开发过程中发现这方面的中文学习资料很少,英文帮助和例程对初学者可能比较难于入手,故想在这里将自己学到的一点知识和编程中的一些心得介绍给大家,希望能对其他读者有所帮助。
二、AVICap简介
AVICap窗口类是VFW(Video for Windows)*的一个重要组成部分,它的主要作用是实现视频的捕获。AVICap为应用程序提供了一个简单的,基于消息的接口,通过该接口,程序可以访问视频和波形音频硬件并控制视频流到硬件的捕获。通过AVICap,程序员可以轻松的将视频捕获功能加入自己的应用程序。
AVICap支持实时视频流捕获和单帧捕获。此外,AVICap使程序员可以控制视频源的开始和结束位置,并加入了如序列帧捕获等功能。
使用AVICap生成的捕获窗具有以下功能:
*将音频和视频流捕获到AVI文件。
*动态地连接或断开音频和视频输入设备。
*以叠加(overlay)或预览(preview)模式显示输入的实时视频信号。
*指定捕获所用的文件,并可将捕获文件的内容拷贝到另一个文件。
*设置捕获速率。
*显示控制视频源和视频格式的对话框。
*创建,保存和载入对话框。
*将图像和调色板拷贝到剪贴板。
*捕获和保存DIB格式单帧图像。
最后,需要指出的是AVICap所能提供的功能是硬件相关的,许多功能,如以叠加(overlay)模式显示视频,捕获音频,以及所支持的视频采集格式是否可用等应由所选择的视频捕获设备而定。具体应用设计时要根据硬件所支持的性能来灵活处理。所幸的是,我们可以通过检查CAPDRIVERCAPS结构来获取捕获驱动器的能力,并通过AVICap提供的Video Source,Video Format,Video Display对话框来对捕获参数进行设置。如何实现,请见下部分的介绍。
三、用AVICap实现视频捕获
用AVICap实现视频捕获主要分为以下几个步骤:
(1)创建捕获窗
捕获窗是所有捕获操作的基础,其构造要调用:
ghWndCap = capCreateCaptureWindow( //创建捕获窗函数
NULL, // 窗口名称
WS_CHILD | WS_VISIBLE, // 窗口风格
0, 0, 176,144, // 窗口位置和大小
hMainWin, //父窗口句柄
1 //窗口ID
);
if (ghWndCap == NULL) //如创建不成功,返回false
return false;
其中ghWndCap为 由HWND ghWndCap; 定义的捕获窗句柄。
(2)将捕获窗与视频捕获驱动相连
BOOL fOK;
fOK = capDriverConnect(ghWndCap, 0);
if(!fOK)
{
//无法将指定的视频捕获驱动连接到捕获窗
//在此加入错误处理
}
(3)获得捕获驱动器的能力
capDriverGetCaps(hwndCap, &gCapDriverCaps, sizeof(CAPDRIVERCAPS)) ;
其中, gCapDriverCaps是由CAPDRIVERCAPS gCapDriverCaps ;定义的。CAPDRIVERCAPS 结构定义了捕获驱动器的能力,如有无视频叠加能力,有无控制视频源、视频格式的对话框等。
执行capDriverGetCaps语句后,gCapDriverCaps中就获得了与当前捕获窗相连的捕获驱动的各项能力,要根据该捕获驱动的能力来实现视频的显示和捕获。
(4)显示视频
上已提及,显示视频有两种模式:叠加(overlay)或预览(preview)模式。
由于叠加模式只被部分视频捕获卡支持,而大部分视频捕获设备都支持预览模式,我们用预览模式显示视频:
capPreviewRate(ghWndCap,66); //设置显示帧率(本例中为66ms/帧)
capPreview(ghWndCap,TRUE); //开始预览显示
要停止预览可用:
capPreview(ghWndCap,FALSE);
用叠加模式显示视频的方法相似,只是所用函数应为capOverlay。
(5)进行视频捕获
视频捕获主要有两种模式,连续视频流捕获和单帧捕获。
在进行视频捕获之前要指定捕获文件名并为捕获文件分配存储空间。
char szCaptureFile[] = “MYCAP.AVI”; //捕获文件名为”MYCAP.AVI”
capFileSetCaptureFile(ghWndCap, szCaptureFile); //指定捕获文件为”MYCAP.AVI”
capFileAlloc(ghWndCap, (1024L * 1024L * 5)); //为捕获文件分配空间
连续视频流捕获用:
capCaptureSequence(ghWndCap);
单帧捕获使用:
capGrabFrame(ghWndCap);
要结束视频捕获可用:
capCaptureAbort(ghWndCap);
还有一种捕获方式是不将捕获结果写到文件,这时,可使用回调函数来直接处理捕获到的数据,关于这种方式,我们在第四节有详细介绍。
(6)设置视频源,视频格式和显示对话框
每个视频捕获驱动最多具有三个不同的对话框用于控制视频的数字化和捕获方法,可调用这些对话框完成对视频捕获的控制。由(3)中获得的gCapDriverCaps中的成员可判断当前的捕获驱动是否具有这些对话框。
if (gCapDriverCaps.fHasDlgVideoSource) //如果具有设置视频源对话框
capDlgVideoSource(ghWndCap); //显示该对话框
if (gCapDriverCaps.fHasDlgVideoFormat) //如果具有设置视频格式对话框
capDlgVideoFormat(ghWndCap); //显示该对话框
if (gCapDriverCaps.fHasDlgVideoDisplay) //如果具有设置显示对话框
capDlgVideoDisplay(ghWndCap); //显示该对话框
在显示的对话框中,该捕获驱动支持的视频源格式,捕获格式,显示格式都会被列出,用户可根据需要进行选取,设置。
(7)结束,将捕获窗同驱动断开连接
capDriverDisconnect (ghWndCap);
这一步在结束视频捕获程序时是必须的,否则将导致视频驱动无法释放,其它程序将不能使用捕获设备。
四、实现AVICap的高级功能
在实际应用中,我们有时候需要对捕获的视频流进行处理,如在视频通信系统中要进行压缩编码,这时,就需要我们在基本的视频捕获程序中加入一些其它函数,如回调函数,并在其中进行处理。而且,在实际应用中,也会遇到如当有多个捕获驱动时的检测问题,设置控制视频捕获过程的参数问题,和视频数据的格式设置问题等,下面,就一些常见的问题及如何运用回调函数在视频捕获中加入视频处理进行基本的介绍。
(1)列举已安装的视频捕获驱动
当有多个视频捕获驱动已安装时,可依次获得各视频捕获驱动的名称及版本信息。
char szDeviceName[80]; //用于存放捕获驱动的名称
char szDeviceVersion[80]; //用于存放捕获驱动的版本号
for (UNIT wIndex = 0; wIndex < 10; wIndex++)
{
if (capGetDriverDescription (
wIndex, //视频捕获驱动的索引号,从1到10
szDeviceName, //视频捕获驱动的名称
sizeof (szDeviceName),
szDeviceVersion, //视频捕获驱动的版本号
sizeof (szDeviceVersion))
{
//将该捕获驱动的名称加入到已安装的视频捕获驱动列表
//使用户可选择使用那个驱动进行捕获
}
)
(2)改变视频捕获参数
结构CAPTUREPARMS中包含控制视频捕获过程的各种参数,如捕获帧频,捕获时间限制,捕获时的缓存数,捕获如何被终止等。用capCaptureGetSetup和capCaptureSetSetup可完成捕获参数的获取和设置。下面的例子是将捕获帧率从省缺的15帧/秒设置为15帧/秒。其它参数可根据应用的需要进行设置,方法不变。
capCaptureGetSetup(ghWndCap, & gCapParms, sizeof(CAPTUREPARMS));
//获得当前视频捕获参数
float FramesPerSec = 10.0; //待设帧率
gCapParms.dwRequestMicroSecPerFrame = (DWORD) (1.0e6 / FramesPerSec);
//计算出每帧的时间(微秒),并赋予相应的成员
capCaptureSetSetup(ghWndCap, & gCapParms, sizeof (CAPTUREPARMS));
//设置新的视频捕获参数
其中,gCapParms由CAPTUREPARMS gCapParms;定义,CAPTUREPARMS结构定义了控制视频流捕获过程的参数。
(3)获取并设置视频格式
前面已经讲过可用视频格式对话框来设置视频格式,在实际应用中,有时候要根据处理视频的要求在程序中自动完成格式设置,如在低码率视频压缩标准H.263中的要处理的标准图像格式是QCIF(YUV4:1:1大小176*144),这时,可用capSetVideoFormat完成格式设置。
需要注意的是在获取并设置视频格式所用到的参数之一是BITMAPINFO结构的变量, BITMAPINFO结构是可变长结构。故应用在检索当前视频格式之前必须用capGetVideoFormatSize获得该结构的大小。
下面的例子先使用capGetVideoFormatSize获取BITMAPINFO结构的大小,再用capGetVideoFormat获取当前的视频格式,如当前格式不为QCIF时用capSetVideoFormat进行设置,若设置成功,则当前视频格式将变为QCIF(YUV4:1:1大小176*144)。
LPBITMAPINFO lpbi;
DWORD dwSize;
BOOL fOK;
dwSize = capGetVideoFormatSize(ghWndCap); //获取BITMAPINFO结构的大小
lpbi = (LPBITMAPINFO)new unsigned char[dwSize];//分配空间
capGetVideoFormat(ghWndCap, lpbi, dwSize); //获取当前的视频格式
if(lpbi->bmiHeader.biWidth!=176||lpbi->bmiHeader.biHeight!=144||
lpbi->bmiHeader.biCompression!=mmioFOURCC(‘I’,‘4’,‘2’,‘0’))
//若不为QCIF格式
{ //设置为所要求的格式
lpbi->bmiHeader.biWidth=176; //位图的宽度
lpbi->bmiHeader.biHeight=144; //位图的高度
lpbi->bmiHeader.biCompression= mmioFOURCC(‘I’,‘4’,‘2’,‘0’);
//图像压缩格式设置为I420(即YUV4:1:1)
lpbi->bmiHeader.biBitCount=12; //每个像素所用的比特数
lpbi->bmiHeader.biSizeImage=38016; //该结构所用总比特数
fOK =capSetVideoFormat(ghWndCap, lpbi,dwSize); //设置为QCIF格式
delete lpbi;
return fOK; //设置成功返回TRUE,否则返回FALSE
}
else// 已为QCIF格式,返回TRUE
{
delete lpbi;
return TRUE;
}
由于视频格式是设备相关的,故应用程序应检查capSetVideoFormat的返回值以判断该视频采集设备是否支持指定的视频格式并采取相应的措施。如该视频采集设备不支持此种格式可用其它格式进行采集再加入格式转换函数。
(4)使用回调函数
回调函数使应用能够直接使用音频和视频。
应用程序可用捕获窗来登记回调函数,在发生下列情况时,它能通知应用程序,此时被登记的回调函数将被自动调用。
*状态改变
*出错
*视频帧和音频缓存可用
*在捕获过程中,应用处于让步(yield)地位
下面我们举例说明回调函数的使用。
我们以capVideoStreamCallback为例,该回调函数是与流式采集相结合使用的,用于选择性的处理捕获的视频帧。当捕获设备标记视频缓存已装满后,捕获窗将自动调用视频流回调函数。它的使用分以下几步
首先,登记回调函数:
capSetCallbackOnVideoStream(ghWndCap,&StreamCallbackProc);
//回调函数StreamCallbackProc应已被提前声明
然后,定义回调函数:
LRESULT CALLBACK StreamCallbackProc(HWND hWnd,LPVIDEOHDR lpVHdr)
{
if (lpVHdr->dwFlags & VHDR_DONE) //视频缓存已装满
{
//此时lpVHdr->lpData中存放的就为已捕获的一帧视频数据
//可在此加入自己的处理函数
//注意要将lpVHdr->lpData内的数据及时保存
}
return (LRESULT) TRUE;
}
其中,VIDEOHDR结构定义了视频数据块的头信息。
最后,取消已定义的回调函数:
capSetCallbackOnVideoStream(ghWndCap,NULL);
在我们的程序设计中,在视频捕获中采用
capCaptureSequenceNoFile(ghWndCap);
进行捕获,capCaptureSequenceNoFile以不存入文件的方式捕获,由回调函数StreamCallbackProc直接处理捕获数据,进行编码等操作。
五、小结
本文介绍了使用AVICap窗口类开发视频捕获程序和视频通信系统的基本方法,对于其基本实现给予了示例和说明,并对一些关键问题的实现方法予以较为详细的解释,有关AVICap中其它函数的使用请参见MSDN的帮助文件和vidcap例程。
* Video for Windows(VFW,Windows环境下的视频服务)软件是Microsoft公司开发,随Windows操作系统发布的,它使多媒体个人计算机(MPC)具有处理视频信号的能力。VFW的一个关键思想是播放时不需要专用硬件,它能使应用程序数字化并播放从传统模拟视频源得到的视频。
|