视频采集器设计总结.docx
《视频采集器设计总结.docx》由会员分享,可在线阅读,更多相关《视频采集器设计总结.docx(49页珍藏版)》请在冰豆网上搜索。
![视频采集器设计总结.docx](https://file1.bdocx.com/fileroot1/2023-2/25/c9a10941-7a69-4ae7-8e49-09742c5da6bf/c9a10941-7a69-4ae7-8e49-09742c5da6bf1.gif)
视频采集器设计总结
福建工程学院
VC++课程设计
课题:
视频采集器
指导老师:
黄旭红
班级:
电子1001
组员:
刘碧端3100204104
李鑫煌3100204111
沈文海3100204112
郑德明3100204113
王桂德3100204122
陈志阳3100204123
吴碧武3100204124
日期:
2013年3月15日
一、设计目的与要求
为了轻松地记录视频和从摄像头、电视调谐卡、数码摄像机中捕捉实时图像,可利用VC++的DirectShow开发包,编写视频采集器软件系统,采集所需的图像。
1.菜单式的人机界面。
2.具有开始、停止、录像、抓图等功能。
二、准备工作
本次设计在VisualStudio2005集成开发环境下完成,利用VC++的DirectShow开发包,编写视频采集器软件系统,采集所需的图像。
DirectShowSDK是Microsoft微软公司为简化或降低音/视频开发的难度而为音/视频应用开发人员定制的开发包、软件库。
它是我们熟悉的DirectX家族中的一个组件,主要针对程序员开发数字音/视频程序提供支持。
。
使用DirectShow我们可以在很短的时间内搭建自己的视频播放、捕获和编辑应用程序,不必对有关视频硬件如显卡,视频捕获设备,视频编码算法,解码算法,音/视频数据同步等,复杂的技术做细节的掌握。
另外,由于现在的视频捕获设备如USB摄像头,视频捕获卡,显卡等主流的驱动均是WDM模式。
VC++开发人员自己访问、控制、读取此类设备的数据显然不是件容易的事情。
DirectShow却可以很灵活地帮助我们去完成工作,即屏蔽了我们直接对硬件的操作,又可快速开发出我们自己的产品。
DirectShowSDK是为多媒体数据流的应用而开发的。
它支持多媒体流的捕获和预览。
运用Directshow,用户可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且可以进行相应的后期处理甚至存储到文件中;同时可以方便地构建影音文件的回放、编辑等操作。
使用DirectShow能够完成以下工作:
.音/视频多媒体流的捕获和预览。
.支持多媒体格式ASF、MPEG、AVI、MP3、WAVE的回放。
.集成其他DirectX技术,增强音/视频硬件如声卡、显卡的性能。
.视频文件的回放、非线性吧,编辑等。
.支持DVD等设备。
.定制自己的Filter。
三、系统分析
3.1系统整体设计设计思路
3.1.1、基于VC++的视频采集系统
3.1.2、显示模块
3.2系统的实现方法
3.2.1设计方案分析
3-1系统框图
USB视频捕捉设备输入视频流,经过SmartTee分流成两路,一路流向AVIMux混频器最终保存为avi视频文件。
另一路通过AVIDecompressor视频解码器输出到电脑显示器VideoRender。
整个方案实现了“视频监控”与“文件保存”的同时进行。
3.2.2、主要类函数的实现
3.2.2.1采集设备的枚举
使用采集设备前,需要首先确定系统己经安装的采集设备:
视频、音频采集设备。
系统设备枚举器为按类型枚举已注册在系统中的滤波器提供了统一的方法。
而且它能够区分不同的硬件设备。
当利用系统设备枚举器查询设备的时候,系统设备枚举器为特定类型的设备(如音频捕获和视频压缩)牛成了一张枚举表.类型枚举器为每个这种类型的设备返回一个Moniker,类型枚举器自动把每种即插即用的设备包含在内。
调用标准方法生成系统设备枚举器,类标识,代码如下:
intCCaptureClass:
:
EnumDevices(HWNDhList)
{
if(!
hList)return-1;
intid=0;
ICreateDevEnum*pCreateDevEnum;//枚举捕获设备
HRESULThr=CoCreateInstance(CLSID_SystemDeviceEnum,NULL,
CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,
(void**)&pCreateDevEnum);
if(hr!
=NOERROR)return-1;
IEnumMoniker*pEm;
//创建视频类型枚举器pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory,&pEm,0);
if(hr!
=NOERROR)return-1;
//类型枚举器复位
pEm->Reset();
ULONGcFetched;
IMoniker*pM;
while(hr=pEm->Next(1,&pM,&cFetched),hr==S_OK)
{
IPropertyBag*pBag;//设备属性页
hr=pM->BindToStorage(0,0,IID_IPropertyBag,(void**)&pBag);
if(SUCCEEDED(hr))
{
VARIANTvar;
var.vt=VT_BSTR;
hr=pBag->Read(L"FriendlyName",&var,NULL);
if(hr==NOERROR)
{
id++;
:
:
SendMessage(hList,CB_ADDSTRING,0,(LPARAM)var.bstrVal);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
pM->Release();
}
returnid;
}
3.2.2.2把指定采集设备与滤波器捆绑
使用DirectShov的滤波器进行流媒体开发,需要一个管理器即滤波器链表管理器,DirectShowSDK提供的是GraphBuilder接口IgraphBuilder。
不过针对捕获仟务(Capture),还有另一个接口ICaptureBuilder2针对采集捕获的增强型接口.
/*创建滤波器链表管理器,查询其各种控制接口*/
HRESULTCCaptureClass:
:
InitCaptureGraphBuilder()
{
HRESULThr;
//创建IGraphBuilder接口
hr=CoCreateInstance(CLSID_FilterGraph,NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,(void**)&m_pGB);
if(FAILED(hr))returnhr;
//创建ICaptureGraphBuilder2接口
hr=CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,
CLSCTX_INPROC,
IID_ICaptureGraphBuilder2,(void**)&m_pCapture);
if(FAILED(hr))returnhr;
//初始化滤波器链表管理器IGraphBuilder
m_pCapture->SetFiltergraph(m_pGB);
//查询媒体控制接口
hr=m_pGB->QueryInterface(IID_IMediaControl,(void**)&m_pMC);
if(FAILED(hr))returnhr;
//查询视频窗口接口
hr=m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
if(FAILED(hr))returnhr;
returnhr;
}
在上述程序中,IGraphBuilder接口,然后创建IcapturGraphBuilder2接口,接着使用ICaptureGraphBuilder初始化IGraphBuiider接口。
在IGraphBuilder接口下查询媒体控制接口、视频窗口接口。
/*开始预览视频数据*/
HRESULTCCaptureClass:
:
PreviewImages(intiDeviceID,HWNDhWnd)
{
HRESULThr;
//初始化视频捕获滤波器链表管理器
hr=InitCaptureGraphBuilder();
if(FAILED(hr))
{AfxMessageBox(_T("Failedtogetvideointerfaces!
"));
returnhr;
}
//把指定采集设备与滤波器捆绑
if(!
BindFilter(iDeviceID,&m_pBF))
returnS_FALSE;
//把滤波器添加到滤波器链表中
hr=m_pGB->AddFilter(m_pBF,L"CaptureFilter");
//渲染媒体,把链表中滤波器连接起来Hr=m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,m_pBF,NULL,NULL);
if(FAILED(hr))
{AfxMessageBox(_T("Can’tbuildthegraph"));
returnhr;
}
//设置视频显示窗口
m_hWnd=hWnd;
SetupVideoWindow();
//testforconfig
hr=m_pMC->Run();
if(FAILED(hr))
{AfxMessageBox(_T("Couldn’trunthegraph!
"));
returnhr;
}
returnS_OK;
}
四、系统实现步骤
1.应用VS2005应用程序向导建立对话框程序框架,项目名称为CapnueVideoe。
2.在项目CaptureVideo的主界面中添加控件:
6个Button,1个ComboBox,1个PictureConvol,如表4-1所示。
根据其功能修改所有控件的ID。
名称
说明
ID_PREVIEW
连接设备
ID_CAPTURE
开始录像
ID_VIDEO_FORMAT
视频格式
ID_IMAGE_PARAMETER
画面参数
ID_SAVEGRAPH
截取图片
ID_EXIT
退出保存
IDC_DEVICE_LISTER
设备列表组合框
IDC_VIDEO_WINDOW
显示捕获的视频图像
表4—1
3.在添加所有的控件后,修改控件大小。
重排其位置。
添加控件后的主界面设计如图4-2所示。
图4-2
4.控件与变量捆绑。
为便于控制,把IDC_VIDEOWINDOW控件、
IDC_DEVICELISTER控件分别与变量捆绑。
途径是选择控件的右键菜单中的“添加变量”命令。
5.添加按钮在线提示ToolTip,首先在类CCaptureVideoDlg定义中声明tooltip控件。
接着在类CCapwreVideoDlg实现文件的对话框初始化函数OnInidJialog中添加:
m_tooltip.Create(this);
m_tooltip.Activate(TRUE);
m_tooltip.AddTool(GetDlgItem(ID_PREVIEW),_T("打开摄像头"));
在PreTranslateMessage消息处理函数中添加如下代码:
m_tooltip.RelayEvent(pMsg);
6.功能按钮的消息响应,即单击按钮的事件处理。
双击某按钮,实现单击按钮事件处理函数的添加。
为了使用类CCaptureClass的变量和函数在CCapmreVideoDlg类中引入头文件并定义视频捕获类的对象。
首先引入头文件:
#include"CaptureClass.h"。
接着在CCaptureVideoDlg类中定义视频捕获类的对象:
7.CCaptureClassm_cap;双击“连接设备”按钮,添加事件处理代码:
voidCCaptureVideoDlg:
:
OnBnClickedPreview()
{
HWNDhVWindow=m_videoWindow.GetSafeHwnd();
intid=m_listCtrl.GetCurSel();
m_cap.PreviewImages(id,hVWindow);
}
获取视频显示窗口的句柄,根据程序最初枚举到的所有采集设备,选择用户选中的采集设备。
调用视频捕获类的成员函数Previewlmage,完成整个视频的采集、显示任务。
图4-3所示为“连接设备”按钮实现的效果图。
图4-3
双击“开始录像”按钮,添加事件处理代码。
voidCCaptureVideoDlg:
:
OnBnClickedCapture()
{
CStringstrFilter=_T("AVIFile(*.avi)|*.avi|");
strFilter+="AllFile(*.*)|*.*|";
CFileDialogdlg(TRUE,NULL,NULL,OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,strFilter,this);
if(dlg.DoModal()==IDOK)
{
CStringm_sourceFile=dlg.GetPathName();
m_cap.CaptureImages(m_sourceFile);
}
}
存储捕获的视频,这里采用AVI格式,视频数据未经压缩。
调用视频捕获类CCaptureClass的成员函数CaptureImages完成视频的捕获、存储任务。
本案例需要先预览视频,然后再开始捕获、存储视频,不能直接捕获、存储视颇。
双击“视频格式"按钮,添加事件处理代码。
voidCCaptureVideoDlg:
:
OnBnClickedVideoFormat()
{
m_cap.ConfigCameraPin(this->m_hWnd);
}
设置视频格式前,首先启动“连接设备”,然后再配置视频的格式。
视频格式包括帧率、颜色空间、视频分辨率等,该功能的效果如图4-4所示。
图4-4
双击“画面参数”按钮,添加事件处理代码。
voidCCaptureVideoDlg:
:
OnBnClickedImageParameter()
{
m_cap.ConfigCameraFilter(this->m_hWnd);
}
设置视频图像参数前,首先启动“连接设备”,然后配置画面参数。
画面参数包括图像渲染、白平衡、防闪烁、亮度、对比度等,该功能的效果如图4-5所示。
并且该功能调整的参数马上起作用。
图4-5
双击“保存图表”按钮,添加事件处理代码。
voidCCaptureVideoDlg:
:
OnBnClickedSavegraph()
{
CFileDialogdlg(TRUE);
if(dlg.DoModal()==IDOK)
{
CStringstr=dlg.GetPathName();
TCHAR*inFileName=str.GetBuffer(str.GetLength());
str.ReleaseBuffer();
m_cap.SaveGraph(inFileName);
}
}
本功能存储的Graph文件可以使用程序GraphEdit播放。
双击“退出程序”按钮,添加事件处理代码。
程序隐含调用了类CCaptureClass的析构函数,释放资源和COM库。
voidCCaptureVideoDlg:
:
OnBnClickedExit()
{
CDialog:
:
OnOK();
}
退出本程序时,由于视频捕获类CCaptureClass的析构函数已经包含了释放资源、指针的工作,所以退出应用程序时不用释放任何资源,只是关闭应用程序。
8.在对话框的初始化OnInitDialog中枚举本系统的视频采集设备,添加到列表框并默认显示第一个设备。
m_cap.EnumDevices(m_listCtrl.GetSafeHwnd());
m_listCtrl.SetCurSel(0);
五、测试与结论
程序的屏幕显示如5-1所示:
图5-1
说明:
1.灰色款图为视频显示框,当连接设备后会显示摄像头捕获的图像。
2.图中组合框为设备名称,默认为显示第一个设备的名称,当电脑有多个摄像头设备时可选择。
3.连接设备按钮即打开摄像头,只有当连接设备后才可以进行后面按钮的操作,否则将退出程序。
4.开始录像按钮为开始捕获、保存视频,保存路径在按钮后选择。
5.视频格式中为数据流选项,可以选择视频帧率、大小等选项。
6.画面参数中有高级选项,摄像头设置,可以控制摄像头亮度、对比度、饱和度等选项。
7.截取图片能够实现对图像的截取并保存图片。
8.保存退出按钮退出程序。
综上所述,我们小组较好的完成了本次设计题目的要求,并还增加了其他功能。
六、课程设计总结
6.1程序特点及功能扩展
程序在实现各项基本要求的情况下还有其他扩展功能:
(1)、能够实现对不同设备的识别,并能够自动加载设备本身所具有的媒体特性。
(2)、能够实现对画面的亮度、对比度、饱和度等基本选项进行设置,也能对画面进行渲染等特殊功能。
(3)、能够实现对视频像素的调节。
(4)、能够调节帧率。
6.2独创及创新点
(1)能够对不同设备的识别并且调用设备的媒体特性,如可以对电脑上多个设备进行切换,并且能够有相应的设备选项供选择。
七、参考文献
1、董正言,张聪.面向对象程序设计(C++版).清华大学出版社.
2、路锦正,周冬梅.VisualC++音频/视频处理技术及工程实践.电子工业出版社.
3、文东,华进.VisualC++程序设计基础与项目实训.北京科海电子出版社.
4、陆其明.DirectShow开发指南.清华大学出版社.
5、电子发烧友网
6、全球最大中文IT社区
八、附录
8.1完整程序代码
8.1.1CCaptureClass视频捕捉类实现文件CaptureVideo.cpp
//CaptureVideo.cpp:
implementationoftheCCaptureClassclass.
//
#include"stdafx.h"
#include"CaptureClass.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
//////////////////////////////////////////////////////////////////////
//Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCaptureClass:
:
CCaptureClass()
{
//COM库初始化
CoInitialize(NULL);
m_hWnd=NULL;
m_pVW=NULL;
m_pMC=NULL;
m_pGB=NULL;
m_pBF=NULL;
m_pCapture=NULL;
}
CCaptureClass:
:
~CCaptureClass()
{
//
if(m_pMC)
m_pMC->Stop();
if(m_pVW)
{
m_pVW->put_Visible(OAFALSE);
m_pVW->put_Owner(NULL);
}
srelease(m_pCapture);
srelease(m_pMC);
srelease(m_pGB);
srelease(m_pBF);
CoUninitialize();
}
intCCaptureClass:
:
EnumDevices(HWNDhList)
{
if(!
hList)return-1;
intid=0;
//枚举捕获设备
ICreateDevEnum*pCreateDevEnum;
HRESULThr=CoCreateInstance(CLSID_SystemDeviceEnum,NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,
(void**)&pCreateDevEnum);
if(hr!
=NOERROR)return-1;
IEnumMoniker*pEm;
//创建视频类型枚举器
hr=pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm,0);
//创建音频捕获类
//hr=pCreateDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory,&pEm,0);
if(hr!
=NOERROR)return-1;
//类型枚举器复位
pEm->Reset();
ULONGcFetched;
IMoniker*pM;
while(hr=pEm->Next(1,&pM,&cFetched),hr==S_OK)
{
IPropertyBag*pBag;
//设备属性页
hr=pM->BindToStorage(0,0,IID_IPropertyBag,(void**)&pBag);
if(SUCCEEDED(hr))
{
VARIANTvar;
var.vt=VT_BSTR;
hr=pBag->Read(L"FriendlyName",&var,NULL);
if(hr==NOERROR)
{
id++;
:
:
SendMessage(hList,CB_ADDSTRING,0,(LPARAM)var