directshow摄像头录像_open camera 使用方法

大家好,又见面了,我是你们的朋友全栈君。

Win10 64 + VS2012

工程下载:
http://download.csdn.net/detail/yulinxx/9263639

建一个基于Dialog的MFC程序,而局如下:
一个PIC控件,用于显示摄像头捕捉画面,几个按钮

创建一个C++类,类名为:CCamera
在CCamera.h中,需要包含

#include <atlbase.h>
#include "qedit.h"
#include "dshow.h"
#include <windows.h>

在#include “qedit.h”之前,需要添加如下代码,避免qedit.h报错:

#pragma include_alias( "dxtrans.h", "qedit.h" )
#define __IDxtCompositor_INTERFACE_DEFINED__
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
#define __IDxtJpeg_INTERFACE_DEFINED__
#define __IDxtKey_INTERFACE_DEFINED__

CCamera.h 全文为:

#pragma once
#pragma include_alias( "dxtrans.h", "qedit.h" )
#define __IDxtCompositor_INTERFACE_DEFINED__
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
#define __IDxtJpeg_INTERFACE_DEFINED__
#define __IDxtKey_INTERFACE_DEFINED__
#include <atlbase.h>
#include "qedit.h"
#include "dshow.h"
#include <windows.h>
#define MYFREEMEDIATYPE(mt) { 
if ((mt).cbFormat != 0) \
{CoTaskMemFree((PVOID)(mt).pbFormat);    \
(mt).cbFormat =0;                        \
(mt).pbFormat = NULL;                    \
}                                            \
if ((mt).pUnk != NULL)                        \
{                                            \
(mt).pUnk->Release();                    \
(mt).pUnk = NULL;                        \
}}                  
class CCamera
{
public:
CCamera(void);
~CCamera(void);
private:
CImage m_image;
bool m_bConnected;
int m_nWidth;
int m_nHeight;
bool m_bLock;
bool m_bChanged;
long m_nBufferSize;
CComPtr<IGraphBuilder> m_pGraphBuilder;
CComPtr<IBaseFilter> m_pDeviceFilter;
CComPtr<IMediaControl> m_pMediaControl;
CComPtr<IBaseFilter> m_pSampleGrabberFilter;
CComPtr<ISampleGrabber> m_pSampleGrabber;
CComPtr<IPin> m_pGrabberInput;
CComPtr<IPin> m_pGrabberOutput;
CComPtr<IPin> m_pCameraOutput;
CComPtr<IMediaEvent> m_pMediaEvent;
CComPtr<IBaseFilter> m_pNullFilter;
CComPtr<IPin> m_pNullInputPin;
bool BindFilter(int nCameraIndex, IBaseFilter **pFilter);
public:
static int CameraCount(); 
bool OpenCamera(int nCamID, bool bDisplayProperties=true, int nWidth =320, int nHeight =240);
CImage* QueryFrame(); 
};

CCamera.cpp 全文为

#include "stdafx.h"
#include "Camera.h"
#pragma comment(lib,"Strmiids.lib") 
CCamera::CCamera(void)
{
}
CCamera::~CCamera(void)
{
}
bool CCamera::BindFilter(int nCameraIndex, IBaseFilter **pFilter)
{
if (nCameraIndex < 0)
return false;
// enumerate all video capture devices
CComPtr<ICreateDevEnum> pCreateDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (hr != NOERROR)
{
return false;
}
CComPtr<IEnumMoniker> pEm;      // This will access the actual devices
// 为指定的Filter注册类型目录创建一个枚举器,并获得 IEnumMoniker接口 (Video Capture Sources )
// 可以访问捕捉设备的列表了
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
if (hr != NOERROR) 
{
return false;
}
pEm->Reset();       // Go to the start of the enumerated list
ULONG cFetched;
IMoniker *pM;
int index =0;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= nCameraIndex)
{
IPropertyBag *pBag;
// BindToStorage之后就可以访问设备标识的属性集了。
// Binds to the storage for the specified object. Unlike the IMoniker::BindToObject method, 
// this method does not activate the object identified by the moniker.
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 == nCameraIndex)
{
// BindToObject将某个设备标识绑定到一个DirectShow Filter,
// 然后调用IFilterGraph::AddFilter加入到Filter Graph中,这个设备就可以参与工作了
// 调用IMoniker::BindToObject建立一个和选择的device联合的filter,
// 并且装载filter的属性(CLSID,FriendlyName, and DevicePath)。
// Binds to the specified object. The binding process involves finding the object, 
// putting it into the running state if necessary, 
// and providing the caller with a pointer to a specified interface on the identified object.
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
}
SysFreeString(var.bstrVal);
}
pBag->Release();
}
pM->Release();
index++;
}
pCreateDevEnum = NULL;
return true;
}
int CCamera::CameraCount()
{
CoInitialize(NULL);
int nCount =0;
// enumerate all video capture devices
CComPtr<ICreateDevEnum> pCreateDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
CComPtr<IEnumMoniker> pEm;
// 使用接口方法ICreateDevEnum::CreateClassEnumerator为指定的Filter注册类型目录创建一个枚举器,并获得 IEnumMoniker接口;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
if (hr != NOERROR) 
{
return nCount;
}
pEm->Reset();
ULONG cFetched;
IMoniker *pM;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK)
{
nCount++;
}
pCreateDevEnum = NULL;
pEm = NULL;
return nCount;
}
bool CCamera::OpenCamera(int nCamID, bool bDisplayProperties/*=true*/, int nWidth /*=320*/, int nHeight /*=240*/)
{
HRESULT hr = S_OK;
CoInitialize(NULL);
// 调用CoCreateInstance来创建筛选器表管理器.筛选器表管理器由一个进程内的DLL提供,所以执行上下文是 CLSCTX_INPROC_SERVER
// 对CoCreateInstance的调用返回IGraphBuilder接口,它主要包含了生成筛选器表的方法。此例中用到的另两个接口为:
// IMediaControl,作用是控制流。它包含了停止和启动表的方法
// IMediaEvent,它包含的方法是从筛选器表管理器中得到事件。
// 创建IGraphBuilder接口 Create the Filter Graph Manager. (用指定的类标识符创建一个Com对象)
// Filter Graph Manager
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 
IID_IGraphBuilder, (void**)&m_pGraphBuilder);
// IMediaControl接口,用来控制流媒体在Filter Graph中的流动,例如流媒体的启动和停止;
hr = m_pGraphBuilder->QueryInterface(IID_IMediaControl, (void**) &m_pMediaControl);
// IMediaEvent接口,该接口在Filter Graph发生一些事件时用来创建事件的标志信息并传送给应用程序
hr = m_pGraphBuilder->QueryInterface(IID_IMediaEvent, (void**) &m_pMediaEvent);
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (LPVOID*) &m_pNullFilter);
hr = m_pGraphBuilder->AddFilter(m_pNullFilter, L"NullRenderer");
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, 
IID_IBaseFilter, (LPVOID *)&m_pSampleGrabberFilter);
// 查询得到组件对象上的接口
hr = m_pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&m_pSampleGrabber);
AM_MEDIA_TYPE   mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
mt.formattype = FORMAT_VideoInfo; 
hr = m_pSampleGrabber->SetMediaType(&mt);
MYFREEMEDIATYPE(mt);
m_pGraphBuilder->AddFilter(m_pSampleGrabberFilter, L"Grabber");
// Bind Device Filter. We know the device because the id was passed in
BindFilter(nCamID, &m_pDeviceFilter);
m_pGraphBuilder->AddFilter(m_pDeviceFilter, NULL);
CComPtr<IEnumPins> pEnum;
m_pDeviceFilter->EnumPins(&pEnum);
hr = pEnum->Reset();    // The Reset method resets the enumeration sequence to the beginning.
hr = pEnum->Next(1, &m_pCameraOutput, NULL);    // The Next method retrieves a specified number of pins in the enumeration sequence.
pEnum = NULL; 
m_pSampleGrabberFilter->EnumPins(&pEnum);
pEnum->Reset();
hr = pEnum->Next(1, &m_pGrabberInput, NULL); 
pEnum = NULL;
m_pSampleGrabberFilter->EnumPins(&pEnum);
pEnum->Reset();
pEnum->Skip(1);
hr = pEnum->Next(1, &m_pGrabberOutput, NULL); 
pEnum = NULL;
m_pNullFilter->EnumPins(&pEnum);
pEnum->Reset();
hr = pEnum->Next(1, &m_pNullInputPin, NULL);
//SetCrossBar();
if (bDisplayProperties) 
{
CComPtr<ISpecifyPropertyPages> pPages;
HRESULT hr = m_pCameraOutput->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);
if (SUCCEEDED(hr))
{
PIN_INFO PinInfo;
m_pCameraOutput->QueryPinInfo(&PinInfo);
CAUUID caGUID;
pPages->GetPages(&caGUID);
OleCreatePropertyFrame(NULL, 0, 0,
L"Property Sheet", 1,
(IUnknown **)&(m_pCameraOutput.p),
caGUID.cElems,
caGUID.pElems,
0, 0, NULL);
CoTaskMemFree(caGUID.pElems);
PinInfo.pFilter->Release();
}
pPages = NULL;
}
else 
{
//////////////////////////////////////////////////////////////////////////////
// 加入由 lWidth和lHeight设置的摄像头的宽和高 的功能,默认320*240
// by flymanbox @2009-01-24
//////////////////////////////////////////////////////////////////////////////
int _Width = nWidth, _Height = nHeight;
IAMStreamConfig* iconfig = NULL;
hr = m_pCameraOutput->QueryInterface(IID_IAMStreamConfig, (void**)&iconfig);   
AM_MEDIA_TYPE* pmt;    
if(iconfig->GetFormat(&pmt) !=S_OK) 
{
//printf("GetFormat Failed ! \n");
return false;   
}
VIDEOINFOHEADER* phead;
if ( pmt->formattype == FORMAT_VideoInfo)   
{   
phead=( VIDEOINFOHEADER*)pmt->pbFormat;   
phead->bmiHeader.biWidth = _Width;   
phead->bmiHeader.biHeight = _Height;   
if(( hr=iconfig->SetFormat(pmt)) != S_OK )   
{
return false;
}
}   
iconfig->Release();   
iconfig=NULL;   
MYFREEMEDIATYPE(*pmt);
}
hr = m_pGraphBuilder->Connect(m_pCameraOutput, m_pGrabberInput);
hr = m_pGraphBuilder->Connect(m_pGrabberOutput, m_pNullInputPin);
if (FAILED(hr))
{
switch(hr)
{
case VFW_S_NOPREVIEWPIN :
break;
case E_FAIL :
break;
case E_INVALIDARG :
break;
case E_POINTER :
break;
}
}
// The SetBufferSamples method specifies whether to copy sample data into a buffer as it goes through the filter.
m_pSampleGrabber->SetBufferSamples(TRUE);
// The SetOneShot method specifies whether the Sample Grabber filter halts after the filter receives a sample.
m_pSampleGrabber->SetOneShot(TRUE);
hr = m_pSampleGrabber->GetConnectedMediaType(&mt);
if(FAILED(hr))
return false;
VIDEOINFOHEADER *videoHeader;
videoHeader = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);
m_nWidth = videoHeader->bmiHeader.biWidth;
m_nHeight = videoHeader->bmiHeader.biHeight;
m_bConnected =true;
pEnum = NULL;
return true;
}
CImage* CCamera::QueryFrame()
{
long evCode;
long size =0;
m_pMediaControl->Run();         // 运行filter
// 当筛选器运行时,数据从筛选器中移出,并以视频和音频的方式还原出来。
// 播放会启动另一个线程。您可以调用IMediaEvent::WaitForCompletion方法。
// 等待结束
m_pMediaEvent->WaitForCompletion(INFINITE, &evCode);
m_pSampleGrabber->GetCurrentBuffer(&size, NULL);    // If pBuffer is NULL, this parameter receives the required buffer size
//if the buffer size changed
if (size != m_nBufferSize)
{
m_nBufferSize = size;
m_image.Create(m_nWidth,m_nHeight,24);
}
if(m_image.IsNull())
{
return 0;
}
byte*q = NULL;
byte*p = new byte[m_nWidth*m_nHeight*3];
m_pSampleGrabber->GetCurrentBuffer(&m_nBufferSize, (long*)p);   // If pBuffer is not NULL, set this parameter equal to the size of the buffer, in bytes.
for(int y=0, z=m_nHeight-1; y<m_nHeight,z>=0; y++,z--)
{
q = (byte*)m_image.GetPixelAddress(0,z);
memcpy(q,&p[m_nWidth*3*y],m_nWidth*3);
}
delete []p;
return &m_image;
}


获取摄像头所支持的所有分辨率:

std::vector<POINT> CCamera::GetAllSupportPix(int iDeviceID)
{
HRESULT hr = S_OK;
std::vector<POINT> vecPix;
ICaptureGraphBuilder2* _pCapture = NULL;
IBaseFilter* _pBF;
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **)&_pCapture);
if (FAILED(hr))
return vecPix;
if (!BindFilter(iDeviceID, &_pBF))
{
srelease(_pCapture);
return vecPix;
}
IAMStreamConfig*  pStreamConfig;
AM_MEDIA_TYPE *pmtConfig;
hr = _pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, 0,_pBF, IID_IAMStreamConfig, (void**)&pStreamConfig); 
if (FAILED(hr))
{
srelease(_pCapture);
srelease(_pBF);
return vecPix;
}
pStreamConfig->GetFormat(&pmtConfig);
if (FAILED(hr))
{
srelease(_pCapture);
srelease(_pBF);
pStreamConfig->Release();
return vecPix;
}
VIDEOINFOHEADER * vi = (VIDEOINFOHEADER*) pmtConfig->pbFormat;
int iCount, iSize;
VIDEO_STREAM_CONFIG_CAPS caps;
pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize);
AM_MEDIA_TYPE *pmtPV = NULL;
for (int i = 0; i<iCount; ++i)
{
if (pStreamConfig->GetStreamCaps(i, &pmtPV, (BYTE*)&caps) == S_OK)
{
if (pmtPV->subtype == MEDIASUBTYPE_RGB24)
{
POINT pix = {caps.MaxOutputSize.cx,caps.MaxOutputSize.cy};
vecPix.push_back(pix);
}
//FreeMediaType(*pmtPV);
}
}
srelease(_pCapture);
srelease(_pBF);
//FreeMediaType(*pmtConfig);
pStreamConfig->Release();
return vecPix;
}



补充:
Camera.cpp 释放的时候
CCamera::~CCamera(void)

if(m_bConnected)
{
m_pMediaControl->Stop();
}
m_pGraphBuilder = NULL;
m_pDeviceFilter = NULL;
m_pMediaControl = NULL;
m_pSampleGrabberFilter = NULL;
m_pSampleGrabber = NULL;
m_pGrabberInput = NULL;
m_pGrabberOutput = NULL;
m_pCameraOutput = NULL;
m_pMediaEvent = NULL;
m_pNullFilter = NULL;
m_pNullInputPin = NULL;
if(!m_image.IsNull())
{
m_image.Destroy();
}
m_bConnected = false;
m_nWidth = 0;
m_nHeight = 0;
m_bLock = false;
m_bChanged = false;
m_nBufferSize = 0;
CoUninitialize();

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/182880.html原文链接:https://javaforall.cn

未经允许不得转载:木盒主机 » directshow摄像头录像_open camera 使用方法

赞 (0)

相关推荐

    暂无内容!