C#?使用com獲取Windows攝像頭列表
前言
想使用ffmpeg打開攝像頭,需要輸入攝像頭的名稱,而ffmpeg本身的枚舉攝像頭列表功能不是接口
,所以需要用其他方式獲取到設(shè)備列表。C++獲取視頻設(shè)備列表的方法有不少,但C#獲取視頻設(shè)備列表的方法網(wǎng)上提供的解決方案基本都是依賴第三方庫(kù)的,為了獲取視頻設(shè)備列表而引入一整個(gè)視頻庫(kù)實(shí)在是不太必要。經(jīng)過思考,Windows的directshow和mediafudation都是基于com的,而且C#對(duì)com的支持是很好的,基于上述兩點(diǎn)我們完全可以在C#中直接調(diào)用com。
一、定義com接口
我們使用directshow獲取視頻設(shè)備列表,由于com的跨語(yǔ)言特性,完全可以直接在C#中調(diào)用,而不用通過C++封裝一層dll給C#使用。我們首先定義需要的com對(duì)象接口。
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); }
二、枚舉設(shè)備
與directshow流程一樣,調(diào)用com枚舉設(shè)備即可,本文只展示獲取設(shè)備名稱(FriendlyName),獲取其他屬性可以參照c++調(diào)用directshow的實(shí)現(xiàn)。
/// <summary> /// 枚舉視頻設(shè)備 /// </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> /// 獲取設(shè)備名稱 /// </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> /// 枚舉視頻設(shè)備 /// </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> /// 獲取設(shè)備名稱 /// </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; //枚舉設(shè)備 foreach (var i in EnumDevices.Devices) { //打印設(shè)備名稱 Console.WriteLine(i); }
效果:
總結(jié)
以上就是今天要講的內(nèi)容,本文介紹了C#直接調(diào)用com獲取視頻設(shè)備列表的方法,只要知道了com的一些基本原理以及c#和com的關(guān)系,很容易就能實(shí)現(xiàn)c#直接使用directshow的功能,第三方的庫(kù)也是做了類似的工作,定義了完整的directshow的接口,只是筆者使用的環(huán)境中只需要枚舉視頻設(shè)備列表,不需要其他功能,引入完整的directshow接口有點(diǎn)大材小用,所以還不如自己定義幾個(gè)必要的接口來的實(shí)在。
到此這篇關(guān)于C# 使用com獲取Windows攝像頭列表的文章就介紹到這了,更多相關(guān)C# 獲取Windows攝像頭列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中Hashtable和Dictionary的區(qū)別與用法示例
由于 Hashtable 和 Dictionary 同時(shí)存在, 在使用場(chǎng)景上必然存在選擇性, 并不任何時(shí)刻都能相互替代。所以這篇文章主要給大家介紹了關(guān)于C#中Hashtable和Dictionary區(qū)別的相關(guān)資料,需要的朋友可以參考下2021-05-05C#語(yǔ)法相比其它語(yǔ)言比較獨(dú)特的地方(一)
這篇文章主要介紹了C#語(yǔ)法相比其它語(yǔ)言比較獨(dú)特的地方(一),本文講解了switch語(yǔ)句可以用來測(cè)試string型的對(duì)象、多維數(shù)組、foreach語(yǔ)句、索引器和Property等內(nèi)容,需要的朋友可以參考下2015-04-04C#?Random類隨機(jī)函數(shù)實(shí)例詳解
這篇文章主要為大家介紹了C#?Random類隨機(jī)函數(shù)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08C#實(shí)現(xiàn)在兩個(gè)數(shù)字之間生成隨機(jī)數(shù)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)在兩個(gè)數(shù)字之間生成隨機(jī)數(shù)的方法,在一些特殊場(chǎng)景會(huì)用到哦,需要的朋友可以參考下2014-08-08Unity使用LineRender實(shí)現(xiàn)簽名效果
這篇文章主要為大家詳細(xì)介紹了Unity使用LineRender實(shí)現(xiàn)簽名效果,制作簽名功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10C#之Windows自帶打印功能的實(shí)現(xiàn)
這篇文章主要介紹了C#之Windows自帶打印功能的實(shí)現(xiàn)方式,具有很好的價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06