C# 使用com获取Windows摄像头列表
作者:CodeOfCC 发布时间:2022-11-03 09:50:49
标签:C#,Windows,摄像头列表
前言
想使用ffmpeg打开摄像头,需要输入摄像头的名称,而ffmpeg本身的枚举摄像头列表功能不是接口
,所以需要用其他方式获取到设备列表。C++获取视频设备列表的方法有不少,但C#获取视频设备列表的方法网上提供的解决方案基本都是依赖第三方库的,为了获取视频设备列表而引入一整个视频库实在是不太必要。经过思考,Windows的directshow和mediafudation都是基于com的,而且C#对com的支持是很好的,基于上述两点我们完全可以在C#中直接调用com。
一、定义com接口
我们使用directshow获取视频设备列表,由于com的跨语言特性,完全可以直接在C#中调用,而不用通过C++封装一层dll给C#使用。我们首先定义需要的com对象接口。
static readonly Guid SystemDeviceEnum = new Guid(0x62BE5D10, 0x60EB, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
static readonly Guid VideoInputDevice = new Guid(0x860BB310, 0x5D01, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
[Flags]
enum CDef
{
None = 0x0,
ClassDefault = 0x1,
BypassClassManager = 0x2,
ClassLegacy = 0x4,
MeritAboveDoNotUse = 0x8,
DevmonCMGRDevice = 0x10,
DevmonDMO = 0x20,
DevmonPNPDevice = 0x40,
DevmonFilter = 0x80,
DevmonSelectiveMask = 0xF0
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("3127CA40-446E-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IErrorLog
{
[PreserveSig]
int AddError([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In] System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo);
}
[ComImport]
[Localizable(false)]
[SuppressUnmanagedCodeSecurity]
[Guid("55272A00-42CB-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyBag
{
[PreserveSig]
int Read([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [MarshalAs(UnmanagedType.Struct)] out object pVar, [In] IErrorLog pErrorLog);
[PreserveSig]
int Write([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In][MarshalAs(UnmanagedType.Struct)] ref object pVar);
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("29840822-5B84-11D0-BD3B-00A0C911CE86")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICreateDevEnum
{
[PreserveSig]
int CreateClassEnumerator([In][MarshalAs(UnmanagedType.LPStruct)] Guid pType, out IEnumMoniker ppEnumMoniker, [In] CDef dwFlags);
}
二、枚举设备
与directshow流程一样,调用com枚举设备即可,本文只展示获取设备名称(FriendlyName),获取其他属性可以参照c++调用directshow的实现。
/// <summary>
/// 枚举视频设备
/// </summary>
public static IEnumerable<string> Devices
{
get
{
IMoniker[] monikers = new IMoniker[5];
var devEnum = Activator.CreateInstance(Type.GetTypeFromCLSID(SystemDeviceEnum)) as ICreateDevEnum;
IEnumMoniker moniker;
if (devEnum.CreateClassEnumerator(VideoInputDevice, out moniker, 0) == 0)
{
while (true)
{
int r = moniker.Next(1, monikers, IntPtr.Zero);
if (r != 0 || monikers[0] == null)
break;
yield return GetName(monikers[0]);
foreach (var i in monikers)
{
if(i!=null)
Marshal.ReleaseComObject(i);
}
}
Marshal.ReleaseComObject(moniker);
}
Marshal.ReleaseComObject(devEnum);
}
}
/// <summary>
/// 获取设备名称
/// </summary>
/// <param name="moniker"></param>
/// <returns></returns>
static string GetName(IMoniker moniker)
{
IPropertyBag property;
object value;
object temp = null;
try
{
Guid guid = typeof(IPropertyBag).GUID;
moniker.BindToStorage(null, null, ref guid, out temp);
property = temp as IPropertyBag;
int hr = property.Read("FriendlyName", out value, null);
Marshal.ThrowExceptionForHR(hr);
return value as string;
}
catch (Exception)
{
return null;
}
finally
{
if (temp != null)
{
Marshal.ReleaseComObject(temp);
}
}
}
三、完整代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
namespace AC
{
public class EnumDevices
{
/// <summary>
/// 枚举视频设备
/// </summary>
public static IEnumerable<string> Devices
{
get
{
IMoniker[] monikers = new IMoniker[5];
var devEnum = Activator.CreateInstance(Type.GetTypeFromCLSID(SystemDeviceEnum)) as ICreateDevEnum;
IEnumMoniker moniker;
if (devEnum.CreateClassEnumerator(VideoInputDevice, out moniker, 0) == 0)
{
while (true)
{
int hr = moniker.Next(1, monikers, IntPtr.Zero);
if (hr != 0 || monikers[0] == null)
break;
yield return GetName(monikers[0]);
foreach (var i in monikers)
{
if(i!=null)
Marshal.ReleaseComObject(i);
}
}
Marshal.ReleaseComObject(moniker);
}
Marshal.ReleaseComObject(devEnum);
}
}
/// <summary>
/// 获取设备名称
/// </summary>
/// <param name="moniker"></param>
/// <returns></returns>
static string GetName(IMoniker moniker)
{
IPropertyBag property;
object value;
object temp = null;
try
{
Guid guid = typeof(IPropertyBag).GUID;
moniker.BindToStorage(null, null, ref guid, out temp);
property = temp as IPropertyBag;
int hr = property.Read("FriendlyName", out value, null);
Marshal.ThrowExceptionForHR(hr);
return value as string;
}
catch (Exception)
{
return null;
}
finally
{
if (temp != null)
{
Marshal.ReleaseComObject(temp);
}
}
}
static readonly Guid SystemDeviceEnum = new Guid(0x62BE5D10, 0x60EB, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
static readonly Guid VideoInputDevice = new Guid(0x860BB310, 0x5D01, 0x11D0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
[Flags]
enum CDef
{
None = 0x0,
ClassDefault = 0x1,
BypassClassManager = 0x2,
ClassLegacy = 0x4,
MeritAboveDoNotUse = 0x8,
DevmonCMGRDevice = 0x10,
DevmonDMO = 0x20,
DevmonPNPDevice = 0x40,
DevmonFilter = 0x80,
DevmonSelectiveMask = 0xF0
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("3127CA40-446E-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IErrorLog
{
[PreserveSig]
int AddError([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In] System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo);
}
[ComImport]
[Localizable(false)]
[SuppressUnmanagedCodeSecurity]
[Guid("55272A00-42CB-11CE-8135-00AA004BB851")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyBag
{
[PreserveSig]
int Read([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [MarshalAs(UnmanagedType.Struct)] out object pVar, [In] IErrorLog pErrorLog);
[PreserveSig]
int Write([In][MarshalAs(UnmanagedType.LPWStr)] string pszPropName, [In][MarshalAs(UnmanagedType.Struct)] ref object pVar);
}
[ComImport]
[SuppressUnmanagedCodeSecurity]
[Guid("29840822-5B84-11D0-BD3B-00A0C911CE86")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICreateDevEnum
{
[PreserveSig]
int CreateClassEnumerator([In][MarshalAs(UnmanagedType.LPStruct)] Guid pType, out IEnumMoniker ppEnumMoniker, [In] CDef dwFlags);
}
}
}
四、使用示例
.net 6.0代码示例如下
// See https://aka.ms/new-console-template for more information
using AC;
//枚举设备
foreach (var i in EnumDevices.Devices)
{
//打印设备名称
Console.WriteLine(i);
}
效果:
来源:https://blog.csdn.net/u013113678/article/details/123771254


猜你喜欢
- 简介这篇文章我一直在纠结到底要不要写,不想写一来因为定时器用法比较简单,二来是面试中也不常问。后来还是决定写了主要是想把自己分析问题思路分享
- Java读文件修改默认换行符Java默认换行符是'\n'。但有时数据并不以'\n'进行换行方法如下publi
- WebBrowser是C#中非常实用的一个控件,本文以实例形式分析了WebBrowser的用法,供大家参考。具体分析如下:一、WebBrow
- 一、IDEA自带打包插件内容:此种方式可以自己选择制作胖包或者瘦包,但推荐此种方式制作瘦包。输出:输出目录在out目录下流程步骤:第一步:
- 本文实例讲述了C++实现的链表类。分享给大家供大家参考。具体如下:#include <iostream>using namesp
- 目录前言Binder的使用模糊进程间调用Binder原理ioctlbinder初始化总结前言Binder是安卓中实现IPC(进程间通信的)常
- 我们知道Android手机操作系统采用的是Linux内核,Linux中最高的系统权限就是Root,这就类似与Windows中的Adminis
- 前言JAVA缓存实现方案有很多,最基本的自己使用Map去构建缓存,或者使用memcached或Redis,但是上述两种缓存框架都要搭建服务器
- 这篇文章主要介绍了Springboot如何设置静态资源缓存一年,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,
- 本文的主要内容包括在下图,下面来一起看看吧。1、&和&&的区别2、switchswitch语句能否作用在byte,能
- 本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时
- 实现效果:先看下效果:需求是 滑动列表 ,其中一部分视图(粉丝数,关注数这一部分)在滑动到顶端的时候不消失,而是停留在整个界面头部。我们先分
- 使用Mybatis的开发者,大多数都会遇到一个问题,就是要写大量的SQL在xml文件中,除了特殊的业务逻辑SQL之外,还有大量结构类似的增删
- 一、html代码 &n
- Maven中建立的依赖管理方式基本已成为Java语言依赖管理的事实标准,Maven的替代者Gradle也基本沿用了Maven的依赖管理机制。
- 一、枚举的概念:C# 枚举(Enum), 枚举类型是用于声明一组命名的常数的基本数据类型(值类型);二、枚举的定义:声明enum变量:enu
- AndroidManifest.xml <uses-feature>和<uses-permisstion>分析及比较
- Java8被称作Java史上变化最大的一个版本。其中包含很多重要的新特性,最核心的就是增加了Lambda表达式和StreamAPI。这两者也
- 本文实例讲述了Android生成带圆角的Bitmap图片。分享给大家供大家参考。具体如下:有时候我们在开发Android应用时,会遇到圆角图
- 1、问题解决主要文件:/m8976/packages/providers/MediaProvider/src/com/android/pro