一、VFW简介
VFW(Video for Windows)是微软提供的数字视频开发包。
VFW有许多函数,详细可参考http://blog.csdn.net/laolei1986/article/details/5733051
下面介绍几个用到的函数:
1、创建视频捕捉窗口
HWND VFWAPI capCreateCaptureWindow(
LPCSTR lpszWindowName, //视频捕捉窗口的名称
DWORD dwStyle, //视频捕捉窗口风格,比如WS_CHILD和 WS_VISIBLE
int x,//(x,y)表示视频捕捉窗口的左上角坐标
int y,
int nWidth, //窗口宽度
int nHeight, //窗口高度
HWND hWnd, //父窗口句柄
int nID//窗口标志
);
2、视频驱动程序与预览窗口连接函数BOOL VFWAPI capDriverConnect(
HWND hWnd, //capCreateWindow函数生成的窗口句柄,即捕捉窗口句柄
int driverId //驱动程序编号,默认为0。可以在System.ini文件中查找
);
3、设置预览帧频率
BOOL VFWAPI capPreviewRate(
HWND hWnd, //预览窗口句柄
in frame//帧频率
);
4、预览函数
BOOL VFWAPI capPreview(
HWNDhWnd, //预览窗口句柄
BOOLflag //FALSE定帧,即预览停止,TRUE则开始预览
);
5、截获当前图片
BOOL VFWAPI capGrabFrameNoStop(
HWND hwnd//预览窗口句柄
);
//复制到剪切板
BOOL VFWAPI capEditCopy(
HWND hwnd //预览窗口句柄
);
二、编码实现
1、新建工程,切换到资源视图,添加一个dialog用于显示视频预览,属性Border设置为None,Control设置为True,在对话框上添加一个Picture控件用于显示预览。如下图:
2、为该对话框添加CVedioDlg类,(Video拼错了,囧,忽略之)
在该类中引入VFW库
要访问对话框资源,所以直接在对话框类中实现预览功能,在有Control类来调用其方法。VedioDlg.h文件如下:
#pragma once #include <vfw.h> //视频处理类库 #pragma comment(lib,"vfw32.lib") // CVedioDlg 对话框 class CVedioDlg : public CDialogEx { DECLARE_DYNAMIC(CVedioDlg) public: CVedioDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CVedioDlg(); public: void OpenCamera();//打开摄像头 void StartCapture();//开始捕捉 void TakePicture();//拍照 void StopCamera();//停止捕捉 void CloseCamera();//关闭摄像头 public: friend UINT vproc(LPVOID pParam);//暂时没用到 friend LRESULT CALLBACK backproc(HWND hwnd,LPVIDEOHDR lpVHDR);<span style="font-family: Arial, Helvetica, sans-serif;">//暂时没用到</span> HWND videohwnd; CStatic CAPVIDEO; int wIndex; CEvent e; BOOL m_connect;//设备连接标志 BOOL m_open;//设备打开标志 // 对话框数据 enum { IDD = IDD_PICTURE }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() };
// VedioDlg.cpp : 实现文件 // #include "stdafx.h" #include "VedioCapture.h" #include "VedioDlg.h" #include "afxdialogex.h" // CVedioDlg 对话框 IMPLEMENT_DYNAMIC(CVedioDlg, CDialogEx) CVedioDlg::CVedioDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CVedioDlg::IDD, pParent) { wIndex = 0; m_connect = FALSE; m_open = FALSE; } CVedioDlg::~CVedioDlg() { } void CVedioDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX,IDC_VIDEO,CAPVIDEO); } BEGIN_MESSAGE_MAP(CVedioDlg, CDialogEx) END_MESSAGE_MAP() // CVedioDlg 消息处理程序 void CVedioDlg::OpenCamera() { // tran = NULL; /* e.ResetEvent();*/ videohwnd = capCreateCaptureWindow(NULL,WS_POPUP,0,0,10,10,0,0); // AfxBeginThread(vproc,(void*)this);//开始线程 // ::WaitForSingleObject(e,INFINITE); if (videohwnd == 0) { m_open = FALSE; AfxMessageBox(_T("创建AVI窗口失败")); return; } m_open = TRUE;//打开标志 } void CVedioDlg::StartCapture() { char szDeviceName[80]; char szDeviceVersion[80]; CRect rc; CAPVIDEO.GetWindowRect(&rc); ScreenToClient(rc); CAPDRIVERCAPS capd; CAPSTATUS caps; if (m_connect == TRUE)//处于连接状态 { //capPreviewRate(videohwnd,60); capPreview(videohwnd,TRUE); return; } // if(!capGetDriverDescription(wIndex,(LPWSTR)szDeviceName,sizeof szDeviceName // ,(LPWSTR)szDeviceVersion,sizeof szDeviceVersion)) // { // AfxMessageBox(_T("无可用视频设备!")); // return ; // } if (capDriverConnect(videohwnd,wIndex) == TRUE) { m_connect == TRUE; capDriverGetCaps(videohwnd,sizeof(CAPDRIVERCAPS),&capd); capGetStatus(videohwnd,&caps,sizeof CAPSTATUS); //capCaptureSequence(videohwnd); //开始捕捉视频,默认保存为CAPTURE.avi ::SetParent(videohwnd,*this); ::SetWindowLong(videohwnd,GWL_STYLE,WS_CHILD); ::SetWindowPos(videohwnd,NULL,rc.left,rc.top,rc.Width(),rc.Height(),SWP_NOZORDER); ::ShowWindow(videohwnd,SW_SHOW); capPreviewRate(videohwnd,60); capPreview(videohwnd,TRUE); } } void CVedioDlg::StopCamera() { //capCaptureStop(videohwnd);//停止捕捉 capPreview(videohwnd,FALSE);//定帧 //Sleep(5000); //capPreview(videohwnd,TRUE); //capDriverDisconnect(videohwnd);//断开连接 } void CVedioDlg::CloseCamera() { if(m_open == TRUE) { capDriverDisconnect(videohwnd);//断开连接 ::CloseWindow(videohwnd);//最小化窗口 ::DestroyWindow(videohwnd);//销毁窗口 m_open = FALSE; m_connect = FALSE; } //this->OnCancel();//退出对话框 } void CVedioDlg::TakePicture() { CAPTUREPARMS params; capCaptureGetSetup(videohwnd,¶ms,sizeof params); capPreview(videohwnd,FALSE);//定帧 capGrabFrameNoStop(videohwnd);//截获当前图像 capEditCopy(videohwnd);//将图像拷贝到剪切板 } static UINT vproc(LPVOID pParam) { CVedioDlg *p = (CVedioDlg*)pParam; HWND hwnd = capCreateCaptureWindow(NULL,WS_POPUP,0,0,10,10,0,0); if (hwnd) { p->videohwnd = hwnd; p->e.SetEvent(); } MSG msg; while (GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK backproc(HWND hwnd,LPVIDEOHDR lpVHDR) { return 0; }
实现方法:
头文件中定义CVedioDlg m_VedioDlg;
// CVedioCaptureCtrl 消息处理程序 int CVedioCaptureCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (COleControl::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 m_VedioDlg.Create(IDD_PICTURE,this);//创建对话框 m_VedioDlg.OpenCamera(); return 0; } void CVedioCaptureCtrl::OnSize(UINT nType, int cx, int cy) { COleControl::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 RECT ActiveXRect; GetClientRect(&ActiveXRect); m_VedioDlg.MoveWindow(&ActiveXRect); } //开始生成预览 void CVedioCaptureCtrl::StartPreview(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加调度处理程序代码 int count = 2;//尝试连接次数 if (m_VedioDlg.m_open == FALSE) { m_VedioDlg.OpenCamera();//先打开设备 } while(count-- > 0) { m_VedioDlg.StartCapture(); } } //停止预览 void CVedioCaptureCtrl::StopPreview(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加调度处理程序代码 m_VedioDlg.StopCamera(); } //关闭预览 void CVedioCaptureCtrl::CancelPreview(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加调度处理程序代码 //m_VedioDlg.StopCamera(); m_VedioDlg.CloseCamera(); } //拍照 void CVedioCaptureCtrl::TakePicture(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加调度处理程序代码 m_VedioDlg.TakePicture(); } void CVedioCaptureCtrl::OpenPreview(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加调度处理程序代码 if(!m_VedioDlg.m_open) m_VedioDlg.OpenCamera(); }
4、测试
html代码:这html代码一看就不专业,毕竟不是研究这个的,囧
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title> New Document </title> <meta name="Generator" content="EditPlus"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> </head> <!--调用代码 ----------------------------- JS处理代码如下--> <script type="text/javascript"> function JoinGame() { //alert("已执行"); var tgame=document.getElementById("ClockOCX"); tgame.Hello(); } function StartPreview() { var video=document.getElementById("VedioCapture"); video.StartPreview(); } function StopPreview() { var video=document.getElementById("VedioCapture"); video.StopPreview(); } function CancelPreview() { var video=document.getElementById("VedioCapture"); video.CancelPreview(); } function Takepicture() { var video=document.getElementById("VedioCapture"); video.Takepicture(); } </script> <body> <div id="container"> <!-- 加载时钟控件--> <div id="clock"> <div id="tip"> <p>时钟显示:</p> </div> <OBJECT ID="ClockOCX" CLASSID="clsid:33E08641-67AD-48DA-9B03-EE694A20B51F"></OBJECT> <div id="clockctrl"> <!--通过一个html的按钮实现调用:--> <input type="button" onclick="JoinGame()" value="调用"/> </div> </div> <!--视频控件--> <div id="video"> <OBJECT ID="VedioCapture" CLASSID="clsid:E1971791-858E-44F1-8D58-9D4F30C1B4F8" height=280px width=380px> </OBJECT> <div id="videoctrl"> <button type="button" onclick="StartPreview()">开始预览</button> <button type="button" onclick="Takepicture()">拍照</button> <button type="button" onclick="CancelPreview()">取消预览</button> <button type="button" onclick="StopPreview()">停止预览</button> </div> </div> </div> </body> </html>停止预览就是定帧,取消预览就是关闭预览窗口。点击拍照即可将抓取的图片复制到剪切板中,打开画图板复制进去就可以看到图片。。。