Windows下获取视频设备的一种改进实现

Posted fengbingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows下获取视频设备的一种改进实现相关的知识,希望对你有一定的参考价值。

之前在https://blog.csdn.net/fengbingchun/article/details/102806822中介绍过在Windows下获取视频设备列表的方法。其实那种实现方法是有缺陷的,当PC机上连接多个视频设备,并且其中有设备处于启动运行状态时,再调用相关接口获取视频设备可能会崩溃,因为为了获取视频设备列表,它会先以索引0遍历获取视频设备名,然后会执行启动此设备操作。如果此设备已经被其它应用程序启动过,则此时就会崩溃。

其实如果仅仅为了获取视频设备列表,没有必要执行启动设备的操作。以下是测试代码,无需启动任何设备即可获取到所有的视频设备列表。

此测试代码调用的是系统C接口,你也可以调整为调用系统的C++接口实现。

#define CINTERFACE
#define COBJMACROS
#include <strmif.h>
#include <Setupapi.h>
#include <uuids.h>
#include <devguid.h>
#include <memory>
#include <algorithm>

namespace 

std::unique_ptr<char[]> dup_wchar_to_utf8(wchar_t *w, int& len)

	len = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
	std::unique_ptr<char[]> s(new char[len]);
	WideCharToMultiByte(CP_UTF8, 0, w, -1, s.get(), len, 0, 0);
	return s;


 // namespace

int test_get_windows_camera_list()

	CoInitialize(nullptr);

	ICreateDevEnum *devenum = nullptr;
	int r = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&devenum));
	if (r != S_OK) 
		fprintf(stdout, "fail to CoCreateInstance: %d\\n", r);
		return -1;
	

	IEnumMoniker *classenum = nullptr;
	r = ICreateDevEnum_CreateClassEnumerator(devenum, CLSID_VideoInputDeviceCategory, (IEnumMoniker **)&classenum, 0);
	if (r != S_OK) 
		fprintf(stdout, "fail to ICreateDevEnum_CreateClassEnumerator: %d\\n", r);
		return -1;
	

	IMoniker *m = nullptr;
	typedef struct devices_info 
		int index;
		std::string name;
	 devices_info;
	std::vector<devices_info> lists;
	int device_counter = 0;

	while (IEnumMoniker_Next(classenum, 1, &m, nullptr) == S_OK) 
		IPropertyBag *bag = nullptr;
		VARIANT var;
		r = IMoniker_BindToStorage(m, 0, 0, IID_IPropertyBag, (void **)&bag);
		if (r != S_OK) 
			fprintf(stdout, "fail to IMoniker_BindToStorage: %d\\n", r);
			return -1;
		

		var.vt = VT_BSTR;
		r = IPropertyBag_Read(bag, L"FriendlyName", &var, nullptr);
		if (r != S_OK) 
			fprintf(stdout, "fail to IPropertyBag_Read: %d\\n", r);
			return -1;
		

		int length;
		auto friendly_name = dup_wchar_to_utf8(var.bstrVal, length);
		lists.push_back( device_counter++, friendly_name.get() );

		if (bag)
			IPropertyBag_Release(bag);

		IMoniker_Release(m);
	

	IEnumMoniker_Release(classenum);
	CoUninitialize();

	fprintf(stdout, "device lists:\\n");
	std::for_each(lists.cbegin(), lists.cend(), [](const devices_info& info) 
		fprintf(stdout, "  index: %d, name: %s\\n", info.index, info.name.c_str());
	);

	return 0;

执行结果如下:设备索引与设备名并不是固定不变的,再次拔下设备再插上,此时获得的设备索引和设备名可能与之前不同。

GitHubhttps://github.com//fengbingchun/OpenCV_Test

以上是关于Windows下获取视频设备的一种改进实现的主要内容,如果未能解决你的问题,请参考以下文章

基于AsyncRestTemplate异步HTTP请求的一种轻量级技术实现

43亿欧元罚款后,谷歌警告安卓可能不再免费;JDK 12早期试用版发布;微软正为Linux用户改进Windows命令行丨Q新闻

ffmpeg中怎么编程实现获取视频中某指定的一帧

js实现快速排序

Windows Server 2012 虚拟化实战:存储

接口测试的作用