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;
}
”开启摄像头“”开启摄像头(选择性)“需互斥,
即点击其中一个按钮后,需禁用另一个按钮
选择性,可以在开启前,选择分辨率等参数
在Dlg.cpp中,点击”开启摄像头“按钮,响应如下代码:
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_VIEW2)->EnableWindow(FALSE);
int nCameraCount = CCamera::CameraCount();
m_vecCamera.resize(nCameraCount);
if (!m_vecCamera[nCameraCount-1].OpenCamera(nCameraCount-1, false, 640, 480))
{
AfxMessageBox(_T("打开摄像头失败"));
return;
}
while (true)
{
if (m_bStop)
{
break;
}
m_pImageView = m_vecCamera[nCameraCount - 1].QueryFrame();
OnDlgEvent();
ShowPicture(m_pImageView, &m_wndStcView);
}
在Dlg.cpp中,点击”开启摄像头(选择性)“按钮,响应如下代码:
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_VIEW2)->EnableWindow(TRUE);
int nCameraCount = CCamera::CameraCount();
m_vecCamera.resize(nCameraCount);
if (!m_vecCamera[nCameraCount-1].OpenCamera(nCameraCount-1, true, 640, 480))
{
AfxMessageBox(_T("打开摄像头失败"));
return;
}
while (true)
{
if (m_bStop)
{
break;
}
m_pImageView = m_vecCamera[nCameraCount - 1].QueryFrame();
OnDlgEvent();
ShowPicture(m_pImageView, &m_wndStcView);
}
DShowCameraDlg.h 全文为:
// DShowCameraDlg.h : 头文件
//
#pragma once
#include <vector>
// CDShowCameraDlg 对话框
#include "Camera.h"
#include "afxwin.h"
class CDShowCameraDlg : public CDialogEx
{
// 构造
public:
CDShowCameraDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_DSHOWCAMERA_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
void ShowPicture(CImage* pImg,CStatic* pStcView);
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg void OnClose();
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedCancel();
afx_msg void OnBnClickedBtnView();
afx_msg void OnBnClickedBtnView2();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
protected:
BOOL m_bStop;
CImage* m_pImageView;
int m_nCameraCount;
std::vector<CCamera> m_vecCamera;
CStatic m_wndStcView;
};
DShowCameraDlg. cpp全文为:
// DShowCameraDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "DShowCamera.h"
#include "DShowCameraDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CDShowCameraDlg 对话框
CDShowCameraDlg::CDShowCameraDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CDShowCameraDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_nCameraCount = -1;
m_pImageView = NULL;
m_bStop = FALSE;
}
void CDShowCameraDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_STC_VIEW, m_wndStcView);
}
BEGIN_MESSAGE_MAP(CDShowCameraDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_VIEW, &CDShowCameraDlg::OnBnClickedBtnView)
ON_WM_DESTROY()
ON_WM_CLOSE()
ON_BN_CLICKED(IDOK, &CDShowCameraDlg::OnBnClickedOk)
ON_BN_CLICKED(IDCANCEL, &CDShowCameraDlg::OnBnClickedCancel)
ON_BN_CLICKED(IDC_BTN_VIEW2, &CDShowCameraDlg::OnBnClickedBtnView2)
END_MESSAGE_MAP()
// CDShowCameraDlg 消息处理程序
void CDShowCameraDlg::ShowPicture(CImage* pImg,CStatic* pStcView)
{
if(pImg == NULL)
return;
int width = pImg->GetWidth();
int height = pImg->GetHeight();
CRect rectView;
pStcView->GetClientRect(&rectView);
CRect rt(rectView);
CDC* dc = pStcView->GetDC();
ASSERT(dc);
CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH));
//dc->FillRect(rt, pBrush);
if(rectView.Height() * width > height * rectView.Width())
{
CPoint p1(0, (rectView.Height()-(rectView.Width()*height/width))/2);
CPoint p2(rectView.Width(),(rectView.Height() - p1.y));
rt.SetRect(p1,p2);
}
else
{
CPoint pt1((rectView.Width()-(rectView.Height()*width/height))/2,0);
CPoint pt2(rectView.Width()-pt1.x, rectView.Height());
rt.SetRect(pt1,pt2);
}
if (dc)
{
::SetStretchBltMode(dc->m_hDC, HALFTONE);
pImg->Draw(dc->m_hDC, rt);
}
}
BOOL CDShowCameraDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CDShowCameraDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CDShowCameraDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void OnDlgEvent()
{
MSG msg;
if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
// 开启摄像头
void CDShowCameraDlg::OnBnClickedBtnView()
{
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_VIEW2)->EnableWindow(FALSE);
int nCameraCount = CCamera::CameraCount();
m_vecCamera.resize(nCameraCount);
if (!m_vecCamera[nCameraCount-1].OpenCamera(nCameraCount-1, false, 640, 480))
{
AfxMessageBox(_T("打开摄像头失败"));
return;
}
while (true)
{
if (m_bStop)
{
break;
}
m_pImageView = m_vecCamera[nCameraCount - 1].QueryFrame();
OnDlgEvent();
ShowPicture(m_pImageView, &m_wndStcView);
}
}
void CDShowCameraDlg::OnBnClickedBtnView2()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_VIEW2)->EnableWindow(TRUE);
int nCameraCount = CCamera::CameraCount();
m_vecCamera.resize(nCameraCount);
if (!m_vecCamera[nCameraCount-1].OpenCamera(nCameraCount-1, true, 640, 480))
{
AfxMessageBox(_T("打开摄像头失败"));
return;
}
while (true)
{
if (m_bStop)
{
break;
}
m_pImageView = m_vecCamera[nCameraCount - 1].QueryFrame();
OnDlgEvent();
ShowPicture(m_pImageView, &m_wndStcView);
}
}
void CDShowCameraDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bStop = TRUE;
CDialogEx::OnClose();
}
void CDShowCameraDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
m_bStop = TRUE;
CDialogEx::OnOK();
}
void CDShowCameraDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
m_bStop = TRUE;
CDialogEx::OnCancel();
}
qedit.h (可网上下载)全文为:
获取摄像头所支持的所有分辨率:
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();