VFW视频捕捉流程(摄像头)

时间:2022-11-14 18:58:31

在VC++上使用VFW需要加入对vfw32.lib的引用。在中有一个AVICap窗口类,负责视频和音频硬件沟通,并把视频捕捉的数据保存为AVI文件,这个类是基于消息的。

(1)引用头文件,导入库文件

#include "vfw.h"
#pragma comment(lib,"vfw32")

(2)创建一个线程,在其中调用capCreateCaptureWindow创建视频捕捉窗口。

下面是在同一个线程中实现:

hVideoWnd = capCreateCaptureWindow("Capture",WS_VISIBLE | WS_CHILD,10,10,300,300,*this,0);

hVideoWnd是HWND类型全局变量。

(3)调用capDriverConnect连接驱动程序。

(4)调用capPreviewRate设置预览速度。

(5)调用capPreview开始预览。

一个简单代码如下:(可以将其放到OnInitDialog()函数中)

 

hVideoWnd = capCreateCaptureWindow("Capture",WS_VISIBLE | WS_CHILD,10,10,300,300,*this,0);
 if(capDriverConnect(hVideoWnd,0))
 {
  capPreviewRate(hVideoWnd,66);
  capPreview(hVideoWnd,TRUE);
 }

运行程序后就会在对话框中看到视频。

capGrabFrame(hVideoWnd);这个函数可以实现捕捉图片,我们可以在对话框上添加一个按钮,在按钮的处理函数中,加入这个函数就可以了,按一下图片就会截图。

但是你会发现截图后,视频就不动了,怎么办?可以用以下代码,同时可以实现将截图送到剪贴板:

capGrabFrame(hVideoWnd);
 capEditCopy(hVideoWnd);
 capPreview(hVideoWnd,TRUE);

 

下面是创建一个新的线程的实现:(这段代码可以放到OnInitDialog中)

	m_pThread = AfxBeginThread(ThreadFun,(LPVOID)this);
	m_Event.ResetEvent();
	::WaitForSingleObject(m_Event,INFINITE);
	if(m_hVideoWnd)
	{
		if(capDriverConnect(m_hVideoWnd,0) == FALSE)
		{
			AfxMessageBox("Connect Driver error!");
			return;
		}
		::SetParent(m_hVideoWnd,*this);
		::SetWindowLong(m_hVideoWnd,GWL_STYLE,WS_CHILD);
		::SetWindowPos(m_hVideoWnd,NULL,10,10,300,300,SWP_NOREDRAW);
		::ShowWindow(m_hVideoWnd,SW_SHOW);
		capPreviewRate(m_hVideoWnd,10);
		capPreview(m_hVideoWnd,TRUE);
	}


 

UINT CImageAcquisitionDlg::ThreadFun(LPVOID lpParam)
{
	CImageAcquisitionDlg *temp = (CImageAcquisitionDlg*)lpParam;
	temp->m_hVideoWnd = capCreateCaptureWindow("Capture",WS_POPUP,10,10,20,20,*temp,0);
	if(temp->m_hVideoWnd)
	{
		temp->m_Event.SetEvent();
		MSG msg;
		while(GetMessage(&msg,temp->m_hVideoWnd,0,0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		return msg.wParam;
	}
	return 0;
}


 

下面是网上查找的一些资料:

用户界面线程和工作者线程都是由AfxBeginThread创建的。MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程:
用户界面线程的AfxBeginThread的原型如下:   
CWinThread* AFXAPI AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs)   
其中:   
参数1是从CWinThread派生的RUNTIME_CLASS类;   
参数2指定线程优先级,如果为0,则与创建该线程的线程相同;   
参数3指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;   
参数4是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。   
参数5表示线程的安全属性,NT下有用。   

工作者线程的AfxBeginThread的原型如下:    
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID lParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL   );
返回值: 一个指向新线程的线程对象的指针   
pfnThreadProc : 线程的入口函数,声明一定要如下:
UINT MyThreadFunction( LPVOID pParam ),不能设置为NULL;   
lpParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.   
nPriority : 线程的优先级,一般设置为 0 .让它和主线程具有共同的优先级.   
nStackSize : 指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈   
dwCreateFlags : 指定创建线程以后,线程有怎么样的标志.可以指定两个值:   
CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread   
0 : 创建线程后就开始运行.   
lpSecurityAttrs : 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL , 那么新创建的线程就具有和主线程一样的安全性.   
如果要在线程内结束线程,可以在线程内调用 AfxEndThread.   

结束线程的两种方式   
1 : 这是最简单的方式,也就是让线程函数执行完成,此时线程正常结束.它会返回一个值,一般0是成功结束,   
当然你可以定义自己的认为合适的值来代表线程成功执行.在线程内调用AfxEndThread将会直接结束线程,此时线程的一切资源都会被回收.   
2 : 如果你想让另一个线程B来结束线程A,那么,你就需要在这两个线程中传递信息.   
不管是工作者线程还是界面线程,如果你想在线程结束后得到它的结果,那么你可以调用:   
::GetExitCodeThread函数

DWORD WINAPI WaitForSingleObject( __in HANDLE hHandle, __in DWORD dwMilliseconds );
参数
  hHandle [in]对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。   
当等待仍在挂起状态时,句柄被关闭,那么函数行为是未定义的。该句柄必须具有 SYNCHRONIZE 访问权限。   
dwMilliseconds [in]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle 标记的对象被触发,或者时间到了。如果dwMilliseconds 为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds 为INFINITE,对象被触发信号后,函数才会返回。
 
WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。   

返回值:   
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。   
WAIT_OBJECT_0 0x00000000 :核心对象已被激活   
WAIT_TIMEOUT 0x00000102:等待超时   
WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

HWND VFWAPI capCreateCaptureWindow(
  LPCTSTR lpszWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWnd,
  int nID
);

Parameters
lpszWindowName
Null-terminated string containing the name used for the capture window.

dwStyle
Window styles used for the capture window. Window styles are described with the CreateWindowEx function.

x
The x-coordinate of the upper left corner of the capture window.

y
The y-coordinate of the upper left corner of the capture window.

nWidth
Width of the capture window.

nHeight
Height of the capture window.

hWnd
Handle to the parent window.

nID
Window identifier.


BOOL capDriverConnect(hwnd,iIndex)
hwnd:标识视频捕捉窗口句柄
iIndex:标识驱动程序,范围是0-9

HWND SetParent(HWND hWndChild,HWND hWndNewParent)
改变某个子窗口的父窗口。
hWndChild:子窗口句柄。   
hWndNewParent:新的父窗口句柄。如果该参数是NULL,则桌面窗口就成为新的父窗口。在WindowsNT5.0中,如果参数为HWND_MESSAGE,则子窗口成为消息窗口。