VFW-MFC视频采集

2024-05-03 05:08
文章标签 视频 采集 mfc vfw

本文主要是介绍VFW-MFC视频采集,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

刚刚做了一个利用VFW(Video For Windows)的视频采集程序,就想写出来,给需要的人分享一下。程序并不复杂,关键是在没人指导的情况下,学习是比较痛苦和漫长的过程,我经历了这个过程,如果大家想避免走弯路,直接看我下面的解释就好了。由于我仅仅作出了结果,对很多东西的理解也许并不完全正确或者是完全错误,愿请指教。提前说一句,我的程序是在Visual C++6.0平台下写的。下面我慢慢说,你也慢慢听。

1 什么是VFW
    VFW 是微软的一个软件包,至少可以用来开发视频采集程序,当然还有别的用处,但不是我想关心的。VFW提供了基于消息的接口,而这些接口,也可以利用它本省定义的宏来实现。
2 怎么使用VFW
    写之前提示一句,可以参照MSDN看下面的内容,一定会更好。
    (1)创建一个基于对话框的程序,工程名称Grasp
     因为要用VFW,所以要包含头文件
     可在GraspDlg.h中加入 #include<Vfw.h>,然后Project ->Settings,在link标签页的Object/library modules :里面加入Vfw32.lib

    (2)在CGraspDlg类中添加一个窗口句柄HWND m_hVideo;
    (3)利用capCreateCaptureWindow函数创建窗口,并且得到返回的窗口句柄。
    m_hVideo=::capCreateCaptureWindow("Me",WS_CHILD | WS_VISIBLE,0,0,500,500,m_hWnd,0);

    上面这个函数写在BOOL CGraspDlg::OnInitDialog()中。参数m_hWnd是你的工程中对话框的句柄,窗口类中都有这个成员变量,而对话框的类是窗口类的子类,记得?
    (4)用capSetCallbackOnFrame宏注册回调函数,也写在BOOL CGraspDlg::OnInitDialog()中。
    capSetCallbackOnFrame(m_hVideo, FrameCallbackProc);
    上面第二个参数是回调函数的地址,名字可以自己来定义,但是回调函数必须有如下参数和返回值。
    LRESULT CALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr);
    人家规定的,咱们也没办法,就照着写就好啦。
    解释一下,什么是回调函数呢,它有什么用处?
    回调函数,就是你自己写的函数,符合规定的参数和返回值类型,符合规定的调用约定,比如上面这个函数
就是回调函数,参数和返回值类型都是规定好的,调用约定为CALLBACK,CALLBACK其实是一个宏#define CALLBACK__stdcall满足一定条件时,此函数可以被系统自动调用,在回调函数当中,你可以写自己的代码完成一定功能。
    比如在这里,用capSetCallbackOnFrame(m_hVideo, FrameCallbackProc)注册后,当每得到一桢数据后,系统就调用函数FrameCallbackProc。
    (5)因为注册了回调函数,所以,当然要自己写出这个函数了。

    在GraspDlg.cpp中,且在BOOL CGraspDlg::OnInitDialog()函数之前写下面代码:
     LRESULT CALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)
    {
        if (!ghVideo)
            return FALSE;

        return (LRESULT) TRUE ;
    }
    目前为止,该回调函数还没有什么作用,一会儿我们再来编写函数当中的代码,现在我就写的话,你也不见得看懂,不是么。一会儿写的话,你就可以轻松明白了。
    注意在这个函数中的ghVideo 了么?其实就和上面的m_hVideo一样,可是这里是全局函数,m_hVideo是对话框类的成员变量,
我写m_hVideo编译器是不认识的,对吧,所以,我又在GraspDlg.cpp当中定义了一个全局变量HWND ghVideo;并且,在m_hVideo=::capCreateCaptureWindow("Me",WS_CHILD | WS_VISIBLE,0,0,500,500,m_hWnd,0);之后加上一句ghVideo=m_hVideo; 这样就可以用ghVideo了。
    (6)在BOOL CGraspDlg::OnInitDialog()中继续添加如下代码:
    char szDeviceName[80];
    char szDeviceVersion[80];
    int wIndex;

    for (wIndex = 0; wIndex < 10; wIndex++)
    {
        if (capGetDriverDescription (wIndex, szDeviceName,sizeof (szDeviceName),

                szDeviceVersion,sizeof (szDeviceVersion)) )

        {
            if(capDriverConnect(m_hVideo,wIndex))
            {


            }
        }

    }
    上面代码中,capGetDriverDescription是列举所有可用视频的驱动程序,如果列举成功,用capDriverConnect进行连接。其实,我的机器上就装了一个摄像头,所以,只有当wIndex=0的时候,列举成功,并且连接也成功。这段代码好像很奇怪,因为列举成功之后,不论是否连接上,都没有做任何事情。其实可以用下面代码代替:
    char szDeviceName[80];
    char szDeviceVersion[80];
    //Get Driver description and the code can also be deleted as you want.
    capGetDriverDescription (0 szDeviceName,sizeof (szDeviceName), szDeviceVersion,
        sizeof (szDeviceVersion));
    //connect window to driver
    capDriverConnect(m_hVideo,0);
    (7)到这里,再加下面两句话你就会有成就感了,在BOOL CGraspDlg::OnInitDialog()中继续添加如下代码:
    capPreviewRate(m_hVideo,40); //设置Preview模式的显示速率
    capPreview(m_hVideo,TRUE); //启动Preview模式
    如果到此为止,已经完成了视频采集的全过程,你运行一下,就可以看到摄像头拍摄的画面了,显示在你的对话框上。但是,我的目的还没有达到,我其实想在每一桢显示之前,能处理一下这一桢的数据,那么,去哪里找这桢数据存放的位置呢?
   (8)为了完成我的目标,我把步骤(7)中的两句代码先注释掉。在对话框上加一个按钮,并在对单击做出响应的响应函数中写下面代码:
    capGrabFrame(m_hVideo);
    这是一个宏,将鼠标移动到这段代码上,右键单击,选择Go To Definition of capGrabFrame,你会看到
#define capGrabFrame(hwnd)((BOOL)AVICapSM(hwnd, WM_CAP_GRAB_FRAME, (WPARAM)0, (LPARAM)0L))
而继续察看AVICapSM宏你会看到其实是在调用SendMessage函数呢,对吧,其实就是在发送消息。至于消息谁处理了,我们就不去关心了,我们关心的是,发送消息后,系统会调用我们刚才注册的回调函数:
    LRESULT CALLBACK FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr) ;
    (9)好了,如果你单击按钮,capGrabFrame(m_hVideo)就发送消息了,然后,我们就进入回调函数了,这太好了。看到回调函数传递的两个参数了么?我们更关心第二个参数,这个就是单击按钮我们捕捉到的一桢数据的入口啊!
    LPVIDEOHDR 是结构体VIDEOHDR的指针,而在MSDN中察看结构体VIDEOHDR,我们就可以找到桢数据的存贮位置指针了。
    VIDEOHDR定义如下:
    typedef struct videohdr_tag {
        LPBYTE lpData;
        DWORD dwBufferLength;
        DWORD dwBytesUsed;
        DWORD dwTimeCaptured;
        DWORD dwUser;
        DWORD dwFlags;
        DWORD_PTRdwReserved[4];
    } VIDEOHDR, NEAR *PVIDEOHDR, FAR * LPVIDEOHDR;
    看到结构体中第一个参数了么?这个就是我们想要的桢数据的指针!后面参数,包括缓冲区长度等。
    (10)终于得到了缓冲区的数据,可是,又一个问题出现了,缓冲区中的数据到底具体是啥含义啊?
    这桢图像多大啊?size 是多少乘多少的啊?就是我们想要的像素信息么?
    好的,我先告诉你,缓冲区中全部是像素信息,我们照着我的步骤这样做,其实是默认了一些参数,包括图像的长度,宽度,色彩数,等等,那么,这个默认的值是多少呢?
    (11)用一下capGetVideoFormat宏吧,你会得到想要的东西。
    在BOOL CGraspDlg::OnInitDialog()中继续添加如下代码:
    BITMAPINFO bmpInfo;
    capGetVideoFormat(m_hVideo,&bmpInfo,sizeof(BITMAPINFO));
    BITMAPINFO结构体内容自己看MSDN.定义如下
    typedef struct tagBITMAPINFO {
        BITMAPINFOHEADER bmiHeader;
        RGBQUAD bmiColors[1];
    } BITMAPINFO, *PBITMAPINFO;
    BITMAPINFOHEADER定义如下:
    typedef struct tagBITMAPINFOHEADER{
        DWORD biSize;
        LONG biWidth;
        LONG biHeight;
        WORD biPlanes;
        WORD biBitCount;
        DWORD biCompression;
        DWORD biSizeImage;
        LONG biXPelsPerMeter;
        LONG biYPelsPerMeter;
        DWORD biClrUsed;
        DWORD biClrImportant;
    } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
    加入步骤(11)的两句话,调试运行,我发现,bmpInfo.bmiHeader.biWidth为320,就是采集的图像宽度;
bmpInfo.bmiHeader.biHeight为240,就是采集的图像高度,这些都是默认值,也可以改变这些值,通过
capSetVideoFormat宏来实现。
    (12)那么,我们在步骤(9)中,回调函数第二个参数对应的结构体VIDEOHDR中,图像数据缓冲区的大小dwBufferLength是多少呢?我们可以在回调函数中加一个MessageBox函数,输出这个值,我们就可以发现,为230400,这个数很好,正好等于图像宽度X图像高度的3倍,也就是说,是图像像素数目的3倍,这就对了,每个像素用3个字节存储的嘛。好啦,我们知道了,桢缓冲区中,存储的完全是图像的像素信息,那么,具体哪个值对应哪个像素呢?
    存储顺序是这样的:先从图像最下面一行开始,从左向右,依次存储,每一个像素用连续的3个字节,分别为B(蓝色分量),G(绿色分量),R(红色分量)。然后存储倒数第二行,仍然按照图像从左向右存储,然后倒数第三行,倒数第四行。。。。。。等等,最后存储正数第一行。
    好啦,我所有想说的都说完啦,你明白了么?好累,现在是晚上,快10点钟了,我正好要去跑步去了。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/laolei1986/archive/2010/07/13/5733046.aspx

这篇关于VFW-MFC视频采集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/955887

相关文章

Java如何获取视频文件的视频时长

《Java如何获取视频文件的视频时长》文章介绍了如何使用Java获取视频文件的视频时长,包括导入maven依赖和代码案例,同时,也讨论了在运行过程中遇到的SLF4J加载问题,并给出了解决方案... 目录Java获取视频文件的视频时长1、导入maven依赖2、代码案例3、SLF4J: Failed to lo

Python实现多路视频多窗口播放功能

《Python实现多路视频多窗口播放功能》这篇文章主要为大家详细介绍了Python实现多路视频多窗口播放功能的相关知识,文中的示例代码讲解详细,有需要的小伙伴可以跟随小编一起学习一下... 目录一、python实现多路视频播放功能二、代码实现三、打包代码实现总结一、python实现多路视频播放功能服务端开

Python实现视频转换为音频的方法详解

《Python实现视频转换为音频的方法详解》这篇文章主要为大家详细Python如何将视频转换为音频并将音频文件保存到特定文件夹下,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5. 注意事项

Python视频处理库VidGear使用小结

《Python视频处理库VidGear使用小结》VidGear是一个高性能的Python视频处理库,本文主要介绍了Python视频处理库VidGear使用小结,文中通过示例代码介绍的非常详细,对大家的... 目录一、VidGear的安装二、VidGear的主要功能三、VidGear的使用示例四、VidGea

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

树莓派5_opencv笔记27:Opencv录制视频(无声音)

今日继续学习树莓派5 8G:(Raspberry Pi,简称RPi或RasPi)  本人所用树莓派5 装载的系统与版本如下:  版本可用命令 (lsb_release -a) 查询: Opencv 与 python 版本如下: 今天就水一篇文章,用树莓派摄像头,Opencv录制一段视频保存在指定目录... 文章提供测试代码讲解,整体代码贴出、测试效果图 目录 阶段一:录制一段

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是: