基于DirectShow获取音频视频输入设备列表

同系列文章

工程下载

EnumAudioVideoDevices.zip

DS_AudioVideoDevices.h

/* ----------------------------------------------------------
 * 文件名称:DS_AudioVideoDevices.h
 *
 * 作者:秦建辉
 *
 * 微信:splashcn
 *
 * 博客:http://www.firstsolver.com/wordpress/
 *
 * 开发环境:
 *      Visual Studio V2017
 *
 * 版本历史:
 *		V1.1	2019年01月01日
 *				增加Json输出,便于C#/JAVA调用
 *
 *		V1.0    2010年10月09日
 *				获取音频视频输入设备列表
 * ---------------------------------------------------------- */
#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		256

typedef struct _TDeviceName
{
	WCHAR Name[MAX_FRIENDLY_NAME_LENGTH];	// 设备友好名
	WCHAR Moniker[MAX_MONIKER_NAME_LENGTH];	// 设备Moniker名
} TDeviceName;
#endif

#ifdef __cplusplus
extern "C"
{
#endif

	/*
	功能:用于预加载动态库
	返回值:TRUE
	*/
	BOOL WINAPI Prepare();

	/*
	功能:获取音频视频输入设备列表
	参数说明:
		devices:用于存储返回的设备友好名及Moniker名
		guid:
			CLSID_AudioInputDeviceCategory:获取音频输入设备列表
			CLSID_VideoInputDeviceCategory:获取视频输入设备列表
	返回值:
		错误代码
	说明:
		基于DirectShow
		列表中的第一个设备为系统缺省设备
		capGetDriverDescription只能获得设备驱动名
	*/
	HRESULT WINAPI DS_GetAudioVideoInputDevices(OUT std::vector<TDeviceName> &devices, REFGUID guid);

	/*
	功能:获取音频视频输入设备列表
	参数说明:
		devices:输出,Json字符串,用于存储返回的设备Name和Moniker
		cch:输出,有效字符个数,不包括字符串结束符
		video:
			FALSE:获取音频输入设备列表
			TRUE:获取视频输入设备列表
	返回值:
		错误代码
	说明:
		基于DirectShow
		列表中的第一个设备为系统缺省设备
		capGetDriverDescription只能获得设备驱动名
	*/
	HRESULT WINAPI DS_GetDeviceSources(OUT TCHAR* &devices, OUT int &cch, BOOL video);

	/*
	功能:释放内存
	参数:
		p:要释放的内存指针
	*/
	VOID WINAPI FreeMemory(LPVOID p);

#ifdef __cplusplus
}
#endif

DS_AudioVideoDevices.cpp

#include "DS_AudioVideoDevices.h"
#include <sstream>

#pragma comment(lib, "Strmiids.lib")

// 用于预加载
BOOL WINAPI Prepare() { return TRUE; }

HRESULT WINAPI DS_GetAudioVideoInputDevices(OUT std::vector<TDeviceName> &devices, REFGUID guid)
{
	devices.clear(); // 初始化

	// 初始化COM
	HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	if (SUCCEEDED(hr))
	{	// 创建系统设备枚举器实例
		ICreateDevEnum *pSysDevEnum = NULL;
		hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
		if (SUCCEEDED(hr))
		{	// 获取设备类枚举器
			IEnumMoniker *pEnumCat = NULL;
			hr = pSysDevEnum->CreateClassEnumerator(guid, &pEnumCat, 0);
			if (hr == S_OK)
			{
				LPOLESTR pOleDisplayName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(MAX_MONIKER_NAME_LENGTH * 2));
				if (pOleDisplayName == NULL)
				{
					hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
				}
				else
				{	// 枚举设备名称
					TDeviceName name;
					IMoniker *pMoniker = NULL;
					ULONG cFetched;
					while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
					{
						IPropertyBag *pPropBag;
						hr = pMoniker->BindToStorage(NULL, NULL, IID_IPropertyBag, (void **)&pPropBag);
						if (SUCCEEDED(hr))
						{
							VARIANT varName;
							VariantInit(&varName);
							hr = pPropBag->Read(L"FriendlyName", &varName, NULL); // 获取设备友好名
							if (SUCCEEDED(hr))
							{
								hr = pMoniker->GetDisplayName(NULL, NULL, &pOleDisplayName); // 获取设备Moniker名
								if (SUCCEEDED(hr))
								{
									StringCchCopy(name.Name, MAX_FRIENDLY_NAME_LENGTH, varName.bstrVal);
									StringCchCopy(name.Moniker, MAX_MONIKER_NAME_LENGTH, pOleDisplayName);
									devices.push_back(name);
								}
							}

							VariantClear(&varName);
							pPropBag->Release();
						}
						pMoniker->Release();
					} // End for While
					CoTaskMemFree(pOleDisplayName);
				}
				pEnumCat->Release();
			}
			pSysDevEnum->Release();
		}
		CoUninitialize();
	}

	return hr;
}

HRESULT WINAPI DS_GetDeviceSources(OUT TCHAR* &devices, OUT int &cch, BOOL video)
{
	// 初始化COM
	HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	if (SUCCEEDED(hr))
	{	// 创建系统设备枚举器实例
		ICreateDevEnum *pSysDevEnum = NULL;
		hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
		if (SUCCEEDED(hr))
		{	// 获取设备类枚举器
			IEnumMoniker *pEnumCat = NULL;
			if (video)
			{	// 视频设备
				hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
			}
			else
			{	// 音频设备
				hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0);
			}

			if (hr == S_OK)
			{
				LPOLESTR pOleDisplayName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(MAX_MONIKER_NAME_LENGTH * 2));
				if (pOleDisplayName == NULL)
				{
					hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
				}
				else
				{	// 枚举设备名称
					BOOL first = TRUE;
					std::wostringstream os;
					os << L"[";

					IMoniker *pMoniker = NULL;
					ULONG cFetched;
					while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
					{
						IPropertyBag *pPropBag;
						hr = pMoniker->BindToStorage(NULL, NULL, IID_IPropertyBag, (void **)&pPropBag);
						if (SUCCEEDED(hr))
						{
							VARIANT varName;
							VariantInit(&varName);
							hr = pPropBag->Read(L"FriendlyName", &varName, NULL); // 获取设备友好名
							if (SUCCEEDED(hr))
							{
								hr = pMoniker->GetDisplayName(NULL, NULL, &pOleDisplayName); // 获取设备Moniker名
								if (SUCCEEDED(hr))
								{
									if (first) first = FALSE; else os << L",";
									os << L"{\"Name\":\"" << varName.bstrVal << L"\",\"Moniker\":\"" << pOleDisplayName << L"\"}";
								}
							}
							VariantClear(&varName);
							pPropBag->Release();
						}
						pMoniker->Release();
					} // End for While
					CoTaskMemFree(pOleDisplayName);
					os << L"]";

					std::wstring ws = os.str();
					cch = (int)ws.size();
					devices = (TCHAR*)CoTaskMemAlloc((cch + 1) << 1);
					if (devices == NULL)
					{
						hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
					}
					else
					{
						wcscpy_s(devices, cch + 1, ws.c_str());
					}
				}
				pEnumCat->Release();
			}
			pSysDevEnum->Release();
		}
		CoUninitialize();
	}

	return hr;
}

VOID WINAPI FreeMemory(LPVOID p)
{
	if (p != NULL) CoTaskMemFree(p);
}

DS_AudioVideoDevices.def

LIBRARY DS_AudioVideoDevices

EXPORTS
	Prepare
	DS_GetAudioVideoInputDevices
	DS_GetDeviceSources
	FreeMemory

Comments are closed.