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视频采集相关推荐
- 使用VFW开发视频采集软件
VFW是Video For Windows的缩写,使用VFW可以快速开发Windows视频采集软件.VFW开发的资源可以参考MSDN中的Video Capture一节的内容,当然也可以参考网上一些翻译 ...
- Window 下 VFW 视频采集与显示
引言 经过几天的努力终于将VFW视频采集与显示功能完整实现了,不得不说网上对这方面完整的详细讲解文章是在太少了.所以就要本人来好好总结一下让后来者不再像我一样折腾好久.在本文中我将详细讲解VFW视频采 ...
- .VC++关于的VFW视频采集方案【转 360doc】
2.2 VFW视频采集方案 VFW是Microsoft于1992年推出的数字视频软件包,它不依赖于专用的硬件设备,提供了通用的数字视频开发方案.VFW主要由AVICap.dll.MSVideo.dl ...
- VFW视频采集方案(Captureparms参数详细)
2.2 VFW视频采集方案 VFW是Microsoft于1992年推出的数字视频软件包,它不依赖于专用的硬件设备,提供了通用的数字视频开发方 案.VFW主要由AVICap.dll.MSVideo.dl ...
- 音视频采集—Windows平台VFW
因为Windows开发相对方便一些,所以将VFW作为入门篇进行分享. VFW(Video for Windows)是Microsoft推出的关于数字视频的一个软件开发包. 我们在这里主要分享:核心AP ...
- VC++实现视频聊天:VFW视频采集+FFmpeg编码
上次介绍了视频聊天软件的界面.文字聊天.文件传输部分,这此介绍视频聊天功能,这算是音视频领域一个很广的应用.首先视频聊天的双方需要有一个USB摄像头(或者笔记本摄像头),在windows系统下,一个完 ...
- (转载)视频采集学习笔记
视频采集学习笔记 第一节.视频采集 一.二者的不同点: 说起视频捕捉问题,我们先要来看一下视频捕捉卡.根据使用的驱动程序的不同来分类,目前市场上大致有两种捕捉卡:VFW (Video for Wi ...
- FFMPEG Qt录屏软件开发之视频采集
前面讲解了视频播放器的开发,初步掌握了使用FFMPEG解码音视频. 现在我们就接着讲解使用FFMPEG来编码音视频,主要是实现一个录屏软件的制作. 一个录屏软件的流程基本就是: 图像采集 图像编码 将 ...
- VFW连接视频驱动不成功问题解决
使用VFW进行视频捕获时,使用capdriverconnect宏连接视频驱动时, 一般方法是 if(capDriverConnect(m_hwnd,0){ //连接视频驱动成功后进行的动作 } el ...
- 流媒体之DirectShow——视频采集
文章目录 一:介绍 二:设备枚举 三:Video Graph 3.1 视频预览 3.2 录制视频到AVI文件 3.3 录制视频到Windows Media File(ASF) 3.4 录制视频到其他文 ...
最新文章
- Python函数16道入门练习题
- 【Splay】【块状链表】bzoj3223 Tyvj 1729 文艺平衡树
- 为什么在子类中不重写超类的实例变量
- android 闪存软件测试,手机为什么这么卡:闪存I/O测试AndroBench
- 服务器间传文件$d,基于OpenSSH+WinSCP完成Windows服务器之间的文件传输
- mysql syncmasterinfo_sync_master_info的一些说明
- 【转】MySQL索引和查询优化
- php base64_decode 图片,php读取和保存base64编码图片
- 妨碍编译器优化的因素
- 电动牙刷C语言程序,电动牙刷的日常维护
- 量产软件测试培训,U盘量产及在虚拟机中测试
- (Linux)简单电子通讯录
- throw Exception
- 分形理论在地理信息科学研究中的应用
- 图片没有透明效果html,为什么png不是透明底
- PHP 合成图片并在图片上加文字
- 统计软件与数据分析—Lesson2
- 接口显示返回值正常,但是拿到的值却是undefined?
- Corrective feedback
- 未来五年最赚钱的不是股市、房地产,而是......
热门文章
- HTML DOM 事件 —— 鼠标事件 JS鼠标事件
- 浅论计算机基础课程远程教学系统的设计和实现
- QQ好友列表名片点赞全自动脚本,使用autojs开发的免root运行
- 手机屏幕常见故障_【最新推荐】手机触摸屏常见问题及解决方法-范文模板 (3页)...
- 硬件设计基础----二极管
- 模电1.2 半导体二极管
- BIT2023 智慧社区综合管理系统-二周目
- KubeVela 1.4:让应用交付更安全、上手更简单、过程更透明
- Matlab:提取或分配日期时间数组的日期时间分量
- away3d学习笔记 转载