DirectShow 开启摄像头

Win10 64 + VS2012

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

建一个基于Dialog的MFC程序,而局如下:
一个PIC控件,用于显示摄像头捕捉画面,几个按钮
DirectShow 开启摄像头_第1张图片

创建一个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 (可网上下载)全文为:

DirectShow 开启摄像头_第2张图片

DirectShow 开启摄像头_第3张图片

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


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();

你可能感兴趣的:(摄像头,directshow)