⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 capturedlg.cpp

📁 一个简单的基于DirectShow的视频捕获程序
💻 CPP
字号:
// CaptureDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Capture.h"
#include "CaptureDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCaptureDlg dialog

CCaptureDlg::CCaptureDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCaptureDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CCaptureDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCaptureDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCaptureDlg)
	DDX_Control(pDX, IDC_VIDEO_WINDOW, m_VideoWindow);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CCaptureDlg, CDialog)
	//{{AFX_MSG_MAP(CCaptureDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCaptureDlg message handlers

BOOL CCaptureDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// 各指针参数的初始化
	m_pVW = NULL;
	m_pMC = NULL;
	m_pGraph = NULL;
	m_pCapture = NULL;

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CCaptureDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CCaptureDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		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;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CCaptureDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CCaptureDlg::OnOK() 
{
	// TODO: Add extra validation here
	HRESULT hr = NULL;
    // 捕获摄像头的图像并显示
    hr = CaptureVideo();

}

// 捕获摄像头的图像并显示
HRESULT CCaptureDlg::CaptureVideo()
{

    HRESULT hr;
    IBaseFilter *pSrcFilter=NULL;	// Filter

    // 获得DirectShow中的各个接口
    hr = GetInterfaces();
    if (FAILED(hr))
    {
        MessageBox("获得接口失败!");
        return hr;
    }

	// 将filter graph加到capture graph中
    hr = m_pCapture->SetFiltergraph(m_pGraph);
    if (FAILED(hr))
    {
        MessageBox("加入Filter Graph失败!");
        return hr;
    }

    // 枚举视频设备,找到摄像头,并将之绑定到Filter中
    hr = FindCaptureDevice(&pSrcFilter);
    if (FAILED(hr))
    {
        return hr;
    }

    // 将视频Filter加入到Filter Graph Manager中
    hr = m_pGraph->AddFilter(pSrcFilter, L"Video Capture");
    if (FAILED(hr))
    {
		MessageBox("不能将视频Filter加入到Filter Graph中");
        pSrcFilter->Release();
        return hr;
    }

    // 连接视频Filter中的输出pin到显示器,输出视频捕获数据流
    // 不用 m_pGraph->RenderFile
    hr = m_pCapture->RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
                                   pSrcFilter, NULL, NULL);
    if (FAILED(hr))
    {
		MessageBox("不能输出视频捕获数据流");
        pSrcFilter->Release();
        return hr;
    }

    // 释放Filter引用
    pSrcFilter->Release();

    // 在控件中显示摄像头捕获的图像
    hr = SetupVideoWindow(m_VideoWindow.GetSafeHwnd());
    if (FAILED(hr))
    {
		MessageBox("不能显示摄像头捕获的图像");
        return hr;
    }

    // 开始显示图像
    hr = m_pMC->Run();
    if (FAILED(hr))
    {
		MessageBox("不能显示图像");
        return hr;
    }

	return S_OK;
}

// 获得DirectShow中的各个接口
HRESULT CCaptureDlg::GetInterfaces()
{
    HRESULT hr;

    // 创建filter graph组件
    hr = CoCreateInstance (CLSID_FilterGraph,			// 要创建的Filter的Class ID
							NULL,						// 表示Filter不被聚合
							CLSCTX_INPROC,				// 创建进程内组件对象
                           IID_IGraphBuilder,			// 创建Filter成功后获得的接口ID
						   (void **) &m_pGraph);		// 生成的接口对象的指针
    if (FAILED(hr))
        return hr;


    // 创建capture graph builder组件
    hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
                           IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
    if (FAILED(hr))
        return hr;

	// 获得VideoWindow接口
    hr = m_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *) &m_pVW);
    if (FAILED(hr))
        return hr;

    // 获得MediaControl接口
    hr = m_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &m_pMC);
    if (FAILED(hr))
        return hr;

    return hr;
}

// 枚举系统设备,找到摄像头
HRESULT CCaptureDlg::FindCaptureDevice(IBaseFilter **ppSrcFilter)
{
    HRESULT hr;
    IBaseFilter * pSrc = NULL;
    CComPtr <IMoniker> pMoniker =NULL;
    ULONG cFetched;

    if (!ppSrcFilter)
        return E_POINTER;
   
    // 创建设备枚举器
    CComPtr <ICreateDevEnum> pDevEnum =NULL;
    hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
                           IID_ICreateDevEnum, (void **) &pDevEnum);
    if (FAILED(hr))
    {
		MessageBox("创建设备枚举器!");
        return hr;
    }

    // 创建设备种类枚举器
    CComPtr <IEnumMoniker> pClassEnum = NULL;

    hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
    if (FAILED(hr))
    {
		MessageBox("创建设备种类枚举器!");
        return hr;
    }

    // 没有探测到视频设备
    if (pClassEnum == NULL)
    {
		MessageBox("没有探测到视频设备!");
        return E_FAIL;
    }

	// 在枚举器中找出第一个视频设备,并将之绑定到Filter上
    if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
    {
        // 将视频设备绑定到Filter上
        hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
        if (FAILED(hr))
        {
			MessageBox("视频设备绑定失败!");
            return hr;
        }
    }
    else
    {
		MessageBox("不能访问视频设备!");
        return E_FAIL;
    }

    *ppSrcFilter = pSrc;

    return hr;

}

HRESULT CCaptureDlg::SetupVideoWindow(HWND inWindow)
{
	// VideoWindow存在,则显示捕获的图像
	if (m_pVW)
	{
		// 首先隐藏VideoWindow
		m_pVW->put_Visible(OAFALSE);
		// 将VideoWindow置于对话框上的显示控件中
		m_pVW->put_Owner((OAHWND)inWindow);

		// 设置VideoWindow的大小
		RECT windowRect;
		::GetClientRect(inWindow, &windowRect);
		m_pVW->put_Left(0);
		m_pVW->put_Top(0);
		m_pVW->put_Width(windowRect.right - windowRect.left);
		m_pVW->put_Height(windowRect.bottom - windowRect.top);
		m_pVW->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);

		// 显示VideoWindow
		if (inWindow != NULL)
		{
			m_pVW->put_Visible(OATRUE);
		}
		else
		{
			m_pVW->put_Visible(OAFALSE);
		}

		return S_OK;
	}
	return S_FALSE;

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -