UVC摄像头技术笔记
+ -

UVC PTZ和扩展单元XU的过滤与分发调试笔记

2021-08-12 637 0

在写这篇文章之前,我得首先感谢微软,感谢你的不严格,让我可以有空子可钻,不至于太过狼狈…
记得看过一句话,开局一张图,内容全告编。我多么希望自己在UVC摄像头的调试过程中也可以瞎编乱造,这样不至于身心疲惫。至少保持着愉快的心情,吹吹牛,也是一件很开心的事。

今日有一个需求,对UVC摄像头的请求进行过滤和重新分发。主要的内容是对摄像头的数据帧格式进行过滤篡改和对UVC摄像头如PTZ和扩展单元的特定类请求进行过部分的过滤和重新分发。
注意这里的部分两个字,比如说对UVC扩展单元支持的10个选择子,5个选择子要直接转发给固件,另外5个要截获交给应用层来处理(其实说成对扩展单元的选择子扩展也许更好)。

我准备了两个方案:

  • 第一是自己重新实现USBCCGP.SYS功能,使用自己编写的驱动代替微软的USBCCGP.SYS,这样可以在该驱动中分析固件的配置描述符,分别虚拟其相关的设备。如UVC摄像头,HID设备和UAC设备。
  • 第二个也是重新实现USBCCGP.SYS功能,不过对大部分请求进行重新转发,只对自己感兴趣的请求进行过滤转发。但是由于数据是需要在应用层转一圈再回来,所以得自己做一些关联IRP请求。不过这个本人并没有实现过,也只是在reactos源代码中看到过(http://www.pnpon.com/article/detail-175.html )。

讲道理,按理来说第二种方法实现起来可能比较简单,但实际上我选的是第一种方案。
第一种方案

为什么选择第一种方案呢?原理是比较简单的,防止需求的变化。因为作为一各程序员,最怕的是需求的变化,最恐怖的是发现在自己以前的方案不能满足新的需求或改起来特别复杂。自己都不一定能改正确。

相机终端PTZ请求

在通过虚拟各种设备成功后,编写其数据的交互过程。在UVC的特定类请求时,卡住了…

由于要对PTZ功能进行过滤处理,首先得将上层发给驱动设备的特定为请求进行截获转发。截获到还可以,问题就出现在了转发。由于我们是不同的设备,且自己虚拟的相机终端单元信息和固件的中的不一致,没办法为了少写转化代码。自己尽可能将如ID等拓扑信息与固件保持一致。在第一次下发请求时,出现了问题:
抓包信息如下:

  13.0            CTL    a1 86 00 0b  00 01 01 00    CLASS      
  13.0            USTS   c0000004                    stall pid  
  13.0            CTL    a1 86 00 0c  00 01 01 00    CLASS      
  13.0            USTS   c0000004                    stall pid  
  13.0            CTL    a1 86 00 0d  00 01 01 00    CLASS      
  13.0            USTS   c0000004                    stall pid  
  13.0            CTL    a1 86 00 0e  00 01 01 00    CLASS      
  13.0            USTS   c0000004                    stall pid  
  13.0            CTL    21 0a 00 00  00 00 00 00    SET IDLE   
  13.0            USTS   c0000004                    stall pid

PID错误,关于PID的内容见:http://www.usbzh.com/article/detail-73.html
当时我就懵了,这玩意还到了USB协议层,幸好本人与正确的进行抓包对比,机智地发现由于接口ID的不同(自己虚拟是从0开始的,但在固件中0是HID设备,从1接口开发UVC).

  31.0            CTL    a1 86 00 0b  01 01 01 00  GET INFO 
  31.0         1  IN     13                        .        
  31.0            CTL    a1 82 00 0b  01 01 02 00  GET MIN  
  31.0         2  IN     00 00                     ..       
  31.0            CTL    a1 83 00 0b  01 01 02 00  GET MAX  
  31.0         2  IN     d0 02                     ..       
  31.0            CTL    a1 84 00 0b  01 01 02 00  GET RES  
  31.0         2  IN     01 00                     ..       
  31.0            CTL    a1 87 00 0b  01 01 02 00  GET DEF  
  31.0         2  IN     00 00                     ..       
  31.0            CTL    a1 86 00 0c  01 01 01 00  GET INFO 
  31.0         1  IN     03                        .        
  31.0            CTL    a1 82 00 0c  01 01 03 00  GET MIN  
  31.0         3  IN     00 00 00                  ...      
  31.0            CTL    a1 83 00 0c  01 01 03 00  GET MAX  
  31.0         3  IN     00 00 01                  ...      
  31.0            CTL    a1 84 00 0c  01 01 03 00  GET RES  
  31.0         3  IN     00 00 01                  ...      
  31.0            CTL    a1 87 00 0c  01 01 03 00  GET DEF  
  31.0         3  IN     00 00 01                  ...

所以对于相机终端的特定类请求(http://www.usbzh.com/article/detail-47.html ),我是这样做的:

if (Urb->UrbControlVendorClassRequest.Index == 0x0100)
{
    Urb->UrbControlVendorClassRequest.Index += 0x01;
    IoSkipCurrentIrpStackLocation(Irp);
    NTSTATUS Status = IoCallDriver(deviceExtension->PhysicalDevice, Irp);
    Urb->UrbControlVendorClassRequest.Index -= 0x01;
    return Status;
}

扩展单元请求

当实现了相机终端的请求,扩展单元还不是一件直分简单的事…
可当我加上之后,发现应用层的有问题了,各种卡死。。。甚至应用层崩掉
就是因为发了这些特定类请求PTZ和扩展单元请求才出的问题。。
当我又改回去不支持扩展单元时,只有相机的PTZ时,又好了。。。。
这…..
难道我的代码有问题,有耦合,难道固件的扩展单元和PTZ有偶合….
当出现这种问题时,也现了大量的IRP cancel,这难道是IRP没有处理的问题,抓包发现IRP有时PENDING…

不显示IN包的抓包信息:

 15.0            CTL    a1 85 00 02  01 0b 02 00   CLASS     
 15.0            CTL    a1 81 00 02  01 0b 01 00   CLASS     
 15.0            CTL    a1 81 00 0e  01 01 04 00   CLASS     
 15.0            CTL    a1 85 00 02  01 0b 02 00   CLASS     
 15.0            CTL    a1 81 00 0e  01 01 04 00   CLASS     
 15.0            USTS   c0000004                   stall pid 
 15.0            USTS   c0000004                   stall pid

各种偿试了…
突然想到一个问题,就是当自己下发IRP前,将Index += 0x01;然后调用IoCallDriver,但是调用完成后又将Index -= 0x01了,但如果遇到pending的状态,由于自己将Index又减回去了,所以有可能是当需要处理的时候,Index不正确了所导致的问题…
为了验证这个这问题,本人将代码这样改了一下:

if (Urb->UrbControlVendorClassRequest.Index == 0x0100)
{
    Urb->UrbControlVendorClassRequest.Index |= 0x01;
    IoSkipCurrentIrpStackLocation(Irp);
    NTSTATUS Status = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
//    Urb->UrbControlVendorClassRequest.Index -= 0x01;
    return Status;
}
else if (Urb->UrbControlVendorClassRequest.Index == 0x0B00) //
{
    Urb->UrbControlVendorClassRequest.Index |= 0x01;
    IoSkipCurrentIrpStackLocation(Irp);
    NTSTATUS Status = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
    if (Status == STATUS_PENDING)
    {
    //    KdBreakPoint();
    }
//    Urb->UrbControlVendorClassRequest.Index -= 0x01;
    return Status;
}

结果是:还真是这个问题…
下来其实最好的方法是对该IRP设置完成例程,在完成例程中修改回去。但是一般当IRP完成后,不是会校验这类输入参数的,所以好像这样也没啥问题…
偷个懒…

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

UVC 扩展单元描述符
扩展单元描述符允许硬件设计者定义任意一组控制接口,使类驱动程序可以在设备与供应商提供的主机软件之间进行通讯控制。扩展单元描述符ID由bUnitID字段中的值唯一标识描述符。同一视频功能内的任何其他单元或终端不得具有相同的功能ID。guidExtensionCode字段包含特定于供应商的代码,该代......
UVC摄像头扩展单元功能的开发步骤是什么?
写在扩展单元的题外话本人在开发支持UVC扩展单元的directShow应用时,必现并不需要注册接口,只需要在其源过滤器参照后续的代码枚举相关的接口如IKsControl,IKsTopologyInfo定位到指定的扩展单元接口后,直接使用其对应的IKsControl::KsProperty即可实现扩展......
UVC 扩展单元控制请求
扩展单元控制请求设置或读取扩展单元内的视频控件.bmRequestTypebRequestwValue(2)wIndexwLengthData00100001SET_CUR选择子扩展单元ID参数长度参数块bmRequestTypebRequestwValue(2)wIndexwLengthData1......
关于UVC摄像头指示灯的调试过程总结
最近遇到了一个很是奇怪的UVC摄像头指示灯问题,现象如下:上层应用是一个会议系统软件,当需要进行会议时,点击会议按钮添加会议。这时应用软件打开摄像头,并开始与服务器进行网络连接。当然由于摄像头的打开,摄像头指示灯点亮。上层应用软件与服务器连接后,进行会议界面。这时突然摄像头指示灯熄灭,但会议正常,摄......
【UVC调试笔记】第一个GET CUR请求产生babble detected的原因排查
【前言】开通blog的目的有两个:一是记录UVC调试过程中遇到的问题和解决方案,方便自己review二是给广大开发者提供一些解决问题的思路故障现象:枚举完以后,打开videocap,从bushoud上抓包,可以看出第一个GET CUR会产生一个babble detected的error排查过程:通......
关于UVC PTZ功能
PTZ功能即缩放(Z),左右移动(P)和上下移动(T)功能,定义在相机终端描述符里面,具体可以查看终端描述符那一章。最近在给模块端添加这个功能的时候折腾了一段时间,zoom功能主要根据SET_CUR请求值对画面做相应处理就好,这里说下PT功能,PT功能需要注意下面几个点:1.PT功能命令的数据长度......
USB设备的调试笔记-奇怪枚举失败问题
自己搞了一个USB 触摸屏的驱动,通过对系统的USB触摸屏设备进行更改,这样可以在自己的驱动中过滤来自触摸屏的数据。在不加自定义驱动的情况下,设备管理器树关系如下:USB输入设备USB触摸屏设备而加上自己的设备驱动后,设备管理器树关系如下:自己的驱动程序USB输入设备USB触摸屏设备......
V4L2访问摄像头扩展单元命令
我们可以通过IOCTL访问扩展单元,调用方法如下:ioctl(fd, UVCIOC_CTRL_QUERY, struct uvc_xu_control_query *);访问不同的扩展命令只需要修改uvc_xu_control_query 结构体里面内容即可。uvc_xu_control_qu......
用XU打造UVC命令行调试工具
在给客户交付UVC固件之后,有时客户会反馈问题,需要客户查看固件的打印信息或者执行一些命令辅助定位问题。如果有一个工具可以通过USB线连接到设备,直接在电脑上查看打印信息,执行命令就好了。有想法就要行动起来,行动才能解决问题。目前该功能已经实现了,说一下实现的方法吧。上位机OS Windows设......
Windows虚拟UAC麦克风增加特性单元的开发调试笔记
昨晚突然接到通知,需要增加对UAC麦克风设备音量增益的控制。我努力地回忆了去年12月份自己粗略地整理的UAC规范,发布于http://www.usbzh.com/article/forum-1.html想着今天完成应该是美好的周五,会心满意足地完成工作,然后美美地打卡下班。可没想到就这么一个简单的......
UVC摄像头扩展单元调试工具-临江仙版
UVC摄像头的开发者为了实现一些私有定制协议的通讯,通常使用UVC自带的扩展单元来实现。通常是自定义一个扩展单元,再定义一些相应的选择子,然后再通过特定类请求实现与固件的通讯。 本站现提供一个Windows环境下,使用DirectShow开发的UVC扩展单元调试工具.UVC摄像头扩展单元工具来自......
UVC PTZ扩展单元XU的过滤与分发调试笔记
在写这篇文章之前,我得首先感谢微软,感谢你的不严格,让我可以有空子可钻,不至于太过狼狈…记得看过一句话,开局一张图,内容全告编。我多么希望自己在UVC摄像头的调试过程中也可以瞎编乱造,这样不至于身心疲惫。至少保持着愉快的心情,吹吹牛,也是一件很开心的事。今日有一个需求,对UVC摄像头的请求进行......
UVC摄像头驱动装调试总结
前几天发表了一篇文章 UVC PTZ扩展单元的过滤与分发调试笔记,原文见: http://www.usbzh.com/article/detail-517.html ,本来想着应该没啥问题了,可没想到上周五在实际测试过程中,还是出现了问题:经过长时间的UVC摄像头工作,突然驱动显示了大量数据包错误......
U盘枚举失败-该设备无法启动(GET_MAX_LUN请求)
群里有人用STM32搞了一个U盘,但是U盘在插入电脑后在设备管理器是枚举失败。我让他看一下设备状态:又是熟悉的错误码10,表示设备启动失败。设备的启动失败,一般在设备获取描述符获取之后,初始会失败,我之前在弄USB虚拟鼠标的时候也遇到此类情况。不过由于这个设备是U盘,本人还没有研究USB存储协议,只......
windows上面通过dshow接口访问uvc摄像头扩展单元,只能访问0x01-0x1F命令问题
最近在给客户做一个修改摄像头数据的工具,在通过dshow接口发送扩展命令的时候发现0x01-0x1F命令都可以发送成功,0x20及以上定义的命令都发送失败,并且返回错误码0x80070490。谷歌百度查了很久终于在windows官网文档中找到了答案,原来是USB 视频类驱动程序对UVC扩展单元实现......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!