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

同系列文章

工程下载

EnumAudioVideoDevices.zip

MF_AudioVideoDevices.h

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

#include <windows.h>
#include <vector>
#include <Mfidl.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:
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID:获取音频输入设备列表
			MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID:获取视频输入设备列表
	返回值:
		错误代码
	说明:
		基于Media Foundation
		列表中的第一个设备为系统缺省设备
		capGetDriverDescription只能获得设备驱动名
		操作系统要求Windows 7及以上版本(关键)
	*/
	HRESULT WINAPI MF_GetAudioVideoInputDevices(OUT std::vector<TDeviceName> &devices, REFGUID guid);

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

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

#ifdef __cplusplus
}
#endif

MF_AudioVideoDevices.cpp

#include "MF_AudioVideoDevices.h"
#include <Mfapi.h>
#include <sstream>

#pragma comment(lib, "Mfplat.lib")
#pragma comment(lib, "Mf.lib")

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

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

	// 初始化Media Foundation
	HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_LITE);
	if (SUCCEEDED(hr))
	{	// 创建属性搜索页
		IMFAttributes *pAttributes = NULL;
		hr = MFCreateAttributes(&pAttributes, 1);	// 要求Windows Vista
		if (SUCCEEDED(hr))
		{	// 设置搜索关键字-枚举音频视频设备
			hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, guid);
			if (SUCCEEDED(hr))
			{	// 获取搜索结果
				IMFActivate **ppDevices = NULL;
				UINT32 dwCount = 0;
				hr = MFEnumDeviceSources(pAttributes, &ppDevices, &dwCount);	// 要求Windows 7
				if (SUCCEEDED(hr))
				{
					if (dwCount == 0)
					{	// 没有找到
						hr = E_FAIL;
					}
					else
					{
						TDeviceName name;
						for (DWORD i = 0; i < dwCount; i++)
						{	// 获取设备友好名
							ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, name.Name, MAX_FRIENDLY_NAME_LENGTH, NULL);

							// 获取设备Moniker名
							ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, name.Moniker, MAX_MONIKER_NAME_LENGTH, NULL);
							devices.push_back(name);
							ppDevices[i]->Release();
						}
					}
					CoTaskMemFree(ppDevices); // 释放内存
				}
			}
			pAttributes->Release();
		}
		MFShutdown(); // 关闭Media Foundation
	}

	return hr;
}

HRESULT WINAPI MF_GetDeviceSources(OUT TCHAR* &devices, OUT int &cch, BOOL video)
{	// 初始化Media Foundation
	HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_LITE);
	if (SUCCEEDED(hr))
	{	// 创建属性搜索页
		IMFAttributes *pAttributes = NULL;
		hr = MFCreateAttributes(&pAttributes, 1);	// 要求Windows Vista
		if (SUCCEEDED(hr))
		{	// 设置搜索关键字-枚举音频视频设备
			if (video)
			{	// 视频设备
				hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
			}
			else
			{	// 音频设备
				hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);
			}

			if (SUCCEEDED(hr))
			{	// 获取搜索结果
				IMFActivate **ppDevices = NULL;
				UINT32 dwCount = 0;
				hr = MFEnumDeviceSources(pAttributes, &ppDevices, &dwCount);	// 要求Windows 7
				if (SUCCEEDED(hr))
				{
					if (dwCount == 0)
					{	// 没有找到
						hr = E_FAIL;
					}
					else
					{
						TCHAR Buffer[MAX_MONIKER_NAME_LENGTH];
						std::wostringstream os;
						os << L"[";
						for (DWORD i = 0; i < dwCount; i++)
						{
							if (i != 0) os << L",";

							// 获取设备友好名
							ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, reinterpret_cast<LPWSTR>(&Buffer), MAX_FRIENDLY_NAME_LENGTH, NULL);
							os << L"{\"Name\":\"" << Buffer << L"\",";

							// 获取设备Moniker名
							ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, reinterpret_cast<LPWSTR>(&Buffer), MAX_MONIKER_NAME_LENGTH, NULL);
							os << L"\"Moniker\":\"" << Buffer << L"\"}";							
							ppDevices[i]->Release();
						}
						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());
						}
					}
					CoTaskMemFree(ppDevices); // 释放内存
				}
			}
			pAttributes->Release();
		}
		MFShutdown(); // 关闭Media Foundation
	}

	return hr;
}

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

MF_AudioVideoDevices.def

LIBRARY MF_AudioVideoDevices

EXPORTS
	Prepare
	MF_GetAudioVideoInputDevices
	MF_GetDeviceSources
	FreeMemory

Comments are closed.