概述
PS:原来发表在百度空间的,但百度空间已发展成交友网站了,so,挪个地儿。原帖地址:http://hi.baidu.com/%C0%DA%CE%DE%B5%D02008/blog/item/60196025ba35b5104c088d8c.html
我用visual studio 2005编了一个摄像头预览程序,还可以导出成avi文件,前提是要安装directshow,并搭建好环境,我安装的是directx 9.0b,搭建环境很简单,网上有很多,注意在项目-属性-配置属性-链接器-输入中要加上strmbasd.lib winmm.lib(中间有空格)。源代码如下:
/*CaptureClass.h*/
#pragma once
#include <atlbase.h>
#include <windows.h>
#include <DShow.h>
#include <qedit.h>//ISampleGrabber接口要求的
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
#endif
class CCaptureClass
{
public:
CCaptureClass(void);
public:
~CCaptureClass(void);
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(); //创建滤波器链表管理器,查询其各种控制接口
};
/*CaptureClass.cpp*/
#include "StdAfx.h"
#include "CaptureClass.h"
/************************************************************************/
/* 类构造函数实现 */
/************************************************************************/
CCaptureClass::CCaptureClass(void)
{
CoInitialize(NULL); //COM库初始化
m_hWnd = NULL; //视频显示窗口的句柄
m_pVW = NULL ; //视频窗口接口指针清空
m_pMC = NULL ; //媒体控制接口指针清空
m_pGB = NULL ; //滤波器链表管理器接口指针清空
m_pBF = NULL ; //捕获滤波器接口指针清空
m_pCapture = NULL ; //增强型捕获滤波器链表管理器接口指针清空
}
/************************************************************************/
/* 析构函数 */
/************************************************************************/
CCaptureClass::~CCaptureClass(void)
{
if(m_pMC) m_pMC ->Stop(); //首先停止媒体
if(m_pVW){
m_pVW->put_Visible(OAFALSE); //视频窗口不可见
m_pVW->put_Owner(NULL); //视频窗口的父窗口清空
}
SAFE_RELEASE(m_pCapture); //释放增强型捕获滤波器链表管理器接口
SAFE_RELEASE(m_pMC); //释放媒体控制接口
SAFE_RELEASE(m_pGB); //释放滤波器链表管理器接口
SAFE_RELEASE(m_pBF); //释放捕获滤波器接口
CoUninitialize( ); //卸载COM库
}
/************************************************************************/
/* 把指定采集设备与滤波器捆绑 */
/************************************************************************/
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 ;
}
/************************************************************************/
/* 设置视频显示窗口的特性 */
/************************************************************************/
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); //设置视频显示窗口的位置
}
}
/************************************************************************/
/* 开始预览视频设备 */
/************************************************************************/
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 ;
}
/************************************************************************/
/* 设置捕获视频的文件,开始捕捉视频数据写文件 */
/************************************************************************/
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 ;
}
int CCaptureClass::EnumDevices(HWND hList)
{
if (!hList)
return -1;
int id = 0;
//枚举视频扑捉设备
ICreateDevEnum *pCreateDevEnum; /*此接口生成一个特殊类别的设备枚举器,The System Device Enumerator exposes this interface*/
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (hr != NOERROR)return -1;
IEnumMoniker *pEm=0; //此接口用来枚举一个"名字"组件或者枚举名字表中的名字
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);//CreateClassEnumerator方法为指定的设备类生成一个类枚举器
if (hr != NOERROR)return -1;
pEm->Reset(); //由于IEnumMoniker接口有一个标准的参考计数,pEm->Release(),一定要释放此接口
ULONG cFetched;
IMoniker *pM; //此接口包含允许你使用“名字”对象的方法,而名字对象包含能唯一确定COM对象的方法
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK) //返回枚举器队列中指定数目的条款,下“1”个
{
IPropertyBag *pBag; //接口IPropertyBag提供一个有属性包的对象,对象可以在包里存储它的特征
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag); //返回包含被“moniker”确定的对象的存储位置的接口指针
if(SUCCEEDED(hr))
{
VARIANT var; //VARIANT结构体包括很多类型
var.vt = VT_BSTR; //vt, describes which of the union members is valid,bstrVal是有效的
hr = pBag->Read(L"FriendlyName", &var, NULL); //Asks the property bag to read the named
//property into a caller-initialized VARIANT,var接收
if (hr == NOERROR)
{
//CP_ACP:The current system Windows "ANSI" code page
//var.bstrVal被转化的
//-1表示长度被自动计算;str表示转化侯接收目标的地方;两个NULL使函数更快
id++;
//此函数处理指定的消息,hList窗口的句柄,此窗口处理此消息;CB_ADDSTRING要处理的消息
::SendMessage(hList, CB_ADDSTRING, 0,(LPARAM)var.bstrVal);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
pM->Release();
}
return id;
}
HRESULT CCaptureClass::InitCaptureGraphBuilder()
{
HRESULT hr ;
//创建IGraphBuilder接口
hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&m_pGB);
if(FAILED(hr)) return hr ;
//创建ICaptureGraphBuilder2接口
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,CLSCTX_INPROC,IID_ICaptureGraphBuilder2,(void**)&m_pCapture) ;
if(FAILED(hr)) return hr ;
//初始化滤波器链表管理器IGraphBuilder
m_pCapture->SetFiltergraph(m_pGB);
//查询媒体控制接口
hr = m_pGB->QueryInterface(IID_IMediaControl,(void**)&m_pMC);
if(FAILED(hr)) return hr ;
//查询视频窗口接口
hr = m_pGB -> QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
if(FAILED(hr)) return hr ;
return hr ;
}
//
//配置摄像头数据源格式:分辨率、RGB/I420等
void CCaptureClass::ConfigCameraPin(HWND hwndParent)
{
HRESULT hr ; //返回值
IAMStreamConfig *pSC ; //流配置接口
ISpecifyPropertyPages *pSpec ; //属性页接口
//只有停止后,才能进行引脚属性的设置
m_pMC ->Stop();
//首先查询捕获CAPTURE、视频VIDEO接口
hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,m_pBF,IID_IAMStreamConfig,(void**)&pSC);
CAUUID cauuid ; //所有属性页结构体
hr = pSC->QueryInterface(IID_ISpecifyPropertyPages,(void**)&pSpec);
if( hr == S_OK ){
hr = pSpec->GetPages(&cauuid); //获取所有属性页
//显示属性页
hr = OleCreatePropertyFrame(hwndParent,30,30,NULL,1,(IUnknown**)&pSC,cauuid.cElems,(GUID*)cauuid.pElems,0,0,NULL);
//释放内存、资源
CoTaskMemFree(cauuid.pElems);
pSpec->Release();
pSC->Release();
}
//回复运行
m_pMC->Run();
}
//
//配置图像参数:亮度、色度、饱和度等
void CCaptureClass::ConfigCameraFilter(HWND hwndParent)
{
HRESULT hr = 0 ;
ISpecifyPropertyPages *pProp ;
hr = m_pBF->QueryInterface(IID_ISpecifyPropertyPages,(void**)&pProp);
if(SUCCEEDED(hr))
{
//获取滤波器名称和IUnknown接口指针
FILTER_INFO FilterInfo ;
hr = m_pBF->QueryFilterInfo(&FilterInfo);
IUnknown *pFilterUnk ;
m_pBF->QueryInterface(IID_IUnknown,(void**)&pFilterUnk);
//显示该页
CAUUID caGUID ;
pProp ->GetPages(&caGUID);
OleCreatePropertyFrame(
hwndParent,
0,0,
FilterInfo.achName,
1,
&pFilterUnk,
caGUID.cElems,
caGUID.pElems,
0,
0,NULL
);
//释放内存、资源
CoTaskMemFree(caGUID.pElems);
pFilterUnk->Release();
FilterInfo.pGraph ->Release();
pProp->Release();
}
m_pMC->Run();
}
在dialog类中声明一个CaptureClass的对象m_cap:
/*CaptureVideoDlg.h*/
#pragma once
#include "afxwin.h"
#include "CaptureClass.h"
// CCaptureVideoDlg 对话框
class CCaptureVideoDlg : public CDialog
{
// 构造
public:
CCaptureVideoDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_CAPTUREVIDEO_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CStatic m_videoWindow;
public:
CComboBox m_listCtrl;
CCaptureClass m_cap ;
public:
afx_msg void OnBnClickedPreview();
public:
afx_msg void OnBnClickedCapture();
public:
afx_msg void OnBnClickedVideoFormat();
public:
afx_msg void OnBnClickedImageParameter();
public:
afx_msg void OnBnClickedExit();
};
/*CaptureVideoDlg.cpp*/
#include "stdafx.h"
#include "CaptureVideo.h"
#include "CaptureVideoDlg.h"
………………………………
BOOL CCaptureVideoDlg::OnInitDialog()
{
…………
// TODO: 在此添加额外的初始化代码
m_cap.EnumDevices(m_listCtrl);//枚举视频设备,并发送消息给设备下拉列表
m_listCtrl.SetCurSel(0);
…………
}
void CCaptureVideoDlg::OnBnClickedPreview()
{
// TODO: 在此添加控件通知处理程序代码
HWND hVWindow = m_videoWindow.GetSafeHwnd(); //获取视频显示窗口的句柄
int id = m_listCtrl.GetCurSel(); //获取当前选中的视频设备
m_cap.PreviewImages(id,hVWindow);
}
void CCaptureVideoDlg::OnBnClickedCapture()
{
// TODO: 在此添加控件通知处理程序代码
CString strFilter = _T("AVI FILE (*.avi)| *.avi|"); //文件类型过滤器
strFilter += "All File (*.*) | *.* |";
CFileDialog dlg( TRUE , NULL,NULL,OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,strFilter,this);
if(dlg.DoModal() == IDOK ){
CString m_sourceFile = dlg.GetPathName(); //获取用户输入的文件路径名
m_cap.CaptureImages(m_sourceFile);
}
}
void CCaptureVideoDlg::OnBnClickedVideoFormat()
{
// TODO: 在此添加控件通知处理程序代码
m_cap.ConfigCameraPin(this->m_hWnd);
}
void CCaptureVideoDlg::OnBnClickedImageParameter()
{
// TODO: 在此添加控件通知处理程序代码
m_cap.ConfigCameraFilter(this->m_hWnd);
}
void CCaptureVideoDlg::OnBnClickedExit()
{
// TODO: 在此添加控件通知处理程序代码
CDialog::OnOK();
}
源代码下载地址:
http://u.115.com/file/aq20aqgm#CaptureVideo.rar
最后
以上就是爱听歌抽屉为你收集整理的directshow实现视频捕获(源码)vs2005的全部内容,希望文章能够帮你解决directshow实现视频捕获(源码)vs2005所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复