万圣节的礼物:基于DShow和VMR-9的视频捕获模块(VC++)

Demo演示:

开发工具:

Visual Studio v2010

Windows SDK v7.1

版本历史:

V2.2 2010年10月30日

  • 增加状态查询

V2.1 2010年10月25日

  • 增加视频格式控制
  • 增加图像缩放显示

V2.0 2010年10月15日

  • 增加视频捕获功能

V1.0 2010年10月09日

  • 获取视频输入设备列表

功能描述:

C接口,通过DShow和VMR-9实现视频捕获、格式设置和图像抓取。 

接口函数:

DS_GetVideoInputDevices
DS_InitCaptureGraphBuilder
DS_SetMediaControl
DS_GetFilterGraphState
DS_UninitCaptureGraphBuilder
DS_GetVideoFormats
DS_GetCurrentFormatIndex
DS_UpdateFormat
DS_GetCurrentDIBImage
DS_DIB2DDB
DS_FreeDIB
DS_GetCurrentDDBImage
DS_SaveDDB2PNG
DS_SaveDDB2JPEG
DS_DisplayImage

下载地址:

DS_VideoInputDevices.zip

源代码:

DS_VideoInputDevices.h

/* ---------------------------------------------------------- 文件名称:DS_VideoInputDevices.h 作者:秦建辉 MSN:[email protected] 版本历史: V2.2 2010年10月30日 增加状态查询 V2.1 2010年10月25日 增加视频格式控制 增加图像缩放显示 V2.0 2010年10月15日 增加视频捕获功能 V1.0 2010年10月09日 获取视频输入设备列表 功能描述: 获取视频输入设备列表 视频采集 视频格式控制 接口函数: DS_GetVideoInputDevices DS_InitCaptureGraphBuilder DS_SetMediaControl DS_GetFilterGraphState DS_UninitCaptureGraphBuilder DS_GetVideoFormats DS_GetCurrentFormatIndex DS_UpdateFormat DS_GetCurrentDIBImage DS_DIB2DDB DS_FreeDIB DS_GetCurrentDDBImage DS_SaveDDB2PNG DS_SaveDDB2JPEG DS_DisplayImage 说明: 由于采用VMR-9,操作系统至少为Windows XP SP2或者安装DirectX 9.0以上版本 调用方法: 第一步:调用DS_GetVideoInputDevices获取设备列表 第二步:根据选择的设备调用DS_InitCaptureGraphBuilder创建Capture Graph Builder 第三步:调用DS_SetMediaControl设置媒体控制 最 后:调用DS_UninitCaptureGraphBuilder释放Capture Graph Builder 图像抓取方法一: 调用DS_GetCurrentDIBImage获取当前视频图像(设备无关位图) 调用DS_DIB2DDB将DIB图像转化为DDB图像 最后调用DS_FreeDIB释放DIB图像资源 图像抓取方法二: 调用DS_GetCurrentDDBImage获取当前视频图像(设备相关位图) 更新视频格式: 首先调用DS_SetMediaControl停止Filter Graph 然后调用DS_UpdateFormat更新视频格式 ------------------------------------------------------------ */ #pragma once #include <windows.h> #include <vector> #include <dshow.h> #ifndef MACRO_GROUP_DEVICENAME #define MACRO_GROUP_DEVICENAME #define MAX_FRIENDLY_NAME_LENGTH 128 #define MAX_MONIKER_NAME_LENGTH 128 typedef struct _TDeviceName { WCHAR FriendlyName[MAX_FRIENDLY_NAME_LENGTH]; // 设备友好名 WCHAR MonikerName[MAX_MONIKER_NAME_LENGTH]; // 设备Moniker名 } TDeviceName; #endif #ifndef MACRO_GROUP_VIDEOFORMAT #define MACRO_GROUP_VIDEOFORMAT typedef struct _TVideoFormat { LONG biWidth; LONG biHeight; WORD biBitCount; } TVideoFormat; #endif #ifdef __cplusplus extern "C" { #endif // ------------------------------视频控制------------------------------------ /* 功能:获取视频输入设备列表 参数说明: vectorDevices:用于存储返回的设备友好名及Moniker名 返回值: 错误代码 说明: 基于DirectShow 列表中的第一个设备为系统缺省设备 capGetDriverDescription只能获得设备驱动名 */ HRESULT WINAPI DS_GetVideoInputDevices( std::vector<TDeviceName> &vectorDevices ); /* 功能:通过设备友好名和图像显示窗口句柄创建Capture Graph Builder 参数说明: FriendlyName:设备友好名 vectorDevices:设备列表 hWnd:用于显示视频图像的窗口句柄 返回值: Capture Graph Builder */ ICaptureGraphBuilder2* WINAPI DS_InitCaptureGraphBuilder( WCHAR* FriendlyName, std::vector<TDeviceName> &vectorDevices, HWND hWnd ); /* 功能:设置媒体控制 参数说明: pBuilder:Capture Graph Builder uCommandType: State_Stopped:停止设备 State_Paused:暂停设备 State_Running:启动设备 返回值: 错误代码 */ HRESULT WINAPI DS_SetMediaControl( ICaptureGraphBuilder2 *pBuilder, FILTER_STATE uCommandType ); /* 功能:获取Filter Graph的状态 参数说明: pBuilder:Capture Graph Builder msTimeout:最大等待时间 fs:存储返回的状态值 返回值: 错误代码 */ HRESULT WINAPI DS_GetFilterGraphState( ICaptureGraphBuilder2 *pBuilder, LONG msTimeout, FILTER_STATE &fs ); /* 功能:释放Capture Graph Builder 参数说明: pBuilder:Capture Graph Builder 返回值: 无 */ VOID WINAPI DS_UninitCaptureGraphBuilder( ICaptureGraphBuilder2* &pBuilder ); // ----------------------格式设置------------------------------------------- /* 功能:获取摄像头支持的的视频格式 参数说明: pBuilder:Capture Graph Builder vectorFormats:设备支持的格式集(宽度X高度X颜色数) 返回值: 错误代码 */ HRESULT WINAPI DS_GetVideoFormats( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats ); /* 功能:获取当前视频格式索引 参数说明: pBuilder:Capture Graph Builder vectorFormats:设备支持的格式集(宽度X高度X颜色数) 返回值: -1:失败 >=0:当前视频格式索引 */ INT WINAPI DS_GetCurrentFormatIndex( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats ); /* 功能:更新视频格式 参数说明: pBuilder:Capture Graph Builder vectorFormats:设备支持的格式集(宽度X高度X颜色数) iIndex:选中的格式索引号 isNeedQueryState:更新前是否先查询Filter Graph的状态。 返回值: 错误代码 E_INVALIDARG:参数错误 E_ACCESSDENIED:Filter Graph没有处于停止状态 说明: 更新视频格式前,需要先停止视频流,断开连接,否则将失败 */ HRESULT WINAPI DS_UpdateFormat( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats, INT iIndex, BOOL isNeedQueryState ); // --------------------图像处理----------------------------------------------- /* 功能:获取当前视频图像(设备无关位图) 参数说明: pBuilder:Capture Graph Builder pDIB:用于存储当前图像 返回值: 错误代码 */ HRESULT WINAPI DS_GetCurrentDIBImage( ICaptureGraphBuilder2 *pBuilder, LPBYTE &pDIB ); /* 功能:转换DIB图像到DDB图像 参数说明: pDIB:获取的DIB图像 hDC:DDB图像依赖的设备上下文句柄 返回值: DDB图像句柄 */ HBITMAP WINAPI DS_DIB2DDB( LPBYTE pDIB, HDC hDC ); /* 功能:释放DIB图像资源 参数说明: pDIB:要释放的DIB图像 返回值: 无 */ VOID WINAPI DS_FreeDIB( LPBYTE &pDIB ); /* 功能:获取当前视频图像(设备相关位图) 参数说明: pBuilder:Capture Graph Builder hDC:DDB图像依赖的设备上下文句柄 返回值: DDB图像句柄 */ HBITMAP WINAPI DS_GetCurrentDDBImage( ICaptureGraphBuilder2 *pBuilder, HDC hDC ); /* 功能:将DDB图像保存为PNG文件 参数说明: pszFileName:要保存的PNG图像文件名 hBitmap:要存储的BITMAP图像句柄 返回值: 错误代码 */ HRESULT WINAPI DS_SaveDDB2PNG( LPCTSTR pszFileName, HBITMAP hBitmap ); /* 功能:将DDB图像保存为JPEG文件 参数说明: pszFileName:要保存的JPEG图像文件名 hBitmap:要存储的BITMAP图像句柄 返回值: 错误代码 */ HRESULT WINAPI DS_SaveDDB2JPEG( LPCTSTR pszFileName, HBITMAP hBitmap ); /* 功能:显示图像到窗口 参数说明: hBitmap:要显示的BITMAP图像句柄 hWnd:要显示位图的窗口句柄 返回值: 无 说明: 在OnPaint事件中也需要调用该函数重绘图像。 */ VOID WINAPI DS_DisplayImage( HBITMAP hBitmap, HWND hWnd ); #ifdef __cplusplus } #endif

DS_VideoInputDevices.cpp

#include <atlimage.h> #include "DS_VideoInputDevices.h" #include <d3d9.h> #include <Vmr9.h> #pragma comment(lib, "Strmiids.lib") // ------------------------------视频设置------------------------------------ // 设定VMR-9 Filter名称 #define FILTER_NAME_VMR9 L"Video Mixing Renderer 9" #define FILTER_NAME_VCS L"Video Capture Source" // 获取视频输入类设备列表 HRESULT WINAPI DS_GetVideoInputDevices( std::vector<TDeviceName> &vectorDevices ) { TDeviceName name; HRESULT hr; // 初始化 vectorDevices.clear(); // 初始化COM hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ); if (FAILED(hr)) { return hr; } // 实例系统设备枚举器 ICreateDevEnum *pSysDevEnum = NULL; hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (LPVOID*)&pSysDevEnum ); if (FAILED(hr)) { CoUninitialize(); return hr; } // 创建视频输入类设备枚举器 IEnumMoniker *pEnumCat = NULL; hr = pSysDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &pEnumCat, 0 ); if (hr == S_OK) { // 枚举设备名称 IMoniker *pMoniker = NULL; while (pEnumCat->Next( 1, &pMoniker, NULL ) == S_OK) { IPropertyBag *pPropBag; hr = pMoniker->BindToStorage( NULL, NULL, IID_IPropertyBag, (LPVOID*)&pPropBag ); if (SUCCEEDED(hr)) { // 获取设备友好名 VARIANT varName; VariantInit( &varName ); hr = pPropBag->Read( L"FriendlyName", &varName, NULL ); if (SUCCEEDED(hr)) { StringCchCopy( name.FriendlyName, MAX_FRIENDLY_NAME_LENGTH, varName.bstrVal ); // 获取设备Moniker名 LPOLESTR pOleDisplayName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(MAX_MONIKER_NAME_LENGTH * 2)); if (pOleDisplayName != NULL) { hr = pMoniker->GetDisplayName( NULL, NULL, &pOleDisplayName ); if (SUCCEEDED(hr)) { StringCchCopy( name.MonikerName, MAX_MONIKER_NAME_LENGTH, pOleDisplayName ); vectorDevices.push_back( name ); } CoTaskMemFree( pOleDisplayName ); } } VariantClear( &varName ); pPropBag->Release(); } // 注意:IEnumMoniker::Next增加IMoniker引用计数 pMoniker->Release(); } // End for While pEnumCat->Release(); } pSysDevEnum->Release(); CoUninitialize(); return hr; } // 创建Source Filter HRESULT WINAPI DS_AddSourceFilter( WCHAR* FriendlyName, std::vector<TDeviceName> &vectorDevices, IGraphBuilder *pGB, IBaseFilter* &pFilter ) { // 参数判断 if ((FriendlyName == NULL) || (pGB == NULL)) { return E_INVALIDARG; } // 查找Moniker名称 UINT uIndex, dwSize; dwSize = vectorDevices.size(); for (uIndex = 0; uIndex < dwSize; uIndex++) { if (wcscmp(FriendlyName, vectorDevices[uIndex].FriendlyName) == 0) { break; } } if (uIndex >= dwSize) { return E_FAIL; } // 解析Moniker名称,获得Moniker指针 IBindCtx *pBindCtx; HRESULT hr = CreateBindCtx( 0, &pBindCtx ); if (hr == S_OK) { IMoniker *pMoniker = NULL; ULONG chEaten = 0; hr = MkParseDisplayName( pBindCtx, vectorDevices[uIndex].MonikerName, &chEaten, &pMoniker ); if (SUCCEEDED(hr)) { hr = BindMoniker( pMoniker, 0, IID_IBaseFilter, (LPVOID*)&pFilter ); if (SUCCEEDED(hr)) { hr = pGB->AddFilter( pFilter, FILTER_NAME_VCS ); // 增加Filter引用计数 // BindMoniker增加Filter引用计数 pFilter->Release(); } // MkParseDisplayName增加IMoniker引用计数 pMoniker->Release(); } pBindCtx->Release(); } return hr; } // 创建VMR-9 Sink Filter HRESULT WINAPI DS_AddSinkFilter( HWND hWnd, IGraphBuilder *pGB, IBaseFilter* &pFilter ) { // 参数判断 if ((hWnd == NULL) || (pGB == NULL)) { return E_INVALIDARG; } // 创建VMR-9实例 HRESULT hr = CoCreateInstance( CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (LPVOID*)&pFilter ); if (SUCCEEDED(hr)) { hr = pGB->AddFilter( pFilter, FILTER_NAME_VMR9 ); // 增加Filter引用计数 if (SUCCEEDED(hr)) { IVMRFilterConfig9* pConfig; hr = pFilter->QueryInterface( IID_IVMRFilterConfig9, (LPVOID*)&pConfig ); if (SUCCEEDED(hr)) { pConfig->SetRenderingMode( VMR9Mode_Windowless ); pConfig->Release(); // 注意:接口查询增加引用计数 // 设置视频捕捉窗口 IVMRWindowlessControl9 *pWC = NULL; hr = pFilter->QueryInterface( IID_IVMRWindowlessControl9, (LPVOID*)&pWC ); if (SUCCEEDED(hr)) { RECT rc; ::GetClientRect( hWnd, &rc ); pWC->SetVideoPosition( NULL, &rc ); // 显示整幅图像 pWC->SetVideoClippingWindow( hWnd ); pWC->Release(); // 注意:接口查询增加引用计数 } } } pFilter->Release(); } return hr; } // 创建Capture Graph Builder ICaptureGraphBuilder2* WINAPI DS_InitCaptureGraphBuilder( WCHAR* FriendlyName, std::vector<TDeviceName> &vectorDevices, HWND hWnd ) { HRESULT hr; // 初始化COM hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); if (FAILED(hr)) { return NULL; } // 创建IGraphBuilder接口 IGraphBuilder *pGB = NULL; hr = CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (LPVOID*)&pGB ); if (FAILED(hr)) { CoUninitialize(); return NULL; } // 添加Source Filter IBaseFilter *pSourceFilter = NULL; hr = DS_AddSourceFilter( FriendlyName, vectorDevices, pGB, pSourceFilter ); if (FAILED(hr)) { pGB->Release(); CoUninitialize(); return NULL; } // 添加Sink Filter IBaseFilter *pSinkFilter = NULL; hr = DS_AddSinkFilter( hWnd, pGB, pSinkFilter ); if (FAILED(hr)) { pGB->Release(); CoUninitialize(); return NULL; } // 创建ICaptureGraphBuilder2接口 ICaptureGraphBuilder2 *pBuilder = NULL; hr = CoCreateInstance( CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (LPVOID*)&pBuilder ); if (SUCCEEDED(hr)) { // 设置FilterGraph pBuilder->SetFiltergraph( pGB ); // 连接Source Filter和Sink Filter hr = pBuilder->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSourceFilter, NULL, pSinkFilter ); } pGB->Release(); CoUninitialize(); return pBuilder; } // 设置媒体控制 HRESULT WINAPI DS_SetMediaControl( ICaptureGraphBuilder2 *pBuilder, FILTER_STATE uCommandType ) { if (pBuilder == NULL) { return E_INVALIDARG; } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IMediaControl *pMediaControl = NULL; hr = pGB->QueryInterface( IID_IMediaControl, (LPVOID*)&pMediaControl ); if (SUCCEEDED(hr)) { switch (uCommandType) { case State_Running: // 运行 hr = pMediaControl->Run(); break; case State_Stopped: // 停止 hr = pMediaControl->Stop(); break; case State_Paused: // 暂停 hr = pMediaControl->Pause(); break; } pMediaControl->Release(); // 注意:接口查询增加引用计数 } pGB->Release(); // 注意:接口查询增加引用计数 } return hr; } // 获取Filter Graph的状态 HRESULT WINAPI DS_GetFilterGraphState( ICaptureGraphBuilder2 *pBuilder, LONG msTimeout, FILTER_STATE &fs ) { if (pBuilder == NULL) { return E_INVALIDARG; } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IMediaControl *pMediaControl = NULL; hr = pGB->QueryInterface( IID_IMediaControl, (LPVOID*)&pMediaControl ); if (SUCCEEDED(hr)) { hr = pMediaControl->GetState( msTimeout, (OAFilterState*)&fs ); pMediaControl->Release(); // 注意:接口查询增加引用计数 } pGB->Release(); // 注意:接口查询增加引用计数 } return hr; } // 释放Capture Graph Builder VOID WINAPI DS_UninitCaptureGraphBuilder( ICaptureGraphBuilder2* &pBuilder ) { if (pBuilder == NULL) { return; } IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IMediaControl *pMediaControl = NULL; hr = pGB->QueryInterface( IID_IMediaControl, (LPVOID*)&pMediaControl ); if (SUCCEEDED(hr)) { pMediaControl->Stop(); pMediaControl->Release(); } pGB->Release(); } pBuilder->Release(); pBuilder = NULL; return; } // --------------------格式设置----------------------------------------------- VOID WINAPI DS_DeleteMediaType( AM_MEDIA_TYPE *pmt ) { if (pmt != NULL) { if (pmt->cbFormat != 0) { CoTaskMemFree( pmt->pbFormat ); pmt->cbFormat = 0; pmt->pbFormat = NULL; } if (pmt->pUnk != NULL) { pmt->pUnk->Release(); pmt->pUnk = NULL; } CoTaskMemFree( pmt ); } } // 获取摄像头支持的的视频格式 HRESULT WINAPI DS_GetVideoFormats( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats ) { if (pBuilder == NULL) { return E_INVALIDARG; } // 初始化 vectorFormats.clear(); // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IBaseFilter *pSourceFilter; hr = pGB->FindFilterByName( FILTER_NAME_VCS, &pSourceFilter ); if (SUCCEEDED(hr)) { IAMStreamConfig *pIAMS; hr = pBuilder->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSourceFilter, IID_IAMStreamConfig, (LPVOID*)&pIAMS ); if (SUCCEEDED(hr)) { INT iCount = 0; INT iSize = 0; hr = pIAMS->GetNumberOfCapabilities( &iCount, &iSize ); if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) { VIDEO_STREAM_CONFIG_CAPS scc; TVideoFormat videoFormat; for (INT i = 0; i < iCount; i++) { AM_MEDIA_TYPE *pmt = NULL; hr = pIAMS->GetStreamCaps( i, &pmt, reinterpret_cast<LPBYTE>(&scc) ); if (SUCCEEDED(hr)) { if (pmt->formattype == FORMAT_VideoInfo) { // 获取视频格式 VIDEOINFOHEADER *pVIH; pVIH = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat); videoFormat.biWidth = pVIH->bmiHeader.biWidth; videoFormat.biHeight = pVIH->bmiHeader.biHeight; videoFormat.biBitCount = pVIH->bmiHeader.biBitCount; vectorFormats.push_back( videoFormat ); } DS_DeleteMediaType( pmt ); } } // End for i } else { hr = E_FAIL; } pIAMS->Release(); } pSourceFilter->Release(); } pGB->Release(); } return hr; } // 获取当前视频格式索引 INT WINAPI DS_GetCurrentFormatIndex( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats ) { INT iIndex = -1; if (pBuilder != NULL) { // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IBaseFilter *pSourceFilter; hr = pGB->FindFilterByName( FILTER_NAME_VCS, &pSourceFilter ); if (SUCCEEDED(hr)) { IAMStreamConfig *pIAMS; hr = pBuilder->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSourceFilter, IID_IAMStreamConfig, (LPVOID*)&pIAMS ); if (SUCCEEDED(hr)) { // 获取当前视频格式 AM_MEDIA_TYPE *pmt = NULL; hr = pIAMS->GetFormat( &pmt ); if (SUCCEEDED(hr)) { if (pmt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER *pVIH = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat); LONG biWidth = pVIH->bmiHeader.biWidth; LONG biHeight = pVIH->bmiHeader.biHeight; WORD biBitCount = pVIH->bmiHeader.biBitCount; // 查找匹配的格式 UINT size = vectorFormats.size(); for (UINT i = 0; i < size; i++) { if ((vectorFormats[i].biWidth == biWidth) && (vectorFormats[i].biHeight == biHeight) && (vectorFormats[i].biBitCount == biBitCount)) { iIndex = i; break; } } } DS_DeleteMediaType( pmt ); } pIAMS->Release(); } pSourceFilter->Release(); } pGB->Release(); } } return iIndex; } // 断开两个Filter之间的连接 HRESULT WINAPI DS_DisconnectFilter( ICaptureGraphBuilder2* pBuilder, IBaseFilter* pSourceFilter, IBaseFilter* pSinkFilter ) { // 检测参数 if (pBuilder == NULL) { return E_INVALIDARG; } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { if (pSourceFilter != NULL) { // 获取视频输出Pin IPin *pPinOutput = NULL; hr = pBuilder->FindPin( pSourceFilter, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, FALSE, 0, &pPinOutput ); if (hr == S_OK) { // 断开 pGB->Disconnect( pPinOutput ); pPinOutput->Release(); } } if (SUCCEEDED(hr) && (pSinkFilter != NULL)) { // 获取视频输入Pin IPin *pPinInput = NULL; hr = pBuilder->FindPin( pSinkFilter, PINDIR_INPUT, NULL, NULL, FALSE, 0, &pPinInput ); if (hr == S_OK) { // 断开 pGB->Disconnect( pPinInput ); pPinInput->Release(); } } pGB->Release(); } return hr; } // 设置视频格式 HRESULT WINAPI DS_SetFormat( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats, INT iIndex ) { if ((pBuilder == NULL) || (iIndex < 0) || (iIndex >= vectorFormats.size())) { return E_INVALIDARG; } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IBaseFilter *pSourceFilter; hr = pGB->FindFilterByName( FILTER_NAME_VCS, &pSourceFilter ); if (SUCCEEDED(hr)) { IAMStreamConfig *pIAMS; hr = pBuilder->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSourceFilter, IID_IAMStreamConfig, (LPVOID*)&pIAMS ); if (SUCCEEDED(hr)) { INT iCount = 0; INT iSize = 0; BOOL isOK = FALSE; hr = pIAMS->GetNumberOfCapabilities( &iCount, &iSize ); if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) { VIDEO_STREAM_CONFIG_CAPS scc; for (INT i = 0; i < iCount; i++) { AM_MEDIA_TYPE *pmt = NULL; hr = pIAMS->GetStreamCaps( i, &pmt, reinterpret_cast<LPBYTE>(&scc) ); if (SUCCEEDED(hr)) { if (pmt->formattype == FORMAT_VideoInfo) { // 获取视频格式 VIDEOINFOHEADER *pVIH = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat); LONG biWidth = pVIH->bmiHeader.biWidth; LONG biHeight = pVIH->bmiHeader.biHeight; WORD biBitCount = pVIH->bmiHeader.biBitCount; // 比较 if ((biWidth == vectorFormats[iIndex].biWidth) && (biHeight == vectorFormats[iIndex].biHeight) && (biBitCount == vectorFormats[iIndex].biBitCount)) { // 找到匹配选项 hr = pIAMS->SetFormat( pmt ); isOK = TRUE; } } DS_DeleteMediaType( pmt ); } if (isOK)break; } // End for iFormat } if (!isOK)hr = E_FAIL; pIAMS->Release(); } pSourceFilter->Release(); } pGB->Release(); } return hr; } // 更新视频格式 HRESULT WINAPI DS_UpdateFormat( ICaptureGraphBuilder2* pBuilder, std::vector<TVideoFormat> &vectorFormats, INT iIndex, BOOL isNeedQueryState ) { if ((pBuilder == NULL) || (iIndex < 0) || (iIndex >= vectorFormats.size())) { return E_INVALIDARG; } // 是否先判断Filter Graph的状态 if (isNeedQueryState) { FILTER_STATE fs; HRESULT hr = DS_GetFilterGraphState( pBuilder, 1000, fs ); if ((hr != S_OK) || (fs != State_Stopped)) { // 注意:如果Filter Graph不处于停止状态,会导致格式设置失败 return E_ACCESSDENIED; } } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IBaseFilter *pSourceFilter = NULL; IBaseFilter *pSinkFilter = NULL; pGB->FindFilterByName( FILTER_NAME_VCS, &pSourceFilter ); pGB->FindFilterByName( FILTER_NAME_VMR9, &pSinkFilter ); if ((pSourceFilter != NULL) && (pSinkFilter != NULL)) { // 完全断开连接 DS_DisconnectFilter( pBuilder, pSourceFilter, pSinkFilter ); // 设置新的视频格式 hr = DS_SetFormat( pBuilder, vectorFormats, iIndex ); if (SUCCEEDED(hr)) { // 重新恢复连接 hr = pBuilder->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSourceFilter, NULL, pSinkFilter ); } } if (pSourceFilter != NULL)pSourceFilter->Release(); if (pSinkFilter != NULL)pSinkFilter->Release(); pGB->Release(); } return hr; } // --------------------图像处理----------------------------------------------- // 获取当前视频图像(设备无关位图) HRESULT WINAPI DS_GetCurrentDIBImage( ICaptureGraphBuilder2 *pBuilder, LPBYTE &pDIB ) { if (pBuilder == NULL) { return E_INVALIDARG; } // 视频控制 IGraphBuilder *pGB = NULL; HRESULT hr = pBuilder->GetFiltergraph( &pGB ); if (SUCCEEDED(hr)) { IBaseFilter *pVMR9; hr = pGB->FindFilterByName( FILTER_NAME_VMR9, &pVMR9 ); if (SUCCEEDED(hr)) { IVMRWindowlessControl9 *pWindowlessControl = NULL; hr = pVMR9->QueryInterface( IID_IVMRWindowlessControl9, (LPVOID*)&pWindowlessControl ); if (SUCCEEDED(hr)) { // 获取设备无关位图文件 hr = pWindowlessControl->GetCurrentImage( &pDIB ); pWindowlessControl->Release(); // 注意:接口查询增加引用计数 } pVMR9->Release(); } pGB->Release(); // 注意:GetFiltergraph增加引用计数 } return hr; } // 转换DIB图像到DDB图像 HBITMAP WINAPI DS_DIB2DDB( LPBYTE pDIB, HDC hDC ) { return CreateDIBitmap( hDC, (BITMAPINFOHEADER*)pDIB, CBM_INIT, pDIB + sizeof(BITMAPINFOHEADER), (BITMAPINFO*)pDIB, DIB_RGB_COLORS ); } // 释放DIB图像资源 VOID WINAPI DS_FreeDIB( LPBYTE &pDIB ) { // 释放资源 CoTaskMemFree( pDIB ); pDIB = NULL; } // 获取当前视频图像(设备相关位图) HBITMAP WINAPI DS_GetCurrentDDBImage( ICaptureGraphBuilder2 *pBuilder, HDC hDC ) { LPBYTE pDIB = NULL; HRESULT hr = DS_GetCurrentDIBImage( pBuilder, pDIB ); if (FAILED(hr)) { return NULL; } // 转换DIB图像到DDB图像 HBITMAP hBitmap = DS_DIB2DDB( pDIB, hDC ); // 释放资源 CoTaskMemFree( pDIB ); return hBitmap; } // 将DDB图像保存为PNG文件 HRESULT WINAPI DS_SaveDDB2PNG( LPCTSTR pszFileName, HBITMAP hBitmap ) { // 检查入口参数 if ((pszFileName == NULL) || (hBitmap == NULL)) { return E_INVALIDARG; } CImage image; // 建立附属关系 image.Attach( hBitmap ); // 存储为PNG图像 HRESULT hr = image.Save( pszFileName, Gdiplus::ImageFormatPNG ); // 解除附属关系 image.Detach(); return hr; } // 将DDB图像保存为JPEG文件 HRESULT WINAPI DS_SaveDDB2JPEG( LPCTSTR pszFileName, HBITMAP hBitmap ) { // 检查入口参数 if ((pszFileName == NULL) || (hBitmap == NULL)) { return E_INVALIDARG; } CImage image; // 建立附属关系 image.Attach( hBitmap ); // 存储为PNG图像 HRESULT hr = image.Save( pszFileName, Gdiplus::ImageFormatJPEG ); // 解除附属关系 image.Detach(); return hr; } // 显示图像到窗口 VOID WINAPI DS_DisplayImage( HBITMAP hBitmap, HWND hWnd ) { if ((hBitmap == NULL) || (hWnd == NULL))return; CImage image; RECT rc; // 建立附属关系 image.Attach( hBitmap ); HDC dc = ::GetDC( hWnd ); // 缩放图像 ::GetClientRect( hWnd, &rc ); ::SetStretchBltMode( dc, COLORONCOLOR ); // 设置图像伸展模式 image.Draw( dc, rc ); // 解除附属关系 image.Detach(); }

你可能感兴趣的:(video,filter,null,Graph,vc++,winapi)