DirectShow 开启摄像头
来源:互联网 发布:类似知否的诙谐宅斗文 编辑:程序博客网 时间:2024/05/01 14:40
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();
0 0
- DirectShow 开启摄像头
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- directshow摄像头录像代码
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- directshow 摄像头参数 设置
- 使用DirectShow驱动摄像头
- 使用DirectShow驱动摄像头
- DirectShow摄像头采集
- DirectShow摄像头采集
- DirectShow控制USB摄像头
- ubuntu用户添加adduser, useradd
- 菜单栏、工具栏和状态栏
- android 刷第三方recovery
- ffmpeg重要结构体之AVFormatContext
- 模拟QQ的停靠时隐藏效果,隐藏树形菜单
- DirectShow 开启摄像头
- css3 文本选中控制属性
- Wireshark工具——网络抓包
- 如何实现软件自动重启
- finereport 之下拉框
- Android Canvas使用
- 光线追踪算法理论与实践
- XML解析问题记录
- 交换机和路由器的数据包转发流程简述