谈谈使用VFW在windows下编程控制摄像头(二)。 【孙涛】

来源:互联网 发布:新概念英语听写软件 编辑:程序博客网 时间:2024/05/17 04:04

版权声明:http://blog.csdn.net/suntaoznz/article/details/448303

目录(?)[-]

  1. 2使用视频捕获
    1. 21创建捕获窗体
    2. 22连接到一个捕获驱动器
    3. 23列举安装的捕获驱动程序
    4. 24获得捕获驱动器的性能参数
    5. 25获得捕获窗口状态Status
    6. 26显示对话框区设置视频属性
    7. 27获得和设定视频格式
    8. 28预览视频
    9. 29允许视频覆盖Overlay
    10. 210捕获文件命名
    11. 211格式化音频捕获
    12. 212改变视频捕获设置
    13. 213捕获数据
    14. 214加入信息块
    15. 215在程序中加入回调函数
    16. 216创建一个状态回调函数
    17. 217创建一个错误的回调函数
    18. 218创建一个帧回调函数

如要转贴请注明转至blog.csdn.net/suntaoznz。谢谢!

3.2使用视频捕获

3.2.1创建捕获窗体

下面的例子通过使用capCreateCaptureWindow函数来创建一个捕获窗体

hWndC = capCreateCaptureWindow (

    (LPSTR) "My Capture Window",       // 如果是Pop-up窗口的窗口名称

    WS_CHILD | WS_VISIBLE,          // 窗口类型

    0, 0, 160, 120,                      // 窗口位置和尺寸

    (HWND) hwndParent,

    (int) nID /* child ID */);

 

3.2.2连接到一个捕获驱动器

下面举例,如何通过捕获窗口的句柄hWndC连接到MS VIDEO驱动程序上,同时还演示了如何断开连接。使用capDriverDisconnect

fOK = SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L);

// 或者使用宏连接:

// fOK = capDriverConnect(hWndC, 0);

 

// 关闭连接

capDriverDisconnect (hWndC);

 

3.2.3列举安装的捕获驱动程序

使用capGetDriverDescription 函数来获得系统已经安装的所有捕获驱动程序的名称和版本。

char szDeviceName[80];

char szDeviceVersion[80];

for (wIndex = 0; wIndex < 10; wIndex++)

{

    if (capGetDriverDescription (wIndex, szDeviceName,

        sizeof (szDeviceName), szDeviceVersion,

        sizeof (szDeviceVersion))

    {

        // 加入名字到一个已经安装的设备列表中

        // 让用户选择一个使用。

    }

}

 

 

3.2.4获得捕获驱动器的性能参数

       WM_CAP_DRIVER_GET_CAPS消息可以返回捕获驱动程序以及其硬件的性能参数。这些信息存放在一个CAPDRIVERCAPS的数据结构中。当你的应用程序的捕获窗口连接到一个新的捕获驱动器后,都会刷新这个CAPDRIVERCAPS数据结构。下面将使用capDriverGetCaps宏来获得捕获设备的性能参数。

CAPDRIVERCAPS CapDrvCaps;

SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS,

    sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDrvCaps);

// 或者,使用宏来获得驱动器的新能参数

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

 

3.2.5获得捕获窗口状态(Status)

下面例子使用SetWindowPos函数区设置捕获窗口的尺寸,这个尺寸的大小是基于输入的视频流大小的。输入视频流的尺寸大小由capGetStatus宏来获得,获得信息放在一个CAPSTATUS的数据结构体中。

 

CAPSTATUS CapStatus;

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

SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth,

             CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);

3.2.6显示对话框区设置视频属性

       每个捕获驱动器都可以提高3个以上的不同对话框来控制数字视频的特性和捕获处理。下面的例子示范如何显示这些对话框。在显示每个对话框前,该例会调用capDriverGetCaps宏并且检查返回的CAPDRIVERCAPS对象来查看是否可以能够显示特定的对话框。

 

CAPDRIVERCAPS CapDrvCaps;

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 (CapDriverCaps.fHasDlgVideoDisplay)

    capDlgVideoDisplay(hWndC);

 

3.2.7获得和设定视频格式

BITMAPINFO数据结构体可以实现长度可调节地去适应标准压缩的数据格式。因为它的长度可以变,所以在每次获得当前视频格式前,都必须去查询这个结构的长度以及分配的内存大小。该例子使用了capGetVideoFormatSize宏去获得缓存区大小,使用capGetVideoFormat宏区获得当前视频格式。

 

LPBITMAPINFO lpbi;

DWORD dwSize;

 

dwSize = capGetVideoFormatSize(hWndC);

lpbi = GlobalAllocPtr (GHND, dwSize);

capGetVideoFormat(hWndC, lpbi, dwSize);

 

// 访问视频格式,并且释放分配的内存。

 

应用程序使用capSetVideoFormat(WM_CAP_SET_VIDEOFORMAT),把一个BITMAPINFO结构发送给捕获窗口,显示修改。因为视频格式由设备指定的,你的应用程序可以去检查获得的返回值,来知道这个视频格式是不是公开的。

 

3.2.8预览视频

       下面使用capPreviewRate宏来设置预览模式的帧频率为66毫秒/帧,使用capPreview宏在捕获窗口预览图像。

 

capPreviewRate(hWndC, 66);      // 速度,微秒

capPreview(hWndC, TRUE);       // 开始预览

 

capPreview(hWnd, FALSE);        // 屏蔽预览

 

3.2.9允许视频覆盖(Overlay)

下面使用capDriverGetCaps宏去检测这个捕获驱动是否支持覆盖(Overlay)模式,如果支持,就允许视频覆盖模式;

 

CAPDRIVERCAPS CapDrvCaps;

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

if (CapDrvCaps.fHasOverlay)

    capOverlay(hWndC, TRUE);

 

 

3.2.10捕获文件命名

    下例使用capFileSetCaptureFile宏来指定一个要命名的文件名(mycap.avi),使用capFileAlloc宏去预分配5MB的文件。

 

char szCaptureFile[] = "MYCAP.AVI";

capFileSetCaptureFile( hWndC, szCaptureFile);

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

 

3.2.11格式化音频捕获

下例使用capSetAudioFormat来设置音频格式为11-KHz PCM 8-bit,立体声。

 

WAVEFORMATEX wfex;

wfex.wFormatTag = WAVE_FORMAT_PCM;

wfex.nChannels = 2;                     // 使用立体声

wfex.nSamplesPerSec = 11025;

wfex.nAvgBytesPerSec = 22050;

wfex.nBlockAlign = 2;

wfex.wBitsPerSample = 8;

wfex.cbSize = 0;

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

 

3.2.12改变视频捕获设置

       下例使用capCaptureGetSetupcapCaptureSetSetup宏来改变捕获速度,从默认值(15/)10/秒。

 

CAPTUREPARMS CaptureParms;

float FramesPerSec = 10.0;

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

CaptureParms.dwRequestMicroSecPerFrame = (DWORD) (1.0e6 /

    FramesPerSec);

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

 

3.2.13捕获数据

       下例使用capCaptureSequence宏开始视频捕获,使用capFileSaveAs宏从捕获文件拷贝数据到其他文件NEWFILE.AVI中。

 

char szNewName[] = "NEWFILE.AVI";

// Set up the capture operation.

capCaptureSequence(hWndC);

// Capture.

capFileSaveAs(hWndC, szNewName);

 

3.2.14加入信息块

如果你想添加其他信息(除了音视频),你可以建一个信息块并把它们插入到一个捕获文件中去。信息块可以包含这个方面的内容。比如版权信息,视频源的ID,外部显示的时间信息。下面的例子保存外部时间信息SMPTE()到一个信息块中,并加入使用capFileSetInfoChunk宏加入到捕获文件中。

 

//  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);

 

3.2.15在程序中加入回调函数

应用程序可以注册捕获窗口的回调函数,这样就可以把下面的情况通知给应用程序:

l         状态变化了

l         错误发生了

l         视频和音频的缓冲区的数据可以使用了

l         在捕获期间,应用程序将yield

下面的例子将创建一个捕获窗口并在应用的消息循环中,注状态、错误、视频流、帧的回调函数。

 

case WM_CREATE:

{

    char    achDeviceName[80] ;

    char    achDeviceVersion[100] ;

    char    achBuffer[100] ;

    WORD    wDriverCount = 0 ;

    WORD    wIndex ;

    WORD    wError ;

    HMENU   hMenu ;

 

    // 使用capCreateCaptureWindow宏创建一个捕获窗体.

    ghWndCap = capCreateCaptureWindow((LPSTR)"Capture Window",

        WS_CHILD | WS_VISIBLE, 0, 0, 160, 120, (HWND) hWnd, (int) 0);

 

    // 使用capSetCallbackOnError宏注册错误回调函数

     capSetCallbackOnError(ghWndCap, fpErrorCallback);

 

    // 使用capSetCallbackOnStatus宏注册状态回调函数

    capSetCallbackOnStatus(ghWndCap, fpStatusCallback);

 

    //使用capSetCallbackOnVideoStream宏注册视频流回调函数

    capSetCallbackOnVideoStream(ghWndCap, fpVideoCallback);

 

    //使用capSetCallbackOnFrame宏注册帧回调函数

    capSetCallbackOnFrame(ghWndCap, fpFrameCallback);

 

    // 连接到一个捕获驱动器上

 

    break;

}

case WM_CLOSE:

{

//使用capSetCallbackOnFrame宏关闭帧回调函数

// 类似可调用其他存在的回调函数。

 

    capSetCallbackOnFrame(hWndC, NULL);

  break;

}

 

 

 

3.2.16创建一个状态回调函数

下面的例子是一个简单的状态回调函数,使用capSetCallbackOnStatus宏来注册这个回调函数。

// StatusCallbackProc: 状态回调函数

// hWnd:            捕获窗体句柄

// nID:              当前状态的状态码

// lpStatusText:       当前状态的文本字符

//

LRESULT PASCAL StatusCallbackProc(HWND hWnd, int nID,

    LPSTR lpStatusText)

{

    if (!ghWndMain)

        return FALSE;

 

    if (nID == 0) {           // 清除旧的状态信息

        SetWindowText(ghWndMain, (LPSTR) gachAppName);

        return (LRESULT) TRUE;

    }

    // 显示状态ID和状态文本..

    wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText);

 

    SetWindowText(ghWndMain, (LPSTR)gachBuffer);

    return (LRESULT) TRUE;

}

 

3.2.17创建一个错误的回调函数

下面例子是一个简单的错误回调函数。通过capSetCallbackOnError宏来注册回调。

// ErrorCallbackProc:    错误回调函数

// hWnd:              捕获窗口句柄

// nErrID:              错误代码

// lpErrorText:          关于错误的文本信息

//

LRESULT PASCAL ErrorCallbackProc(HWND hWnd, int nErrID,

    LPSTR lpErrorText)

{

 

    if (!ghWndMain)

        return FALSE;

 

    if (nErrID == 0)            // Starting a new major function.

        return TRUE;          // 清除旧的错误

 

    // 显示错误ID和错误文本信息

    wsprintf(gachBuffer, "Error# %d", nErrID);

 

    MessageBox(hWnd, lpErrorText, gachBuffer,

               MB_OK | MB_ICONEXCLAMATION);

 

    return (LRESULT) TRUE;

}

 

3.2.18创建一个帧回调函数

下面是一个简单的帧回调函数。通过capSetCallbackFrame宏来注册回调函数。

 

// FrameCallbackProc:   帧回调函数

// hWnd:              捕获窗体句柄

// lpVHdr:             指向一个包含帧信息的数据结构体

//

LRESULT PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)

{

    if (!ghWndMain)

        return FALSE;

 

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

    SetWindowText(ghWndMain, (LPSTR)gachBuffer);

    return (LRESULT) TRUE ;

}

0 0
原创粉丝点击