zoukankan      html  css  js  c++  java
  • DirectShow 进行视频预览和录制

    这一篇讲怎么采集摄像头图像并预览,以及录制视频到本地。


    程序实现流程

    这里通过使用 CaptureGraphBuilder 来简化 Graph 的创建流程。


    具体流程如下:

    1. 初始化 COM 库
    2. 创建各 Filter
    3. 找到视频采集设备,也就是通过 USB 连接的摄像头
    4. 渲染并预览视频
    5. 销毁先前创建的 Filter
    6. 释放COM

    视频采集类

    先看一下视频采集类的头文件,而源文件就不一次性全部贴出了,而是只介绍几个重要的成员函数。captrue.h 的内容如下:

    #pragma once
    
    #include <Windows.h>
    #include <dshow.h>
    
    // 用于确保安全释放的宏
    #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
    
    class CCapture
    {
    public:
    	CCapture();
    	~CCapture();
    
    	HRESULT Init(HWND hwnd); // 初始化
    	HRESULT FindCaptureDevice(); // 寻找视频采集设备
    	HRESULT Render(); // 渲染并预览视频
    	void DestroyGraph(); // 销毁先前创建的filter
    
    	void ResizeWindow(); // 重设窗口
    
    private:
    	// 窗口句柄
    	HWND					m_hwnd;
    	// 视频采集预览相关
    	IGraphBuilder			*m_pGraph; // filter granph(manager)
    	ICaptureGraphBuilder2	*m_pCapture; // capture granph
    	IMediaControl			*m_pMediaC; // 媒体控制接口
    	IMediaEventEx			*m_pMediaE; // 媒体事件接口
    	IVideoWindow			*m_pVideoW; // 视频窗口接口
    	IBaseFilter				*m_pFilter; // 基类filter
    };
    

    1.初始化

    // 初始化
    HRESULT CCapture::Init(HWND hwnd)
    {
    	HRESULT hr;
    
    	// 创建filter graph manager
    	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGraph);
    	if (FAILED(hr))
    		return hr;
    
    	// 创建capture granph
    	hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **)&m_pCapture);
    	if (FAILED(hr))
    		return hr;
    
    	// 查询graph中各IID参数标识的接口指针
    	hr = m_pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&m_pMediaC);
    	if (FAILED(hr))
    		return hr;
    	hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (LPVOID *)&m_pMediaE);
    	if (FAILED(hr))
    		return hr;
    	hr = m_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *)&m_pVideoW);
    	if (FAILED(hr))
    		return hr;
    
    	// 为capture graph指定要使用的filter graph
    	hr = m_pCapture->SetFiltergraph(m_pGraph);
    	if (FAILED(hr))
    		return hr;
    
    	// 将Win32窗口句柄赋给m_hwnd
    	m_hwnd = hwnd;
    
    	return hr;
    }
    

    进行初始化操作。


    2.寻找视频采集设备

    // 寻找视频采集设备
    HRESULT CCapture::FindCaptureDevice()
    {
    	HRESULT hr = S_OK;
    	ICreateDevEnum *pDevEnum = NULL;
    	IEnumMoniker *pClassEnum = NULL; // 用于视频采集设备的枚举
    	IMoniker* pMoniker = NULL; // 设备Moniker号
    
    	// 创建系统设备枚举
    	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,IID_ICreateDevEnum, (void **)&pDevEnum);
    	if (FAILED(hr))
    		return hr;
    
    	// 创建一个指定视频采集设备的枚举
    	hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
    	if (FAILED(hr) || pClassEnum == NULL)
    	{
    		SAFE_RELEASE(pDevEnum);
    		return hr;
    	}
    
    	// 使用第一个找到的视频采集设备(只适用于单摄像头的情况)
    	hr = pClassEnum->Next(1, &pMoniker, NULL);
    	if (hr == S_FALSE)
    	{
    		SAFE_RELEASE(pDevEnum);
    		SAFE_RELEASE(pClassEnum);
    		return hr;
    	}
    	// 绑定找到摄像头的moniker到filter graph
    	hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pFilter);
    	if (FAILED(hr))
    	{
    		SAFE_RELEASE(pDevEnum);
    		SAFE_RELEASE(pClassEnum);
    		SAFE_RELEASE(pMoniker);
    		return hr;
    	}
    
    	// 增加filter graph的引用计数
    	m_pFilter->AddRef(); 
    
    	return hr;
    }
    

    初始化之后,就要找到视频采集设备,即通过 USB 连接的摄像头。这里没有去循环枚举查找多个视频采集设备,固定选择了找到的第一个视频采集设备。


    3.渲染并预览视频

    // 渲染并预览视频
    HRESULT CCapture::Render()
    {
    	HRESULT hr;
        
        // 将base filter添加到filter graph中
        hr = m_pGraph->AddFilter(m_pFilter, L"Video capture");	
    	if (FAILED(hr))
    	{
    		m_pFilter->Release();
    		return hr;
    	}
    
    	// 用ICaptureGraphBuilder2接口构建预览的filter链路
    	hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pFilter, NULL, NULL);
    	if (FAILED(hr))
    	{
    		m_pFilter->Release();
    		return hr;
    	}
    	// 同时构建一个写文件的filter链路
    	IBaseFilter *pMux;
    	hr = m_pCapture->SetOutputFileName(&MEDIASUBTYPE_Avi, L"D:\example.avi", &pMux, NULL); // 设置输出视频文件位置
    	hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pFilter, NULL, pMux); // 将m_pFilter的输出pin连接到pMux
    	
    	// 使用完就可以释放base filter了
    	pMux->Release();
    	m_pFilter->Release();
    
    	// 显示窗口 , 预览采集图形
    	hr = m_pVideoW->put_Owner((OAHWND)m_hwnd);
    	if (FAILED(hr))
    		return hr;
    	hr = m_pVideoW->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
    	if (FAILED(hr))
    		return hr;
    	ResizeWindow(); // 重设窗口
    	hr = m_pVideoW->put_Visible(OATRUE);
    	if (FAILED(hr))
    		return hr;
    	hr = m_pMediaC->Run();
    	
    	return hr;
    }
    

    实现效果


    代码下载

    Github - DShow_captruePreview


    参考:

    (一) DirectShow简单采集程序——使用CaptureGraphBuilder

    2.使用DShow进行摄像头预览


  • 相关阅读:
    OpenStack Paste.ini详解(二)
    OpenStack Paste.ini详解(一)
    PDB调试python代码常用命令
    Devstack 安装OpenStack Pike版本(单机环境)
    Openstack Pycharm 的远程调试
    django Forbidden
    Python 常用命令
    OSI模型和TCP/IP协议族(一)
    ubuntu 下关闭MySql server
    安装ubuntu时的注意事项----个人小总结
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12068978.html
Copyright © 2011-2022 走看看