设为首页 加入收藏

TOP

9.2.2 视频捕获类CCaptureClass的实现
2013-10-07 00:41:31 来源: 作者: 【 】 浏览:60
Tags:9.2.2 视频 捕获 CCaptureClass 实现

9.2.2  视频捕获类CCaptureClass的实现

在9.1.2节中讲述了CCaptureClass类的部分实现,现在详细讲述该类的成员变量和其他成员方法的实现,剖析其完成视频采集、保存的技术过程。

1)定义CCaptureClass类

class CCaptureClass
{
public:
CCaptureClass();          //类构造器
virtual ~CCaptureClass(); //类析构器
int EnumDevices(HWND hList);
void SaveGraph(TCHAR *wFileName);            //保存滤波器链表
void ConfigCameraPin(HWND hwndParent);       //配置摄像头的视频格式
void ConfigCameraFilter(HWND hwndParent);     //配置摄像头的图像参数
HRESULT CaptureImages(CString inFileName);    //捕获保存视频
HRESULT PreviewImages(int iDeviceID, HWND hWnd); //采集预览视频
private:
HWND       m_hWnd;          //视频显示窗口的句柄
IGraphBuilder    *m_pGB;          //滤波器链表管理器
ICaptureGraphBuilder2  *m_pCapture;  //增强型捕获滤波器链表管理器
IBaseFilter     *m_pBF;   //捕获滤波器
IMediaControl    *m_pMC;   //媒体控制接口
IVideoWindow     *m_pVW;   //视频显示窗口接口
IBaseFilter     *pMux;   //写文件滤波器
protected:
bool BindFilter(int deviceId, IBaseFilter **pFilter);   
//把指定的设备滤波器捆绑到链表中
void ResizeVideoWindow();               //更改视频显示窗口
HRESULT SetupVideoWindow();             //设置视频显示窗口的特性
HRESULT InitCaptureGraphBuilder();     //创建滤波器链表
管理器,查询其各种控制接口
};

上述代码是类CCaptureClass的成员变量和成员函数,成员变量包括DirectShow 开发流媒体播放应用程序需要的各种接口指针变量。成员函数实现创建滤波器链表管理器、配置视频采集格式、配置图像参数和保存滤波器链表等。

在类的构造器和析构器中完成对COM库的初始化和卸载,以及接口指针的初始化和资源释放。

/*定义的资源释放操作宏*/
#ifndef srelease
#define srelease(x)
if ( NULL != x )
{
x->Release( );
x = NULL;
}
#endif
/*类构造函数实现*/
CCaptureClass::CCaptureClass()
{
CoInitialize(NULL);  //COM 库初始化
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();     //卸载COM库
}

在类构造函数中,清空所有指针以便于清楚其后续操作的状态。析构函数释放各种资源、指针并清空指针,最后卸载COM库。

2)根据指定的设备ID,把基本滤波器与设备捆绑

首先枚举系统所有采集设备,直到列举的ID相同为止,最后BindToObject完成捆绑。

//把指定采集设备与滤波器捆绑
bool CCaptureClass::BindFilter(int deviceId, IBaseFilter **pFilter)
{
if (deviceId < 0) return false;
//枚举所有的视频捕获设备
ICreateDevEnum *pCreateDevEnum;
//生成设备枚举器pCreateDevEnum
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,
(void**)&pCreateDevEnum);
if (hr != NOERROR)  return false;
IEnumMoniker *pEm;
//创建视频输入设备类枚举器
hr = pCreateDevEnum->CreateClassEnumerator
(CLSID_VideoInputDeviceCategory,
&pEm, 0);
if (hr != NOERROR) return false;
pEm->Reset();         //复位该设备
ULONG cFetched;
IMoniker *pM;
int index = 0;
//获取设备
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= deviceId)
{
IPropertyBag *pBag;
//获取该设备的属性集
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;     //保存的是二进制的数据
hr = pBag->Read(L"FriendlyName", &var, NULL);
         //获取FriendlyName形式的信息
if (hr == NOERROR)
{
//采集设备与捕获滤波器捆绑
if (index == deviceId) pM->BindToObject(0, 0,
IID_IBaseFilter,         (void**)pFilter);
SysFreeString(var.bstrVal); //释放二进制数据资源,必须释放
}   
pBag->Release();
}
pM->Release();
index++;
}
return true;
}

该函数的传入参数是采集设备的索引号和捕获设备的滤波器。根据索引号查询系统中的视频捕获设备。以友好名字(FriendlyName)的方式获取所选设备的信息,然后把查询成功的设备与传入的滤波器捆绑,返回捕获设备的滤波器。

3)设置视频显示窗口

DirectShow的显示窗口与IVideoWindow接口的设置基本相同,把传入的显示窗口的句柄捆绑到IvideoWindow接口上。

/*设置视频显示窗口的特性*/
HRESULT CCaptureClass::SetupVideoWindow()
{
HRESULT hr;
//m_hWnd为类CCaptureClass的成员变量,在使用该函数前须初始化
hr = m_pVW->put_Visible(OAFALSE);                  //视频窗口不可见
hr = m_pVW->put_Owner((OAHWND)m_hWnd);      //窗口所有者:传入的窗口句柄
if (FAILED(hr)) return hr;
hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);//设置窗口类型
if (FAILED(hr)) return hr;
ResizeVideoWindow();                           //更改窗口大小
hr = m_pVW->put_Visible(OATRUE);              //视频窗口可见
return hr;
}
/*更改视频窗口大小*/
void CCaptureClass::ResizeVideoWindow()
{
if (m_pVW) {
//让图像充满整个指定窗口
CRect rc;
::GetClientRect(m_hWnd,&rc);    //获取显示窗口的客户区
m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);
//设置视频显示窗口的位置
}
}

在调用该函数前,需要把应用程序的显示窗口句柄传入以初始化m_hWnd。首先视频窗口不可见,捆绑传入的窗口句柄为视频窗口,设置窗口类型。ResizeVideoWindow函数获取显示窗口的客户区域,利用视频窗口接口的方法SetWindowPosition设置视频显示窗口的位置。

4)预览采集到的视频数据

使用上述有关的类成员函数初始化滤波器链表管理器,把指定采集设备的滤波器添加到链表中,然后渲染RenderStream方法把所有的滤波器链接起来,最后根据设定的显示窗口预览采集到的视频数据,具体实现过程如下。

/*开始预览视频数据*/
HRESULT CCaptureClass::PreviewImages(int iDeviceID, HWND hWnd)
{
HRESULT hr;
//初始化视频捕获滤波器链表管理器
hr = InitCaptureGraphBuilder();
if (FAILED(hr)) {
AfxMessageBox(_T("Failed to get video interfaces!"));
return hr;
}
//把指定采集设备与滤波器捆绑
if (!BindFilter(iDeviceID, &m_pBF))   return S_FALSE;
//把滤波器添加到滤波器链表中
hr = m_pGB->AddFilter(m_pBF, L"Capture Filter");
//渲染媒体,把链表中滤波器链接起来
hr = m_pCapture->RenderStream( &PIN_CATEGORY_PREVIEW,
      &MEDIATYPE_Video, m_pBF, NULL, NULL );
if( FAILED( hr ) ) {
AfxMessageBox(_T("Can't build the graph"));
return hr;
}
//设置视频显示窗口
m_hWnd = hWnd;         //初始化窗口句柄
SetupVideoWindow();   //设置显示窗口
hr = m_pMC->Run();   //开始采集、预览视频,在指定窗口显示视频
if(FAILED(hr)) {
AfxMessageBox(_T("Couldn't run the graph!"));
return hr;
}
return S_OK;
}

上述程序从最初的创建滤波器链表管理器、枚举系统视频采集设备、把采集设备与捕获滤波器捆绑,到添加滤波器到滤波器链表、设置视频显示窗口,最后开始运行媒体:采集、预览视频,包含了使用DirectShow SDK开发视频采集、预览的整个技术过程。函数功能独立而又完整。

5)保存采集到的数据

把捕获的视频以AVI格式写文件。注意设置前停止调用滤波器链表,设置完成后再运行链表。

 /*设置捕获视频的文件,开始捕捉视频数据写文件*/
HRESULT CCaptureClass::CaptureImages(CString inFileName)
{
HRESULT hr=0;
m_pMC->Stop();      //先停止视频
//设置文件名,注意第二个参数的类型
hr = m_pCapture->SetOutputFileName( &MEDIASUBTYPE_Avi,

inFileName.AllocSysString(), &pMux, NULL );
//渲染媒体,链接所有滤波器
hr = m_pCapture->RenderStream( &PIN_CATEGORY_CAPTURE,

&MEDIATYPE_Video, m_pBF, NULL, pMux );
pMux->Release();
m_pMC->Run();     //回复视频
return hr;
}
预览视频后,用户可以使用该函数存储捕获的视频数据。首先停止视频媒体,利用ICaptureGraphBuilder2的方法SetOutputFileName设置存储捕获数据的文件名,然后渲染视频媒体,RenderStream方法自动链接图表中的滤波器,最后开始运行视频媒体。
【责任编辑:云霞 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇14.5 本章小结 下一篇9.1.2 使用Capture Graph Builder

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: