目 录 一. 视频捕获快速入门 二.基本的捕获设置 1.设置捕获速度: 2.设置终止捕获 3.捕获的时间限制 三.关于捕获窗口 1.创建一个AVICAP捕获窗口 2.将一个捕获窗口连接至捕获设备 3. 父窗口与子窗口的交互 4.捕获窗口的状态 四.视频捕获驱动和音频驱动 1.视频捕获驱动的性能: 2.视频对话框: 3.PREVIEW 和 OVERLAY模式: 4.视频格式 5.视频捕获设置 6.声频格式 五.使用视频捕获 1.创建捕获窗口(CREATING A CAPTURE WINDOW) 2.连接到捕获驱动(CONNECTING TO A CAPTURE DRIVER) 3.列举所有已安装的捕获驱动(ENUMERATING INSTALLED CAPTURE DRIVERS) 4.得到捕获驱动的性能(OBTAINING THE CAPABILITIES OF A CAPTURE DRIVER) 5.得到捕获窗口的状态(OBTAINING THE STATUS OF A CAPTURE WINDOW) 6.显示对话框设置视频特征(DISPLAYING DIALOG BOXES TO SET VIDEO CHARACTERISTICS) 7.得到和设置视频格式(OBTAINING AND SETTING THE VIDEO FORMAT) 8. 预览视频(PREVIEWING VIDEO) 9.将视频设置为OVERLAY模式(ENABLING VIDEO OVERLAY) 10.命名捕获文件(NAMING THE CAPTURE FILE) 11.格式化声频捕获(FORMATTING AUDIO CAPTURE) 12.改变视频捕获设置(CHANGING A VIDEO CAPTURE SETTING) 13.捕获数据(CAPTURING DATA) 14.增加一个信息块(ADDING AN INFORMATION CHUNK) 15.在程序中加入一个回调函数(ADDING CALLBACK FUNCTIONS TO AN APPLICATION) 16.创建一个状态回调函数(CREATING A STATUS CALLBACK FUNCTION) 17.创建一个错误回调函数( CREATING AN ERROR CALLBACK FUNCTION) 18.创建一个框架回调函数(CREATING A FRAME CALLBACK FUNCTION) 六.将四个标准对话框改成函数调用形式 AUDIOFORMAT对话框 VIDEOFORMAT对话框 VIDEOSOURCE对话框 VIDEO COMPRESSION对话框 前 言 视频捕获是指由专用的视频采集卡捕获声频和视频信息,然后将其进行数据化处理,再经过软件的压缩进行处理,这时就可对这些数据进行保存、回放、传输等各种操作。 Windows专门提供了Video for Windows来对视频处理进行支持,提供的接口可以被大多数的视频采集卡支持,并有多种视频压缩驱动供选择(当然视频压缩可以自己开发),采集卡支持摄像头,TV等多种输入。
视频捕捉将一个视频流和音频流数字化, 然后存储在硬盘或其他存储介质上. 一个AVICap视窗口句柄描述了声频与视频流的细节, 这样就使你的应用程序从AVI文件格式, 声频视频缓冲管理, 低层声频视频驱动访问等等解脱出来, AVICap为应用程序提供了一个灵活的介面, 你可以仅仅使用如下几行代码就可以将视频捕捉加入你的程序: hWndC = capCreateCaptureWindow ( "My Own Capture Window", WS_CHILD | WS_VISIBLE , 0, 0, 160, 120, hwndParent, nID); SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0 /* wIndex */, 0L); SendMessage (hWndC, WM_CAP_SEQUENCE, 0, 0L); 一个宏其实也是使用SendMessage, 只不过提供给程序一个更易读的代码而已, 下面的这些示例就是使用宏的方法将视频捕捉加入程序: hWndC = capCreateCaptureWindow ( "My Own Capture Window", WS_CHILD | WS_VISIBLE , 0, 0, 160, 120, hwndParent, nID); capDriverConnect (hWndC, 0); capCaptureSequence (hWndC);
如果是缺省的设置, WM_CAP_SEQUENCE会开始捕捉视频音频流到CAPTURE.AVI文件中, 直到下面的某一事件发生为止: 用户按下了ESC键或者一个鼠标键 你的应用程序终止或异常中断捕捉操作 磁盘已满
基本的捕获设置包括:设置捕获速度(每秒捕获多少帧),是否同时捕获声频,捕获缓冲,允许最大丢失多少帧,是否使用DOS内存,以及用键盘的哪个键或鼠标 的哪个键来终止捕获等等。这些基本的设置都可以使用CAPTUREPARAMS结构来描述,你可以使用capCaptureGetSetup宏来得到当前 的设置,然后改变此结构的成员变量,再使用capCaptureSetSetup宏设置新的设置。 例如: 1.设置捕获速度: 捕捉速度是指捕捉任务每秒钟捕获的帧数, 你可以发送WM_CAP_GET_SEQUENCE_SETUP消息(或者使用capCaptureGetSetup宏)来得到当前的捕捉速度, 当前的捕捉速度保存在CAPTUREPARAMS结构的dwRequestMicroSecPerFrame成员变量中, 你可以通过设置此变量来改变当前设置, 单位是每毫秒连续的帧数, 你可以发送WM_CAP_SET_SEQUENCE_SETUP消息(或者使用capCaptureSetSetup宏), dwRequestMicroSecPerFrame的值是66667, 相当于每秒15帧.
你可以允许用户按下某键或某组合键或者鼠标的左右键来终止一个捕获任务, 如果是实时的捕获, 则捕获的文件将会被丢弃; 如果是单步捕获, 在终止之前所捕获的内容将会被保存. 你可以通过发送WM_CAP_GETQUENCE_SETUP消息(或者使用capCaptureGetSetup宏)来得到当前的设置, 当前的按键设置保存在CAPTUREPARAMS的vKeyAbort成员中, 当前的鼠标设置保存在fAbortLeftMouse和fAbortRightMouse成员中. 你可以设置新的按键或按键组合, 或者鼠标左右键, 当你修改的CAPTUREPARAMS后,应该发送WM_CAP_SET_SEQUENCE_SETUP消息来进行更新(或者使用 capCaptureSetSetup宏). 缺省的按键是VK_ESCAPE. 你必须在指定按键之前使用RegisterHotKey函数, 鼠标缺省的值是fAbortLeftMouse和fAbortRightMouse都为TRUE.
CAPTUREPARAMS结构中的fLimitEnabled指示是否有时间限度, wTimeLimit指示最大的持续时间, 单位为秒. 得到fLimitEnabled和wTimeLimit的值可以发送WM_CAP_GET_SEQUENCE_SETUP消息(或使用 capCatureGetSetup宏), 当设置了这些成员变量后, 应该发送消息WM_CAP_SET_SEQUENCE_SETUP消息(或capCaptureSetSetup宏)来更新CAPTUREPARAMS结 构.
在捕获之前必须创建一个捕获窗口(capture window),在发送消息或使用宏的过程中都需要使用此窗口。 1.创建一个AVICap捕获窗口 你可以使用capCreateCaptureWindow函数来创建一个AVICap捕获窗口, 此函数将会返回一个句柄, 此句柄以后在发送消息时要用. 你可以在一个程序里创建一个或多个捕获窗口, 然后给每一个窗口连接不同的捕获设置.
你可以动态的在一个捕获窗口与一个捕获设备之前连接或断接, 你可以发送WM_CAP_DRIVER_CONNECT消息来使一个捕获窗口与一个捕获设备连接或关联. 当连接上以后, 你就可以通过捕获窗口向捕获设备发送各种消息. 如果你的系统里装有多个捕获设备, 你可以在发送WM_CAP_DRIVER_CONNECT消息时用wParam参数指定使用哪一个, 此参数是登记在SYSTEM.INI文件的[drivers]一节里的列表中的某一项, 0为第一个. 你可以使用capGetDriverDescription函数来得到已安装的捕获设备的名称及版本, 这样你的程序就可以列举所有已安装的捕获设备和驱动, 这样用户就可以选择其中的一个来与你的捕获窗口连接. 你可以发送WM_CAP_DRIVER_GET_NAME消息(或capDriverGetName宏)来得到连接到捕获窗口的捕获设备的名称, 得到版本发送WM_CAP_DRIVER_GET_VERSION消息(或capDriverGetVersion宏) 你可以发送WM_CAP_DRIVER_DISCONNECT消息(或capDriverDisconnect宏)来断接.
一些象WM_PALETTECHANGED和WM_QUERYNEWPALETTE的系统级消息只能发送到顶级窗口或OVERLAPPED窗口, 如果一个捕获窗口是子窗口,就必须通过父窗口转送. 同样的, 如果父窗口的尺寸改变了, 它就需要通知捕获窗口, 相反地, 如果捕获窗口的尺寸改变了, 捕获窗口就需要发送消息给父窗口, 一个简单的方法就是始终保持捕获窗口的尺寸与视频流的尺寸一致, 并随时将尺寸的改变通知父窗口.
你可以发送WM_CAP_GET_STATUS消息(或capGetStatus宏)来得到当前捕获窗口的状态, 得到的是一个CAPSTATUS结构的拷贝, 它包含图片的尺寸, 卷轴的当前位置, overlay和preview是否已设置. 因为CAPSTATUS信息是动态的, 你的程序应该只要捕获的视频流的尺寸或格式可能发生了改变就应该进行刷新(例如: 显示了捕获设备的视频格式以后). 改变捕获窗口的尺寸并不影响实际的捕获的视频流的尺寸, 视频捕获设备的格式对话框捕获频流的尺寸.
1.视频捕获驱动的性能: 你可以通过发送WM_CAP_DRIVER_GET_CAPS消息(或者capDriverGetCaps宏)来得到当前连接的视频驱动的硬件性能. 得到的信息保存在CAPDRIVERCAPS结构中.
每一个视频驱动能够提供四个对话框来控制视频捕获和数字化处理, 定义压缩品质等, 这些对话框都定义在视频捕获驱动中. Video Source对话框用于控制选择视频来源, 此对话框列举了此视频捕获卡连接的所有视频源(典型的例如:SVHS和合成输入), 并提供了改变色调, 对比度, 饱和度. 如果视频驱动支持此对话框, 你就可以显示并更新它, 使用WM_CAP_DLG_VIDEOSOURCE消息(或capDlgVideoSource宏). Video Format对话框定义视频帧的尺寸以及精度, 视频捕获卡的压缩设置. 如果卡支持的话, 可以发送消息WM_CAP_DLG_VIDEOFORMAT消息或(capDlgVideoFormat宏). Video Display对话框控制在视频捕获期间在显示器上的显示, 此控制不会影响视频数字数据, 但是他们可能会影响数字信号的表现形式, 例如: 如果捕获设备支持overlay, 可能允许改变色调和饱和度, 关键色彩 或者overlay队列. 如果卡支持, 你可以发送WM_CAP_DLG_VIDEODISPLAY消息(或者使用capDlgVideoDisplay宏). Video Compression对话框控制压缩品质, 如果卡支持, 发送消息WM_CAP_DLG_VIDEOCOMPRESSION(或capDlgVideoCompression宏).
一个视频捕获驱动对进入的视频流有两种工作模式: Preview模式和overlay模式, 如果一个捕获驱动能够执行两种方法, 用户可以在其中选择一种. Preview模式把从捕获硬件传来的数据送入系统内存并使用图形设备介面(GDI)将数字化帧显示在捕获窗口内. 应用程序可以在父窗口失去焦点时减缓显示速度, 当重新又得到焦点后加快显示速度, 此种模式要占用大量CPU时间. 有三种消息控制Preview操作: WM_CAP_SET_PREIVEW消息(capPreview宏)允许或禁止preview模式 WM_CAP_SET_PREVIEWRATE(capPreviewRate宏)当帧在preview模式显示时设置速度. WM_CAP_SET_SCALE(capPreviewScale宏)允许或禁止preview视频的缩放比例. 当preview和scaling同时使用, 捕获的视频帧将会根据捕获窗口的尺寸自动缩放, 允许preview模式会自动关闭overlay模式. overlay模式是一个硬件函数它将数据送入捕获缓冲区中因而不占用CPU资源. 你可以发送消息WM_CAP_SET_OVERLAY(或capOverlay宏)给捕获窗口来启用或终止overlay模式, 允许overlay模式会自动禁止preview模式. 你同时也可以在preview模式或overlay模式里发送WM_CAP_SET_SCROLL消息(或capSetScrollPos宏)来设置视频帧的客户区卷轴位置.
你可以通过发送WM_CAP_GET_VIDEOFORMAT消息(或capGetVideoFormat和capGetVideoFormatSize 宏)来得到视频格式的结构或结构的尺寸. 你可以通过发送CAP_SET_VIDEOFORMAT消息(或capSetVideoFormat宏)来设置视频格式.
CAPTUREPARMS结构包含了对视频捕获流的控制参数, 你可以完成以下这些任务: 指定帧数 指定分配多少视频缓冲 允许或禁止声频捕获 指定捕获的时间间隔 指定在捕获的过程中是否使用MCI设置(VCR或者videodisc) 指定终止流的键盘或鼠标 specify the type of video averaging applied during capture.
设置:WM_CAP_SET_SEQUENCE_SETUP消息(或capCaptureSetSetup宏)
你可以通过发送WM_CAP_GET_AUDIOFORMAT消息(或capGetAudioFormat宏和 capGetAudioFormatSize宏)来得到当前捕获音频数据的格式或尺寸格式。缺省的声频格式是:单声道、8位、11kHz PCM。 当你使用WM_CAP_GET_AUDIOFORMAT时,总是使用WAVEFORMATEX结构。 设置发送消息WM_CAP_SET_AUDIOFORMAT消息(或capSetAudioFormat宏),可以传送WAVEFORMAT,WAVEFORMATEX,PCMWAVEFORMAT结构指针。 五.使用视频捕获 1.创建捕获窗口(Creating a Capture Window) hWndC = capCreateCaptureWindow ( (LPSTR) "My Capture Window", // window name if pop-up WS_CHILD | WS_VISIBLE, // window style 0, 0, 160, 120, // window position and dimensions (HWND) hwndParent, (int) nID /* child ID */);
下面的例子是将MSVIDEO驱动连接到句柄为hWndC的捕获窗口, 然后调用capDriverDisconnect宏来断接. fOK = SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L); // // 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);
下面的例子使用capGetDriverDescription函数得到已安装的捕获驱动的名称及版本: char szDeviceName[80]; char szDeviceVersion[80];
{ 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. } }
发送WM_CAP_DRIVER_GET_CAPS消息可以得到捕获驱动的性能,并保存入一个CAPDRIVERCAPS结构.每当程序连接一个新的捕获 驱动到一个捕获窗口时, 就应该更新CAPDRIVERCAPS结构. 下面的程序举例说明了如何使用capDriverGetCaps宏来得到捕获驱动的性能:
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));
下面的例子使用SetWindowPos函数使捕获窗口与进来的视频流尺寸保持一致, 视频流的基本信息是使用capGetStatus宏得到的, 保存在CAPSTATUS结构中.
capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS)); SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth, CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);
每个视频捕获卡一般能提供三个不同的对话框用于控制视频捕获及数字化处理. 下面的例子说明如何显示这些对话框, 在显示这些对话框之前,使用了capDriverGetCaps宏来检查CAPDRIVERCAPS结构, 以检测该卡是否有显示这些对话框:
capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));
if (CapDriverCaps.fHasDlgVideoSource) capDlgVideoSource(hWndC);
if (CapDriverCaps.fHasDlgVideoFormat) { capDlgVideoFormat(hWndC); // Are there new image dimensions? capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS)); // If so, notify the parent of a size change. }
if (CapDriverCaps.fHasDlgVideoDisplay) capDlgVideoDisplay(hWndC);
BITMAPINFO结构的长度既适应于标准的也适应于压缩的数据格式, 所有程序必须总是询问此结构的尺寸以便在得到当前的视频格式之前分配内存. 下面的例子就是使用capGetVideoFormatSize宏来得到缓冲区尺寸并调用capGetVideoFormat宏来得到当前的视频格式.
DWORD dwSize; dwSize = capGetVideoFormatSize(hWndC); lpbi = GlobalAllocPtr (GHND, dwSize); capGetVideoFormat(hWndC, lpbi, dwSize);
下面的例子使用capPreviewRate宏来设置每66毫秒显示一帧, 并使用capPreview宏将它放置在捕获窗口里.
capPreview(hWndC, TRUE); // starts preview // Preview capPreview(hWnd, FALSE); // disables preview
下面的例子: capDriverGetCaps宏确定此捕获卡是否有overlay功能, 如果有就使用宏来设置它
capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));
capOverlay(hWndC, TRUE);
下面的例子: 使用capFileSetCaptureFile宏来指定预备文件名为:MYCAP.AVI, capFileAlloc宏预先指定它的大小为5M.
capFileSetCaptureFile( hWndC, szCaptureFile); capFileAlloc( hWndC, (1024L * 1024L * 5));
下面的例子使用capSetAudioFormat来设置声频格式为:11kHz, PCM 8位, 立体声
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;
下面的例子使用capCaptureGetSetup和capCaptureSetSetup宏得将捕获帧数从缺省的15帧改成每秒10帧.
float FramesPerSec = 10.0;
capCaptureSetSetup(hWndC, &CaptureParms, sizeof (CAPTUREPARMS));
下面的例子使用capCaptureSequence宏来开始捕获视频并使用capFileSaveAs宏来将捕获的数据拷贝至NEWFILE.AVI文件中.
// Set up the capture operation. capCaptureSequence(hWndC); // Capture. capFileSaveAs(hWndC, szNewName);
如果你需要在你的程序捕获的声频和视频数据中加入你的其他信息, 你可以创建一个信息块并将它们插入捕获文件中, 信息块可以包含一些典型的信息, 例如:版权信息,视频来源, 外部定位信息等. 下面的例子使用capFileSetInfoChunk宏来插入一个信息块, 里面包含了一个SMPTE的时间代码.
// 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);
一个程序可以为捕获窗口登记一个回调函数以便在以下的这些情况下通知程序.
错误发生 视频框架和声频缓冲区变得可用 程序应用在捕获视频流的过程中接收
{ char achDeviceName[80] char achDeviceVersion[100] char achBuffer[100] WORD wDriverCount = 0 WORD wIndex WORD wError HMENU hMenu
ghWndCap = capCreateCaptureWindow((LPSTR)"Capture Window", WS_CHILD | WS_VISIBLE, 0, 0, 160, 120, (HWND) hWnd, (int) 0);
// capSetCallbackOnError macro. capSetCallbackOnError(ghWndCap, fpErrorCallback);
// capSetCallbackOnStatus macro. capSetCallbackOnStatus(ghWndCap, fpStatusCallback);
// capSetCallbackOnVideoStream macro. capSetCallbackOnVideoStream(ghWndCap, fpVideoCallback);
// capSetCallbackOnFrame macro. capSetCallbackOnFrame(ghWndCap, fpFrameCallback);
} case WM_CLOSE: { // Use the capSetCallbackOnFrame macro to // disable the frame callback. Similar calls exist for the other // callback functions.
}
下面的例子是创建一个简单的状态回调函数,登记此回调函数使用capSetCallbackOnStatus宏.
// hWnd: capture window handle // nID: status code for the current status // lpStatusText: status text string for the current status // LRESULT PASCAL StatusCallbackProc(HWND hWnd, int nID, LPSTR lpStatusText) { if (!ghWndMain) return FALSE;
SetWindowText(ghWndMain, (LPSTR) gachAppName); return (LRESULT) TRUE; } // Show the status ID and status text... wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText);
return (LRESULT) TRUE; }
下面的例子是创建一个简单的错误回调函数,登记此回调函数使用capsetCallbackOnError宏:
// hWnd: capture window handle // nErrID: error code for the encountered error // lpErrorText: error text string for the encountered error // LRESULT PASCAL ErrorCallbackProc(HWND hWnd, int nErrID, LPSTR lpErrorText) { if (!ghWndMain) return FALSE;
return TRUE; // Clear out old errors.
wsprintf(gachBuffer, "Error# %d", nErrID);
MB_OK | MB_ICONEXCLAMATION);
}
登记此回调函数使用capSetCallbackOnFrame宏:
// hWnd: capture window handle // lpVHdr: pointer to struct containing captured // frame information // LRESULT PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) { if (!ghWndMain) return FALSE;
SetWindowText(ghWndMain, (LPSTR)gachBuffer); return (LRESULT) TRUE } 六.将四个标准对话框改成函数调用形式 系统提供了四个标准的对话框:AudioFormat, VideoFormat, VideoSource, Video Compression,但有时程序希望通过函数控制它们,而不是使用系统提供的那个单一的对话框,此时就应该使用函数调用的方法:
可以通过使用capSetAudioFormat来实现,此时要使用WAVEFORMATEX结构。 例如:改成PCM格式,立体声,16声道,12.05kHz,则: WAVEFORMATEX audioFormat; // 确定宽度 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT,&dwSize); dwSize = max (dwSize, capGetAudioFormatSize (m_hwCapCapturing)); // 设置参数 audioFormat.wFormatTag = WAVE_FORMAT_PCM; audioFormat.nChannels = 2; audioFormat.nSamplesPerSec = 120500; audioFormat.wBitsPerSample =16; audioFormat.nBlockAlign = nBitsPerSample * nChannels / 8; audioFormat.nAvgBytesPerSec = audioFormat.nBlockAlign * nSamplesPerSec; // 更新 capSetAudioFormat(ghCapWnd,&audioFormat,dwSize); VideoFormat对话框 可以通过使用capSetVideoFormat来实现,此时要使用BITMAPINFOHEADER结构。 例如:设置图片大小为RGB24位岁,大小为230X160 BITMAPINFOHEADER bi; DWORD dwSize,dw; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = 320; // 起作用 bi.biHeight = 160; // 起作用 bi.biPlanes = 1; bi.biBitCount = 24; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 176; bi.biYPelsPerMeter = 144; bi.biClrUsed = 0; bi.biClrImportant = 0; dwSize = bi.biSize + ((bi.biBitCount > 8 || bi.biClrUsed) ? (bi.biClrUsed * sizeof(PALETTEENTRY)) : (2 ^ bi.biBitCount * sizeof(PALETTEENTRY))); dw = capSetVideoFormat(m_hwCapCapturing, &bi, dwSize); VideoSource对话框 没有找到现成的方法,但视频捕获卡提供的CD里面有一个动态链接库可以实现。 Video Compression对话框 可以通过使用ICOpen,ICInfo等函数联合起来,得到当前系统里面的视频压缩驱动的列表,并可选择其一,MSDN里面有一个程序示范了此用户,程序名叫:ICWalk。 |