最近公司增加了一些UVC协议的摄像头接口,下面是一些资料整理(感谢项目组内志宇同学的耐心指导)
摄像头插件为AForge,所以IKsControl接口对象AForge.FilterInfo。(IKsControl接口:提供了控制 KS 过滤器或 KS 引脚的用户模式方法。参考:https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/ks-h-typedef-reference)
/// <summary>
/// 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;
}
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent
我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.