本文共 3831 字,大约阅读时间需要 12 分钟。
这一篇讲怎么采集摄像头图像并预览,以及录制视频到本地。
这里通过使用 CaptureGraphBuilder 来简化 Graph 的创建流程。
具体流程如下:
先看一下视频采集类的头文件,而源文件就不一次性全部贴出了,而是只介绍几个重要的成员函数。captrue.h 的内容如下:
#pragma once#include#include // 用于确保安全释放的宏#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;}
参考:
转载地址:http://pgsyz.baihongyu.com/