同系列文章
工程下载
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