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

目录
  • 前言
  • 一、定义com接口
  • 二、枚举设备
  • 三、完整代码
  • 四、使用示例
  • 总结

前言

想使用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获取视频设备列表的方法,只要知道了com的一些基本原理以及c#和com的关系,很容易就能实现c#直接使用directshow的功能,第三方的库也是做了类似的工作,定义了完整的directshow的接口,只是笔者使用的环境中只需要枚举视频设备列表,不需要其他功能,引入完整的directshow接口有点大材小用,所以还不如自己定义几个必要的接口来的实在。

到此这篇关于C# 使用com获取Windows摄像头列表的文章就介绍到这了,更多相关C# 获取Windows摄像头列表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#获取摄像头拍照显示图像的方法

    本文实例为大家分享了C#获取摄像头拍照显示图像的具体代码,供大家参考,具体内容如下 概述 之前有个需求,就是在web界面可以实现调用摄像头,用户把手机的个人二维码展示给摄像头,摄像头进行摄像识别用户. 其实本质就是保存图像二维码,在进行二维码识别. 下面来看看如何实现. 主要代码实现 1.初始化摄像头 /// <summary>         /// 初始化摄像头         /// </summary>         /// <param name="ha

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

    目录 前言 一.定义com接口 二.枚举设备 三.完整代码 四.使用示例 总结 前言 想使用ffmpeg打开摄像头,需要输入摄像头的名称,而ffmpeg本身的枚举摄像头列表功能不是接口,所以需要用其他方式获取到设备列表.C++获取视频设备列表的方法有不少,但C#获取视频设备列表的方法网上提供的解决方案基本都是依赖第三方库的,为了获取视频设备列表而引入一整个视频库实在是不太必要.经过思考,Windows的directshow和mediafudation都是基于com的,而且C#对com的支持是很好

  • PowerShell获取Windows用户列表、用户信息的方法

    WMI是Windows管理规范的缩写,其中包含很多系统的软硬件信息.而Windows用户信息也可以通过WMI对象来获取.PowerShell提供了对WMI的访问功能,十分方便且强大--这就是Get-WmiObject这个cmdlet. 获取所有的Windows用户列表: Get-WmiObject -Class Win32_UserAccount 或者 Get-WmiObject 复制代码 代码如下: Win32_UserAccount 如果是想知道查看当前登录的用户的信息,可以用如下语句: 复

  • PowerShell函数中使用$PSBoundParameters获取输入参数列表实例

    本文介绍在自定义PowerShell函数时,有一个$PSBoundParameters的变量可以获取到输入参数列表.获取输入参入列表对我们进行功能调试有很大的帮助. 当我们在执行一个函数时,可以使用输入参数的值,但我在PowerShell中,参数有的是必选,有的是可选,那么我们怎么知道用户真实的输入了哪些参数呢? 在PowerShell函数中,有一个全局变量$PSBoundParameters,它是一个Hash表,里面保存了所有的输入参数和输入参数的值.通过输出这个变量,我们就可以看到所有的输入

  • python使用wmi模块获取windows下的系统信息 监控系统

    Python用WMI模块获取Windows系统的硬件信息:硬盘分区.使用情况,内存大小,CPU型号,当前运行的进程,自启动程序及位置,系统的版本等信息. 本文实例讲述了python使用wmi模块获取windows下的系统信息 监控系统 #!/usr/bin/env python # -*- coding: utf- -*- #http://www.cnblogs.com/liu-ke/ import wmi import os import sys import platform import

  • python使用wmi模块获取windows下硬盘信息的方法

    本文实例讲述了python使用wmi模块获取windows下硬盘信息的方法.分享给大家供大家参考.具体实现方法如下: # -*- coding: utf-8 -*- #import ######################################################################## import os, sys import time import wmi ################################################

  • Python获取Windows或Linux主机名称通用函数分享

    通过python的os模块获取windows或者linux主机名的通用函数. 复制代码 代码如下: #!/usr/bin/env python  #coding=utf-8    import os    def hostname():          sys = os.name            if sys == 'nt':                  hostname = os.getenv('computername')                  return hos

  • PowerShell小技巧之获取Windows系统密码Hash

    当你拿到了系统控制权之后如何才能更长的时间内控制已经拿到这台机器呢?作为白帽子,已经在对手防线上撕开一个口子,如果你需要进一步扩大战果,你首先需要做的就是潜伏下来,收集更多的信息便于你判断,便于有更大的收获.用什么方法才能有尽可能高的权限,同时能更有效的隐藏自己,是留webshell,留后门,种木马还是Rootkit?webshell,哪怕是一句话木马都很容易被管理员清除,放了木马,也容易被有经验的管理员查出,不管是早期自己创建进程,进程被干掉就完了,还是注入进程的木马,或者是以服务自启动的木马

  • java网络编程之识别示例 获取主机网络接口列表

    获取主机地址信息 在Java中我们使用InetAddress类来代表目标网络地址,包括主机名和数字类型的地址信息,并且InetAddress的实例是不可变的,每个实例始终指向一个地址.InetAddress类包含两个子类,分别对应两个IP地址的版本: 复制代码 代码如下: Inet4AddressInet6Address 我们通过前面的笔记可以知道:IP地址实际上是分配给主机与网络之间的连接,而不是主机本身,NetworkInterface类提供了访问主机所有接口的信息的功能.下面我们通过一个简

  • c#获取windows桌面背景代码示例

    复制代码 代码如下: #region 获取windows桌面背景        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]        public static extern int SystemParametersInfo(int uAction, int uP

  • Android获取分享应用列表详解及实例

    Android获取分享应用列表详解及实例 如果在应用的AndroidManifest.xml中含有 ACTION_SEND 属性,那就证明该应用可以供第三方应用进行调用分享,那怎么获取函数该属性的分享列表了,这对我们做应用的非常有用:最近在做该功能,自己也做了下自定义的分享列表,用PopupWindow的方式弹出. 1.布局: popup_share.xml <?xml version="1.0" encoding="utf-8"?> <Linea

随机推荐