最近公司增加了一些UVC協議的攝像頭介面,下麵是一些資料整理(感謝項目組內志宇同學的耐心指導) 攝像頭插件為AForge,所以IKsControl介面對象AForge.FilterInfo。(IKsControl介面:提供了控制 KS 過濾器或 KS 引腳的用戶模式方法。參考:https://lea ...
最近公司增加了一些UVC協議的攝像頭介面,下麵是一些資料整理(感謝項目組內志宇同學的耐心指導)
攝像頭插件為AForge,所以IKsControl介面對象AForge.FilterInfo。(IKsControl介面:提供了控制 KS 過濾器或 KS 引腳的用戶模式方法。參考:https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/ks-h-typedef-reference)
/// <summary> /// VC01 8K 攝像頭 UVC協議擴展介面 /// </summary> public class Vc01UvcExtension { /// <summary> /// 指定標識內核流方法集的 GUID。 /// </summary> private readonly Guid _ksMethodSetGuid = new("A29E7641-DE04-47E3-8B2B-F4341AFF003B"); private const string Vc01CameraName = "VC01"; private IKsControl _pControl; /// <summary> /// 初始化UVC協議擴展介面 /// </summary> /// <param name="cameraName">攝像頭名稱</param> public string Init(string cameraName = "") { var cameraInfos = CameraDevicesManager.GetCameraInfos(); if (cameraInfos.Count == 0) { return "未接入攝像頭"; } if (string.IsNullOrWhiteSpace(cameraName)) { cameraName = Vc01CameraName; } var vc01CameraInfo = cameraInfos.FirstOrDefault(cameraInfo => cameraInfo.Name.ToUpper().Contains(cameraName)); if (vc01CameraInfo == null || string.IsNullOrWhiteSpace(vc01CameraInfo.Identity)) { return "未接入8K攝像頭"; } _pControl = FilterInfo.CreateFilter(vc01CameraInfo.Identity) as IKsControl; return _pControl == null ? "轉換IKsControl介面失敗" : ""; } /// <summary> /// 獲取UVC擴展屬性 /// </summary> /// <param name="type"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public DvbResult<T> GetUvcExtensionProperty<T>(int type) where T : struct { var ksProperty = new KsMethod(_ksMethodSetGuid, type, (int)(KsPropertyTypeEnum.KsPropertyTypeGet | KsPropertyTypeEnum.KsPropertyTypeTopology)); var nod = new KspNode { Property = ksProperty, NodeId = 2, Reserved = 0 }; var dvbResult = new DvbResult<T>(); var dataPro = Marshal.AllocHGlobal(Marshal.SizeOf(dvbResult.Data)); var dataSize = Marshal.SizeOf(dvbResult.Data); var dwReturned = 0; try { var hr = _pControl.KsProperty(ref nod.Property, Marshal.SizeOf(nod), dataPro, dataSize, ref dwReturned); if (hr != 0 || dwReturned != dataSize) return dvbResult; dvbResult.Data = (T)Marshal.PtrToStructure(dataPro, typeof(T)); dvbResult.Result = 0; return dvbResult; } finally { Marshal.FreeHGlobal(dataPro); } } /// <summary> /// 設置UVC擴展屬性 /// </summary> /// <param name="type"></param> /// <param name="data"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public DvbResult SetUvcExtensionProperty<T>(int type, T data) where T : struct { var ksProperty = new KsMethod(_ksMethodSetGuid, type, (int)(KsPropertyTypeEnum.KsPropertyTypeSet | KsPropertyTypeEnum.KsPropertyTypeTopology)); var nod = new KspNode { Property = ksProperty, NodeId = 2, Reserved = 0 }; var dvbResult = new DvbResult(); var dataPro = Marshal.AllocHGlobal(Marshal.SizeOf(data)); var dataSize = Marshal.SizeOf(data); var dwReturned = 0; try { Marshal.StructureToPtr(data, dataPro, true); var hr = _pControl.KsProperty(ref nod.Property, Marshal.SizeOf(nod), dataPro, dataSize, ref dwReturned); if (hr != 0) return dvbResult; dvbResult.Result = 0; return dvbResult; } finally { Marshal.FreeHGlobal(dataPro); } } }
/// <summary> /// KsProperty 請求類型 /// </summary> [Flags] public enum KsPropertyTypeEnum { /// <summary> /// 傳遞的屬性是KSP_NODE類型,其中 NodeId 表示拓撲節點的數字 ID。不要單獨設置此標誌;相反,將其與該表中的其他標誌進行或運算。 /// </summary> KsPropertyTypeTopology = 0x10000000, /// <summary> /// 檢索指定屬性項的值。 /// </summary> KsPropertyTypeGet = 0x00000001, /// <summary> /// 設置指定屬性項的值。 /// </summary> KsPropertyTypeSet = 0x00000002, }
/// <summary> /// IKsControl介面提供了控制 KS 過濾器或 KS 引腳的用戶模式方法。(參考c語言的Ks.h) /// </summary> [ComImport, SuppressUnmanagedCodeSecurity, Guid("28F54685-06FD-11D2-B27A-00A0C9223196"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IKsControl { /// <summary> /// KsProperty方法設置屬性或檢索屬性信息,以及屬性集上可用的任何其他定義的支持操作。 /// </summary> /// <param name="property">指向描述屬性和屬性請求的請求類型的結構的指針。此結構必須是KSPROPERTY或包含KSPROPERTY結構作為其第一個成員的結構。該成員可以指向的結構示例是KSPROPERTY_VIDEOPROCAMP_S結構。</param> /// <param name="propertyLength">Property處緩衝區的大小(以位元組為單位)。</param> /// <param name="propertyData">指向包含 KSPROPERTY_TYPE_SET、KSPROPERTY_TYPE_UNSERIALIZESET 或 KSPROPERTY_TYPE_UNSERIALIZERAW 操作的數據的緩衝區的指針,或接收所有其他操作的數據的緩衝區空間。</param> /// <param name="dataLength">PropertyData中緩衝區的大小(以位元組為單位)。</param> /// <param name="bytesReturned">指向一個變數的指針,該變數接收KsProperty存儲在PropertyData緩衝區中的數據的大小(以位元組為單位)。如果沒有存儲數據,則大小為零。</param> /// <returns></returns> [PreserveSig] int KsProperty( [In] ref KsMethod property, [In] int propertyLength, [In, Out] IntPtr propertyData, [In] int dataLength, [In, Out] ref int bytesReturned ); /// <summary> /// KsMethod方法向 KS 對象發送一個方法,以及方法集上可用的任何其他定義的支持操作。 /// </summary> /// <param name="method">指向描述方法和方法請求的請求類型的KSMETHOD結構的指針。</param> /// <param name="methodLength">Method處緩衝區的大小(以位元組為單位)。</param> /// <param name="methodData">指向包含用於 KSMETHOD_TYPE_SEND 操作的數據和緩衝區空間的緩衝區,或用於接收所有其他操作的數據的緩衝區空間的指針。</param> /// <param name="dataLength">MethodData緩衝區的大小(以位元組為單位)。</param> /// <param name="bytesReturned">指向一個變數的指針,該變數接收KsMethod存儲在MethodData緩衝區中的數據的大小(以位元組為單位)。</param> /// <returns></returns> [PreserveSig] int KsMethod( [In] ref KsMethod method, [In] int methodLength, [In, Out] IntPtr methodData, [In] int dataLength, [In, Out] ref int bytesReturned ); /// <summary> /// KsEvent方法啟用或禁用事件,以及事件集上可用的任何其他定義的支持操作。 /// </summary> /// <param name="method">指向描述事件的KSEVENT結構的指針以啟用該事件,為NULL以禁用該事件。</param> /// <param name="eventLength">啟用事件時事件緩衝區的大小(以位元組為單位),禁用事件時為零。</param> /// <param name="eventData">指向包含事件數據和接收事件數據的緩衝區空間的KSEVENTDATA結構的指針。</param> /// <param name="dataLength">EventData中緩衝區的大小(以位元組為單位)。</param> /// <param name="bytesReturned">指向一個變數的指針,該變數接收KsEvent存儲在EventData緩衝區中的數據的大小(以位元組為單位)。</param> /// <returns></returns> [PreserveSig] int KsEvent( [In, Optional] ref KsMethod method, [In] int eventLength, [In, Out] IntPtr eventData, [In] int dataLength, [In, Out] ref int bytesReturned ); } /// <summary> /// 結構指定方法集中的單個內核流方法。 /// </summary> public struct KsMethod { /// <summary> /// 指定標識內核流方法集的 GUID。 /// </summary> public Guid Set; /// <summary> /// 指定方法集的成員。 /// </summary> public int Id; /// <summary> /// /// </summary> public int Flags; /// <summary> /// 指定請求類型。 /// </summary> /// <param name="set"></param> /// <param name="id"></param> /// <param name="flags"></param> public KsMethod(Guid set, int id, int flags) { Set = set; Id = id; Flags = flags; } } /// <summary> /// /// </summary> public struct KspNode { /// <summary> /// /// </summary> public KsMethod Property; /// <summary> /// /// </summary> public Int32 NodeId; /// <summary> /// /// </summary> public Int32 Reserved; }
/// <summary> /// UVC擴展介面返回結果 /// </summary> public class DvbResult<T> : DvbResult where T : struct { /// <summary> /// 返回欄位結果對象 /// </summary> public T Data { get; set; } = new T(); } /// <summary> /// UVC擴展介面返回結果 /// </summary> public class DvbResult { /// <summary> /// 返回結果 /// </summary> public int Result { get; set; } = -1; }
_pControl.KsProperty(ref nod.Property, Marshal.SizeOf(nod), dataPro, dataSize, ref dwReturned);
(T)Marshal.PtrToStructure(dataPro, typeof(T));
對於返回結果對象類型,經常會出現匹配不上,獲取給的位元組大小對應不上,導致獲取的數據不對。所以最好統一使用byte類型或者byte[]類型獲取,然後進一步轉化成需要的類型。
例如:
public struct RectangleAreaDvbData { public RectangleAreaDvbData(byte[] reserve) { Reserve = reserve; } [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] Reserve; }