注册通行证 用户名 密码
  • 文章投稿
  • 博客
  • 论坛
  • 设为首页
  • 加入收藏
jztop.com网络技术
  • 首页
  • | iT新闻
  • | 操作系统
  • | 组网建网
  • | 网络安全
  • | 程序开发
  • | 办公一族
  • | 工具软件
  • | 网页制作
  • | 多媒体制作
  • | 网吧技术
  • | 服务器
  • | 专题教程
Vista | 软件评测 | 系统备份 | 优化 | 进程 | 聊天 | 病毒 | Linux | 黑客 | 防火墙 | 数据库 | Web开发 | Java | Word | 游戏 | 32位开发 | 移动开发
当前位置:首页 > 程序开发 > 32位开发 > C/C++ 内容正文:Visual C++编程实现摄像头视频捕捉

Visual C++编程实现摄像头视频捕捉

发布时间:2006-05-05 19:02:47 来源:天极网 网友评论 0 条

摘要:本文主要讲述用Directshow进行视频捕捉(捕捉静态图像)的编程思路,并提供针对摄像头编程的一个视频捕捉类CcaptureVideo和一个示例。

  前言

DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布。DirectShow为多媒体流的捕捉和回放提供了强有力的支持。用DirectShow开发应用程序,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。

  DirectShow是基于COM的,为了编写DirectShow应用程序,需要了解COM客户程序编写的基础知识。DirectShow提供了大量的接口,但在编程中发现还是不够方便,如果能构建一个视频捕捉类把常用的一些动作封装起来,那么就更方便了。

  编程思路

  为了更加容易建立视频捕捉应用程序,DirectShow提供了一个叫做Capture Graph Builder的对象,Capture Graph Builder提供IcaptureGraphBuilder2接口,该接口可以建立和控制Capture Graph。

  建立视频捕捉程序,必须首先获取并初始化IcaptureGraphBuilder2接口,然后选择一个适当的视频捕捉设备。选择好设备后,为该设备创建Capture filter,然后调用AddFilter把Capture filter添加到Filter Graph。

  如果仅仅希望用摄像头来进行实时监控的话,只需要在上面的基础上调用ICaptureGraphBuilder2::RenderStream就可以了:

ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
//省略初始化部分代码
IBaseFilter *pCap; // Video capture filter.
//省略初始化和添加到Filter Graph部分代码
pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);

  DirectShow提供了一个捕捉静态图像的方法:使用Sample Grabber filter。依次按照以下三个步骤就可以了:

  第一步, 定义一个类实现Sample Grabber的回调接口IsampleGrabberCB:

class CSampleGrabberCB : public ISampleGrabberCB
{
  //在后面提供的类中具体完成
}
CSampleGrabberCB mCB;

  第二步、调用RenderStream依次把Still pin、Sample Grabber和系统默认Renderer Filter连接起来。

  第三步、配置Sample Grabber以捕获数据。

  视频捕捉类CCaptureVideo的具体实现

// CCaptureVideo视频捕捉类头文件
/////////////////////////////////////////////////////////////////////
#if !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_)
#define AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_
/////////////////////////////////////////////////////////////////////
// CaptureVideo.h : header file
/////////////////////////////////////////////////////////////////////
#if _MSC_VER >1000
#pragma once
#endif // _MSC_VER >1000
#include
#include
#include
#ifndef SAFE_RELEASE
#define SAFE_RELEASE( x ) /
if ( NULL != x ) /
{ /
  x->Release( ); /
  x = NULL; /
}
#endif
class CSampleGrabberCB;
class CCaptureVideo : public CWnd
{
  friend class CSampleGrabberCB;
  public:
   void GrabOneFrame(BOOL bGrab);
   HRESULT Init(int iDeviceID,HWND hWnd);
   int EnumDevices(HWND hList);
   CCaptureVideo();
   virtual ~CCaptureVideo();
  private:
   HWND m_hWnd;
   IGraphBuilder *m_pGB;
   ICaptureGraphBuilder2* m_pCapture;
   IBaseFilter* m_pBF;
   IMediaControl* m_pMC;
   IVideoWindow* m_pVW;
   CComPtrm_pGrabber;
  protected:
   void FreeMediaType(AM_MEDIA_TYPE& mt);
   bool BindFilter(int deviceId, IBaseFilter **pFilter);
   void ResizeVideoWindow();
   HRESULT SetupVideoWindow();
   HRESULT InitCaptureGraphBuilder();
};
#endif // !defined(AFX_CAPTUREVIDEO_H__F5345AA4_A39F_4B07_B843_3D87C4287AA0__INCLUDED_)
//-------------------------------------------------------------------
// CCaptureVideo视频捕捉类实现文件CaptureVideo.cpp
//-------------------------------------------------------------------
// CaptureVideo.cpp: implementation of the CCaptureVideo class.
//
/////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CaptureVideo.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
BOOL bOneShot=FALSE;//全局变量
class CSampleGrabberCB : public ISampleGrabberCB
{
  public:
   long lWidth;
   long lHeight;
   TCHAR m_szFileName[MAX_PATH];// 位图文件名称
   CSampleGrabberCB( ){
    strcpy(m_szFileName, "c://donaldo.bmp");
   }
   STDMETHODIMP_(ULONG) AddRef() { return 2; }
   STDMETHODIMP_(ULONG) Release() { return 1; }
   STDMETHODIMP QueryInterface(REFIID riid, void ** ppv){
   if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ){
    *ppv = (void *) static_cast( this );
    return NOERROR;
   }
   return E_NOINTERFACE;
  }
  STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ){
  return 0;
}
STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ){
  if( !bOneShot )return 0;
 
  if (!pBuffer)return E_POINTER;
  SaveBitmap(pBuffer, lBufferSize);
  bOneShot = FALSE;
  return 0;
}
//创建位图文件
BOOL SaveBitmap(BYTE * pBuffer, long lBufferSize )
{
  HANDLE hf = CreateFile(
  m_szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  CREATE_ALWAYS, NULL, NULL );
  if( hf == INVALID_HANDLE_VALUE )return 0;
   // 写文件头
   BITMAPFILEHEADER bfh;
   memset( &bfh, 0, sizeof( bfh ) );
   bfh.bfType = ’MB’;
   bfh.bfSize = sizeof( bfh ) + lBufferSize + sizeof( BITMAPINFOHEADER );
   bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER );
   DWORD dwWritten = 0;
   WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
   // 写位图格式
   BITMAPINFOHEADER bih;
   memset( &bih, 0, sizeof( bih ) );
   bih.biSize = sizeof( bih );
   bih.biWidth = lWidth;
   bih.biHeight = lHeight;
   bih.biPlanes = 1;
   bih.biBitCount = 24;
   WriteFile( hf, &bih, sizeof( bih ), &dwWritten, NULL );
   // 写位图数据
   WriteFile( hf, pBuffer, lBufferSize, &dwWritten, NULL );
   CloseHandle( hf );
   return 0;
  }
};
CSampleGrabberCB mCB;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCaptureVideo::CCaptureVideo()
{
  //COM Library Intialization
  if(FAILED(CoInitialize(NULL))) /*, COINIT_APARTMENTTHREADED)))*/
  {
   AfxMessageBox("CoInitialize Failed!/r/n");
   return;
  }
  m_hWnd = NULL;
  m_pVW = NULL;
  m_pMC = NULL;
  m_pGB = NULL;
  m_pCapture = NULL;
}
CCaptureVideo::~CCaptureVideo()
{
  // Stop media playback
  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( );
}
int CCaptureVideo::EnumDevices(HWND hList)
{
  if (!hList)
   return -1;
  int id = 0;

  //枚举视频扑捉设备
  ICreateDevEnum *pCreateDevEnum;
  HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);

  if (hr != NOERROR)return -1;
  CComPtrpEm;
  hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);

  if (hr != NOERROR)return -1;
  pEm->Reset();
  ULONG cFetched;
  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))
   {
    VARIANT var;
    var.vt = VT_BSTR;
    hr = pBag->Read(L"FriendlyName", &var, NULL);
    if (hr == NOERROR)
    {
     TCHAR str[2048];
     id++;
     WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, str, 2048, NULL, NULL);
     ::SendMessage(hList, CB_ADDSTRING, 0,(LPARAM)str);
     SysFreeString(var.bstrVal);
    }
    pBag->Release();
   }
   pM->Release();
  }
  return id;
}
HRESULT CCaptureVideo::Init(int iDeviceID, HWND hWnd)
{
  HRESULT hr;
  hr = InitCaptureGraphBuilder();
  if (FAILED(hr)){
   AfxMessageBox("Failed to get video interfaces!");
   return hr;
  }
  // Bind Device Filter. We know the device because the id was passed in
  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);
  // create a sample grabber
  hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
  if( !m_pGrabber ){
   AfxMessageBox("Fail to create SampleGrabber, maybe qedit.dll is not registered?");
   return hr;
  }
  CComQIPtr< IBaseFilter, &IID_IBaseFilter >pGrabBase( m_pGrabber );

  //设置视频格式
  AM_MEDIA_TYPE mt;
  ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
  mt.majortype = MEDIATYPE_Video;
  mt.subtype = MEDIASUBTYPE_RGB24;
  hr = m_pGrabber->SetMediaType(&mt);

  if( FAILED( hr ) ){
   AfxMessageBox("Fail to set media type!");
   return hr;
  }
  hr = m_pGB->AddFilter( pGrabBase, L"Grabber" );
  if( FAILED( hr ) ){
   AfxMessageBox("Fail to put sample grabber in graph");
   return hr;
  }

  // try to render preview/capture pin
  hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
  if( FAILED( hr ) )
   hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);

   if( FAILED( hr ) ){
    AfxMessageBox("Can’t build the graph");
    return hr;
   }
 
  hr = m_pGrabber->GetConnectedMediaType( &mt );
  if ( FAILED( hr) ){
   AfxMessageBox("Failt to read the connected media type");
   return hr;
  }

  VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
  mCB.lWidth = vih->bmiHeader.biWidth;
  mCB.lHeight = vih->bmiHeader.biHeight;
  FreeMediaType(mt);
  hr = m_pGrabber->SetBufferSamples( FALSE );
  hr = m_pGrabber->SetOneShot( FALSE );
  hr = m_pGrabber->SetCallback( &mCB, 1 );

  //设置视频捕捉窗口
  m_hWnd = hWnd ;
  SetupVideoWindow();
  hr = m_pMC->Run();//开始视频捕捉
  if(FAILED(hr)){AfxMessageBox("Couldn’t run the graph!");return hr;}
  return S_OK;
}
bool CCaptureVideo::BindFilter(int deviceId, IBaseFilter **pFilter)
{
  if (deviceId < 0)
  return false;

  // enumerate all video capture devices
  CComPtrpCreateDevEnum;
  HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
  if (hr != NOERROR)
  {
   return false;
  }
  CComPtrpEm;
  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);
    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 CCaptureVideo::InitCaptureGraphBuilder()
{
  HRESULT hr;

  // 创建IGraphBuilder接口
  hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB);
  // 创建ICaptureGraphBuilder2接口
  hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
  if (FAILED(hr))return hr;
  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;
}
HRESULT CCaptureVideo::SetupVideoWindow()
{
  HRESULT hr;
  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 CCaptureVideo::ResizeVideoWindow()
{
  if (m_pVW){
   //让图像充满整个窗口
   CRect rc;
   ::GetClientRect(m_hWnd,&rc);
   m_pVW->SetWindowPosition(0, 0, rc.right, rc.bottom);
  }
}
void CCaptureVideo::GrabOneFrame(BOOL bGrab)
{
  bOneShot = bGrab;
}
void CCaptureVideo::FreeMediaType(AM_MEDIA_TYPE& mt)
{
  if (mt.cbFormat != 0) {
   CoTaskMemFree((PVOID)mt.pbFormat);
   // Strictly unnecessary but tidier
   mt.cbFormat = 0;
   mt.pbFormat = NULL;
  }
  if (mt.pUnk != NULL) {
   mt.pUnk->Release();
   mt.pUnk = NULL;
  }
}
相关文章
  • Visual C++中动态链接库技术浅谈
  • Visual C++设计UDP协议通讯示例
  • Visual C++泛型编程实践
  • Visual C++ 入门精解-第一部分
  • Visual C++ 入门精解-引言
【评论】【收藏本文】【打印】【关闭】
上一篇文章:轻轻松松学习C++ 标准模板库STL
下一篇文章:在VC++中实现自动连续播放多媒体文件
讨论区
查看
已有 0 位对此新闻感兴趣的网友发表了看法
匿名发表
注册通行证 登陆
图文阅读推荐
推荐阅讯
  • 就c++中的const限定修饰符做一个入门的教程
  • Windows下的函数hook技术
  • VC++实现动画弹出/弹入式窗口
  • c++中函数重载的相关知识
  • VC中利用人工智能解决八迷宫问题
  • 用VC实现特定编辑框上对回车键响应
  • C/C++中命令行参数的原理
  • c++面向对象的编程入门篇-----类(class)
  • c++中布尔类型的入门教程
  • More Effective C++:类型转换
阅读排行
  • 1.Borland 发布C++ Builder 2006 RAD 环境
  • 2.C/C++程序员应聘常见面试题深入剖析
  • 3.Visual C++常用数据类型转换详解
  • 4.C++中的 static 关键字
  • 5.利用VC++实现局域网实时视频传输
  • 6.浅谈C/C++内存泄漏及其检测工具
  • 7.英国投票否决C++/CLI 微软强攻ISO标准受挫
  • 8.VC++下用MSComm控件实现串口通讯
  • 9.伪随机数生成及在VC++中的实现
  • 10.VC++编程实现对波形数据的频谱分析
专题教程
  • 大话G游 专题:手机病毒揭密
  • ARP攻击防范与解决方案 路由故障处理手册
  • Picasa中文版_Picasa教程 专题:清除流氓软件
  • Firefox专题 seo搜索引擎优化专区
  • 重装Windows必知的事情 装机之必备软件大行动
病毒专杀栏
  • 杀毒软件反被病毒杀 连"救命"都不能喊
  • 金山ARP防火墙
  • 还原卡神话破灭“机器狗”病毒来势汹汹
  • cctv经济半小时:你的手机现在安全吗?
  • 新挂马方式开始流行 ARP挂马称雄局域网
  • 木马和病毒清除的通用解法
  • IP地址不再冲突 查找ARP攻击者元凶
  • 教你几招识别和防御Web网页木马
  • 分析:封杀BT只是暂时的止痛药
  • QQ爆危险漏洞,“QQ游戏邀请大盗”邀请你玩病
关于我们 | 诚聘英才 | 联系我们 | 版权声明 | 网站大事 | 网站地图 | 意见建议
CopyRight 2005-2007 Jztop.Com 版权所有 未经许可 请勿转载