软件编程
位置:首页>> 软件编程>> C#编程>> C# 使用com获取Windows摄像头列表

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);
}

效果:

C# 使用com获取Windows摄像头列表

来源:https://blog.csdn.net/u013113678/article/details/123771254

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com