目的:通过USB视频源获取视频,在VC6.0中的MFC环境下,使用系统自带的VFW实现视频的显示,并实现鼠标双击视频最大化显示。
工具:USB摄像头 VC6.0 VFW
方法:通过使用SetWindowLong给创建的窗口添加过程函数,解惑鼠标双击消息,然后通过自定义的消息,实现过程函数与主窗口的通信,实现全屏显示。下面我通过几个步骤介绍我的实现过程。
(1)实现视屏的显示。利用VFW的自带API函数实现视频的显示。这里就不做赘述。网上有多资料,我把代码贴出来。
BOOL CVideoTestDlg::OnInitDialog()
{
// TODO: Add extra initialization here
g_hDlg = m_hWnd;
m_hWndVideo = capCreateCaptureWindow(NULL,WS_POPUP,0,0,640,480,m_hWnd,0);
m_flag = capDriverConnect(m_hWndVideo,0);//链接驱动程序
if(!m_flag)
MessageBox("请确认USB视频源已连接!");
while(!m_flag)
{
m_flag = capDriverConnect(m_hWndVideo,0);
}
if(m_flag)
{
::SetParent(m_hWndVideo,*this);
::SetWindowLong(m_hWndVideo,GWL_STYLE,WS_CHILD);
//设置窗口过程函数响应鼠标双击消息 pOldWndProc=(WNDPROC)SetWindowLong(m_hWndVideo,GWL_WNDPROC,(LONG)NewWndProc);
//视频居中显示使用
GetClientRect(wndRC);
x_original = wndRC.Width()/2;
y_original = wndRC.Height()/2; ::SetWindowPos(m_hWndVideo,NULL,x_original-320,y_original-240,640,480,SWP_NOZORDER);
::ShowWindow(m_hWndVideo,SW_SHOW);
capPreviewRate(m_hWndVideo,20);
capPreview(m_hWndVideo,TRUE);
}
return TRUE; // return TRUE unless you set the focus to a control
}
头文件如下:
HWND m_hWndVideo;//视频显示窗口
BOOL m_flag;
BOOL m_flagDlg;//是否最大化标志
int x_original,y_original; //客户区中心位置
CRect wndRC;
(2)窗口过程函数在调用前定义(在孙鑫的第7讲中有详细的介绍和源码可以参考),过程函数的定义代码如下:
WNDPROC pOldWndProc;
HWND g_hDlg;//当前运行窗口句柄
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_LBUTTONDBLCLK:
::PostMessage(g_hDlg,WM_MYDBCLICK,0,0);
break;
default :
break;
}
return pOldWndProc(hWnd,uMsg,wParam,lParam);
}
主要是截获鼠标的左键双击消息,并向主窗口发送自定义的WM_MYDBCLICK消息。
注意:在发送消息时,需要指定窗口句柄,我的实现方式是定义了一个全局的HWND变量g_hDlg;在OnInitialDialog中把主窗口句柄赋值过来,具体如上所示。
(3)自定义消息WM_MYDBCLICK。
具体的自定义过程就不说了,消息的实现部分如下:
LRESULT CVideoTestDlg::OnMyLBtnDBClick(WPARAM wParam,LPARAM lParam)
{
if(!m_flagDlg)
{
ShowWindow(SW_MAXIMIZE);
//隐藏对话框的标题栏
ModifyStyle(WS_CAPTION,0,SWP_FRAMECHANGED);
m_flagDlg = TRUE;
Invalidate();
}
else
{
ShowWindow(SW_NORMAL);
//显示
ModifyStyle(0,WS_CAPTION,SWP_FRAMECHANGED);
m_flagDlg = FALSE;
Invalidate();
}
return 0L;
}
通过以上的就可以实现了。
接下来的部分就是实现背景图的绘制和文字显示。
细节部分有:从资源导入位图,文本的背景色透明,文本宽度获取并居中。
(1)参考CSDN邓的方法,在BOOL CVideoTestDlg::OnEraseBkgnd(CDC* pDC){}实现了背景图的加载和文本的输出。
BOOL CVideoTestDlg::OnEraseBkgnd(CDC* pDC)
{
GetClientRect(wndRC);
x_original = wndRC.Width()/2;
y_original = wndRC.Height()/2;
::SetWindowPos(m_hWndVideo,NULL,x_original-320,y_original-240,640,480,SWP_NOZORDER);
::ShowWindow(m_hWndVideo,SW_SHOW);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
BITMAP bitmapInfo;
bitmap.GetBitmap(&bitmapInfo);
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
dcMem.SelectObject(&bitmap);
CRect rect;
GetWindowRect(rect);
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmapInfo.bmWidth,bitmapInfo.bmHeight,SRCCOPY);
//字体及输出位置指定
CFont font;
font.CreatePointFont(300,"华文行楷",NULL);//创建字体
CFont *pOldFont=pDC->SelectObject(&font);
CSize sz = pDC->GetTextExtent("闪亮之星现场");//获取字串的宽高
pDC->SetTextColor(RGB(255,255,0));
pDC->SetBkMode(TRANSPARENT);//设置透明背景
pDC->TextOut(x_original-sz.cx/2,y_original-250-sz.cy,"闪亮之星现场");
pDC->SelectObject(pOldFont);
ReleaseDC(&dcMem);
return TRUE;
//return CDialog::OnEraseBkgnd(pDC);
}