Showing Posts From
Usb
- 20 May, 2022
《Microsoft Skype for Business H.264 Video Encoder Specification》学习笔记
对于要通过Mircosoft的Teams或者Skype For Business认证的视频会议系统,要使用H.264来进行图像传输的情况,就需要对图像视频压缩所使用的H.264编码器进行Teams和Skype For Business的认证,才能打上对应的认证Logo。而这个对于H.264编码器进行认证的规范指导文件就是《Microsoft Skype for Business H.264 Video Encoder Specification》,文档编号为H105958。 - 注意:这个规范文件和认证流程针对的是单纯的H.264编码器,而不是整个摄像头系统。所有的指标、功能性要求以及进行测试和验证的流程,都是针对链路上所使用的H.264编码器。 在该规范文档中,把要通过Teams和Skype For Business认证的H.264编码器分为以下三种情况: - Category 1:USB Camera内部包含的H.264编码器; - Category 2:笔记本、平板电脑和手机中集成的摄像头内部自带的H.264编码器; - Category 3:通用的H.264硬件编码器。 如同其他所有的Teams认证的规范文档,通过Teams的H.264 Encoder的认证,同样存在Standard和Premium两种认证规格,后者的指标和功能要求更加严格一些。而只要通过Standard的指标要求,就可以打上Teams的认证Logo。 无论对于Standard还是Premium类型的认证而言,对于H.264编码器的基本要求就是能够支持UCConfig Mode 1,也就是需要H.264编码器至少能够支持SVC的Temporal Layer。所以那些不支持SVC模式的编码器就可以洗洗睡了:(4.1)Encoders must support UCConfig Mode 1 and the corresponding requirements outlined below in order to participate in the Skype for Business Logo program。另外要通过这个认证,需要编码器支持的最大分辨率至少要是1080P。 - UCConfig Mode 1的定义:SVC temporal scalability with hierarchical P with Simulcast (number of simulcast streams >= 1). H.264编码器进行Teams认证的测试流程 微软为了进行这个H.264编码器的一致性测试,专门提供了一个测试工具:Microsoft Skype Video Encoding Conformance (MLVEC) toolkit。这个工具主要分为两个部分:H.264的码流产生器(BitStream Generator)和码流一致性验证器(Conformance Verifier)。 !Untitled.png BitStream Generator: - BitStream Generator的输入有两个:一个是Skype Business进行测试认证的录像片段(不同分辨率、不同场景),也就是上面的Skype Logo Clips;另外一个就是Config Scripts,在其中定义了测试编码器需要设置编码器的参数和工作流程,编码器按照该脚本的命令进行工作。 - 对于USB Camera而言,要进行这个测试肯定就没那么容易了,因为没有办法很容易的把这些认证录像片段方便的送入USB Camera的编码器中进行编码。所以针对这个问题,文档中明确规定,对于这类USB Camera的认证而言,Camera的生产厂家,要自己想办法(例如通过一个专门的开发板)把测试录像片段送入Camera内部的编码器,并按照要求自行完成码流的生成。(5.3)Tethered USB webcams usually don’t have a possibility to feed the pre-recorded clips into the hardware encoder. Due to this we are currently requiring these tests to be run on a development kit which allows feeding the pre-recorded clips into the encoder. - BitStream Generator的输出就是各种不同测试参数状态下的码流文件,以及运行中所产生的的log。 Conformance Verifier: - Conformance Verifier读取BitStream Generator所产生的码率文件和运行log,基于其内部的功能性分析工具进行判断,看编码器所产生的的码率及其运行过程的指标性数据,是否符合Standard和Premium的标准,给出最终的测试判定报告。 H.264编码器认证需求 - Aspect ratios and image resolutions:对于编码器能够支持的图像长宽比和分辨率的要求,三个Category的编码器有不同的长宽比和分辨率编码测试要求; !Untitled.png !Untitled.png - Frame rate:不同分辨率下的编码帧率要求 !Untitled.png - Video preview:对于Preview视频的输出需求。内置H.264编码器的USB Camera需要能够同时提供一路小分辨率(640x480或者640x360 30fps)的YUV图像作为Preview的功能。 - 不是很清楚对于USB UVC camere而言,如何能够在传输H.264 main Streaming的同时,把这个YUV的preview video也传过去?具体应该怎么做? - Encoder latency:编码延迟指标,对于编码进行编码导致的Pipeline延迟不应该影响帧率,或者造成图像在传输和解码回放时出现抖动。 - Dynamic resolution change:编码器应该能够支持在Pipelien的编码器正常运行的过程中,动态的调整分辨率。且有一定的调整延迟指标。 - Dynamic profile/level change:编码器应该能够支持在Pipelien的编码器正常运行的过程中,根据具体情况动态调整编码的profile和level的设置。且有一定的调整延迟指标。 - Dynamic add/remove temporal layers:对于支持SVC扩展的编码器而言,能够在编码过程中,动态的增加或者删除帧率扩展层(temporal layer),且有一定的调整延迟指标。 - Bitstream Conformance:这部分对于编码器在各种模式下输出的码率的设置有明确的的要求。 - Quality Conformance:对编码器产生的码率,经过解压缩以后的图像质量有明确的要求。 其他 - 对于USB Camera而言,如果要通过Teams的这个H.264 Video Encoder认证,需要在USB Camera中支持UVC1.5规范:实际上UVC1.1已经可以通过Frame Based的方式来支持H.264的Payload了,但是把H.264当成一种独立的payload来进行支持的话,只能使用UVC1.5规范。不过UVC1.5的兼容性不大好,只有在Win8及其以后的系统中才能够支持。 参考资料: - Microsoft Skype for Business H.264 Video Encoder Specification,H105958 - Unified Communication Specification for H.264 AVC and SVC UCConfig Modes, V1.1
- 24 Mar, 2022
基于Linux UAC gadget驱动实现Audio Control处理-Kernel层GET
基于对SigmaStar Webcam方案源代码的学习,通过三篇文章的篇幅,整体总结了SigmaStar提供的在基于Linux kernel的UAC gadget设备中增加audio control控制功能的完整工作流程: 1. 应用层 2. 内核层1-Audio Control Get类命令的处理流程 3. 内核层2-Audio Control Set类命令的处理流程 以下为内核层GET类命令的完整总结。 kernel部分UAC的实现主要用到三个文件:drivers/usb/gadget/function目录下的f_uac1.c和u_audio.c,和drivers/usb/gadget/legacy下的audio.c文件。 Audio control在kernel中的实现流程需要从f_uac1结构的定义开始进行分析: 以上使用Control Set Command字符串标准的这部分就是在Linux标准uac实现的基础上增加的,以提供对audio control功能的支持。 以上数据结构中增加了一个列表定义cs,用于保存该设备可以支持的unit基本的audio control命令队列: - uac规范把audio control command分为多个不同的unit,每个unit中又包含有多个command。所以每次device收到host发出的audio control命令以后,首先要找到这个命令归属于那个unit,然后在这个unit中再找到对应的command进行处理。 - 这里的cs保存的是unit的列表。 在f_uac1.c文件中f_audio_alloc函数的最后通过control_selector_init函数来实现两个队列的初始化,后续在接收到host的audio control命令后需要对这两个队列进行轮询。在下面的例子中,提供了一个包含在Feature Unit中的volume control音量控制功能的例子: 以上初始化中用到的capture_fu_controls和capture_volume_control结构的定义如下: 接下来开始分析Device端接收到Host的Audio Control命令的完整处理流程。 按照UAC规范的定义,Audio Control命令的处理逻辑与UVC的Video Control的处理类似,都是通过在端点0上发送的控制传输类型来进行实现的。 那么在f_uac1.c中,每次Device端收到端点0上发过来的控制传输类型的数据后,自动调用的回调函数是f_audio_setup: 所以对这个f_audio_setup函数执行流程的分析就是整个audio control命令处理的起点所在。 - 首先对控制传输结构数据中包含的BRequestType字段进行解析,针对它的方向(IN还是OUT)、目的类型(端点还是接口)分为四类调用不同的函数进行处理; - 因此audio control命令都是发给audio control interface的,所以对于Set类型的audio control,我们只需要关注audio_set_intf_req;Get类型只需要关注audio_get_intf_req的实现即可。 - audio_set_intf_req和audio_get_intf_req执行完成后,返回这个控制传输后面的data stage要传输的字节数。如果大于0的话,需要再调用usb_ep_queue进行data stage的收发处理。 - 例如对于上面的volume control的例子,GET类型的命令处理上,在这个阶段会把当前的volume value返回给Host;SET类型的命令处理上,则在这个阶段接收Host新设置的volume value数据。 Audio Control Get类型命令的处理接口audio_get_intf_req: - 注意:对于get类audio command的处理,实际上在找到对应的audio command并调用其con->get函数,得到它的当前设置值,并返回以后,整个流程实际上就结束了。这个函数返回后,在f_audio_setup中会把返回的当前设置值通过usb_ep_queue发回给Host。因此在这里注册的这个f_audio_complete回调实际上没有实际作用,根本没有执行有意义的处理流程。f_audio_complete实际上主要应用在Set类型audio control的处理上,可以参考后面对Set类型命令的处理流程。 Get类型命令的实际处理入口实际上就是上面在轮询中找到的con->get函数,也就是generic_get_cmd: - 所以说这个函数实际上只是返回这个audio control中包含的当前设置值而已。那么这个当前设置值在哪儿初始化呢?答案是在前面的control_selector_init中就对所有的audio control的参数初始值进行了初始化。并且在此后收到Set类型命令以后,也会对这个con->data进行赋值,确保其中包含的参数是最新的。 至此,整个Get类型的audio control命令的处理流程就完整的分析完了。需要注意的一点是:所有audio control的当前运行参数都是在内核中进行维护和管理的,因此get类型的命令,直接从内核中就可以得到这些参数并直接返回,不需要到应用层去获取这些数据。
- 24 Mar, 2022
基于Linux UAC gadget驱动实现Audio Control处理-Kernel层SET
基于对SigmaStar Webcam方案源代码的学习,通过三篇文章的篇幅,整体总结了SigmaStar提供的在基于Linux kernel的UAC gadget设备中增加audio control控制功能的完整工作流程: 1. 应用层 2. 内核层1-Audio Control Get类命令的处理流程 3. 内核层2-Audio Control Set类命令的处理流程 以下为内核层SET类命令的完整总结。 延续前面的Get类命令的分析。下面来继续分析Audio Control Set类型命令的处理接口audio_set_intf_req: - 整体的工作逻辑与Get类的处理基本类似。最大的不同就是通过轮询两个队列,找到对应的audio control以后,只是把这个audio control结构体赋值给uac1->set_con,并没有做具体的set操作。这个set操作需要在req->complete上注册的回调函数f_audio_complete中执行。 - 放到f_audio_complete中执行的原因是,set类型的命令需要收到data stage发过来的设置参数,而audio_set_intf_req执行的时候这个data stage还没发过来。所以只能在这里先记下来,然后等整个控制传输结束,这个时候会自动回调req->complete上注册的f_audio_complete函数。因此在f_audio_complete中处理实际的set命令比较合适。 因此Set类型命令的实际处理入口函数就是f_audio_complete: - 可以看到,上面最终执行的set功能仍然是audio control command自己的set函数。这个set函数在对应的audio control结构体的定义中已经设置好。例如可以查看前面的capture_volume_control变量定义的时候给set赋值的处理函数是generic_set_cmd。 generic_set_cmd的分析: - 前面的f_audio_alloc函数中定义了一个schedule work,对应的执行函数是mixer_cmd_work。因此这里的schedule_work(&uac1->cmd_work)实际上就是给kernel的调度器提交了一个执行mixer_cmd_work的执行任务。 通过调度器执行的mixer_cmd_work函数来负责audio control功能在应用层的生效处理,其执行分析如下: g_audio_notify利用linux声卡驱动的ALSA架构来实现与应用层之间的通信。在u_audio.c文件中定义: - 需要注意,上面的g_audio_notify的实现非常简略。实际上只提供了一个volume调整上传应用层的机制,如果需要增加其他audio control的控制,就要在以上代码的基础上增加对应的处理逻辑,可以通过id把不同的命令区分开来,告诉应用层究竟需要对哪个audio control进行控制。 那么问题来了,上面的g_audio->uac->volume_ctl究竟是什么?为什么snd_ctl_notify函数可以向应用层发出volume control变化的通知? 这是因为UAC的实现借助了Linux的ALSA网卡驱动框架。ALSA网卡驱动框架提供了一个kcontrol的机制来实现在应用层和kernel层进行音频参数控制功能。 每个音频参数的设置都对应一个kcontrol结构体,也就是所谓的struct snd_kcontrol,把这个结构体定义并填充好以后,注册到内容中。应用层就可以访问到kernel中注册的所有kcontrol的列表,需要控制哪个参数,就通过对应的kcontrol控制的接口来进行控制即可。 那么对于volume control这个kcontrol而言,其定义及其在kernel中的注册流程如下: - 所以如果还要增加新的audio control的控制类型,就需要像上面的volume control一样,先定义清楚这个新的audio control对应的snd_kcontrol_new结构体,然后调用snd_ctl_add把这个kcontrol注册到内核中。这样后续就可以在g_audio_notify中通过snd_ctl_notify函数向应用层发出audio control command了。
- 23 Mar, 2022
基于Linux UAC gadget驱动实现Audio Control处理-应用层
基于对SigmaStar Webcam方案源代码的学习,通过三篇文章的篇幅,整体总结了SigmaStar提供的在基于Linux kernel的UAC gadget设备中增加audio control控制功能的完整工作流程: 1. 应用层 2. 内核层1-Audio Control Get类命令的处理流程 3. 内核层2-Audio Control Set类命令的处理流程 以下为应用层部分的完整总结。详细解析了SigmaStar SDK中提供的在应用层通过ALSA KControl机制实现audio control命令的通知和功能实现。 Linux USB Gadget中的UAC部分与kernel部分的交互,实际上使用了Linux的ALSA音频驱动框架。这一点有点类似于在UVC Gadget中使用了v4l2摄像头驱动框架一样: - v4l2摄像头框架原本的设计是要实现一个内核中的摄像头驱动,以方便应用层以统一的流程和接口从kenel中读取摄像头的数据;而在UVC中使用v4l2的图像流的走向刚好与原本的v4l2框架相反,是把应用层的图像流通过v4l2机制发到内核,然后由内核调用USB底层驱动发给Host; - 在UAC上使用ALSA音频驱动框架的逻辑也是类似。ALSA原本的设计,是通过ALSA框架定义的标准,从kernel中读取麦克风的数据到应用层,向kernel中写入需要通过喇叭来播放的音频数据,以及通过kcontrol机制实现对音频硬件的控制;UAC中对于ALSA的使用刚好相反,是把应用层整理好的音频数据使用SNDRV_PCM_IOCTL_WRITEI_FRAMES ioctl code写入kernel,然后由kernel调用USB硬件发给Host,以及把USB Host发过来的音频数据通过使用SNDRV_PCM_IOCTL_READI_FRAMES ioctl code读取到应用层,再调用SDK应用层的API把这个声音从喇叭中播放出来,而USB Host所发过来的audio control类的命令则是通过kcontrol机制返回给应用层,由应用层做针对的处理。 应用层部分的实现逻辑 应用层实现audio control的大致流程,与ALSA声卡驱动框架的kcontrol一致: - 调用mixer_open函数打开audio control设备文件,以及通过这个设备文件读取kernel中支持kcontrol列表; - 调用mixer_subscribe_events函数开启内核audio control事件的订阅; - 循环执行: - 调用mixer_wait_event函数等待audio control设备文件是否有新的command通知上来; - 调用mixer_ctl_get_event和mixer_ctl_get_value获取事件详细信息及其参数; - 利用从内核设备文件中读取到的事件和参数,通过SigmaStar SDK应用层的MI_AI_SetVqeVolume接口设置新的音量参数。 mixer_open函数的解析: mixer_subscribe_events mixer_subscribe_events的实现比较简单,实际上就是通过ioctl code SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS开启或者关闭对内核ALSA control事件的订阅; Audio Control消息处理循环结构 - 通过在事件监听和处理循环中,通过mixer_ctl_get_event可以知道哪个audio control的参数发生了变化,然后通过mixer_ctl_get_value函数读取这个audio control在kernel中的当前设置值,然后就可以在应用层调用对应的audio control的功能函数,把Host发过来的audio control功能实现出来。 - 以上例子代码只是实现了一个volume control的例子。如果要增加其他的audio control功能,可以在mixer_ctl_get_value函数中进行判断和识别,究竟是哪个audio control的参数发生了变化,然后对应的在mixer_ctl_get_value函数中读取其内核中的设置值,并在应用层设置功能。
- 18 Mar, 2022
USB接口与端点的概念总结
端点EndPoint 从逻辑上看,端点可以认为是USB device端的FIFO,用于保存Host与Device之间的通信数据。 每个USBdevice上都包含有多个端点,所以可以认为USB device上会并行运行多个独立的FIFO队列,分别用于保存发送给Host或者Device的数据。Host端通过device地址和端点号来对通信数据应该存取的端点FIFO进行定位。 - 所有由Host发送给Device的数据,都会根据device地址和端点号定位要对应的OUT类型端点FIFO,然后把数据保存到FIFO中;等待Device端有空闲时从FIFO中读走。 - 所有由Device发送到Host的数据,都会先放到对应的IN类型端点FIFO中,然后在Host轮询USB总线上的端点数据的时候,使用一个IN Packet从这个FIFO中读走。 所有的USB device都必须有端点0,而且只有这个端点0是双向的,这个端点0用于接收所有的控制和状态类型的请求;其他所有的端点都是单向的,要么为IN,要么为OUT。 - IN和OUT是站在Host的角度来理解,所以尽管端点是device侧的FIFO,从Host发到Device的端点类型是OUT端点,从Device发到Host的端点类型是IN端点。 !Untitled.png 端点描述符 !Untitled.png - bLength,表示这个端点描述符结构体的大小,固定为7; - bDescriptorType,描述符类型,固定为5,表示是端点描述符; - bEndPointAddress:端点的方向以及编号。 - bit0-3为端点编号,因此一个USB Device最多有16个端点; - bit7为端点方向,0表示OUT,1表示IN,均从HOST的角度来作为参照。 - 此外对于控制端点而言,固定使用端点0,并且因为是双向端点,不需要使用bit7作区分; - bmAttributes:端点属性,用于定义这个端点是Control、Bulk、Iso、Interrupt中的哪一个,及其相关的属性信息; - wMaxPacketSize:这个端点一次收发能够处理的数据大小; - bInterval:对Bulk和Control端点没有意义,对于Interrupt和Iso端点,表示多长时间对这个端点进行一次轮询。 - 这里设置的单位并非是时间,而是USB总线收发Frame的个数。因此对于USB2.0高速设备而言,这里的单位是125us。 - Iso类型的端点设置值固定为1,Interrupt类型的端点设置值在1-255之间。 接口Interface 所谓的接口,可以认为是一组端点的集合,用于实现一个标准的独立功能。因此,一个USB设备一般有一个设备描述符,一个或多个(绝大多数情况下只有一个)配置描述符。而每个配置描述符下面可以包含多个接口描述符,每个接口描述符又可以包含有多个端点用于实现某项功能: !Untitled.png 注意:如果一个设备中包含有多个接口,这些接口可以同时并行独立工作,互不干扰。接口描述符中有一个bInterfaceNumber用于区分不同的接口。 接口的Alternative Setting功能 接口可以使用Alternative Setting选项来动态改变接口的配置。 接口描述符专门有一个bAlternateSetting参数指定当前定义的接口描述符是第几个接口的第几个alternative配置。 如果一个接口不需要使能Alternative Setting功能,那么就只需要定义一个接口描述符,并把它的bAlternateSetting设置为0; 如果一个接口使能Alternative Setting功能,就需要按照它需要的Alternative Setting的数量定义多个接口描述符,这些接口描述符的bInterfaceNumber一样,表示都是针对同一个Interface的配置,而每个描述符的bAlternateSetting参数不同,Host可以在运行中对这个Interface选择和设置不同的Alternative Setting。 Alternative Setting功能最典型的应用就是对于包含有Iso类型端点的接口,可以使用Alternative Setting对这个接口设置多个不同的wMaxPacketSize选项,在运行中由Host根据USB总线情况动态选择。例如联想X260笔记本摄像头上读取到的UVC Video Streaming Interace就使用了Iso端点,并通过多个Alternative Setting定义了多个wMaxPacketSize选项: 默认情况下,一个接口的bAlternateSetting=0的描述符选项会被启用。但是Host可以在运行中通过使用Set Interface标准命令来指定某个接口设置其某个已定义的alternative setting。 接口描述符 !Untitled.png - bLength,表示这个接口描述符结构体的大小,固定为9; - bDescriptorType,描述符类型,固定为4,表示是接口描述符; - bInterfaceNumber,接口在配置描述符中的索引; - bAlternateSetting,该接口描述符的alternative setting索引; - bNumEndpoints:这个接口使用的端点数量。注意如果接口用到控制端点的话,这个端点数量不会把控制端点计算在内; - bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol:这三个参数用于指定这个接口实现的标准功能,由USB规范定义; - iInterface:该接口对应的字符串描述符的索引。 参考资料: 1. USB in a NutShell - Chapter 3 - USB Protocols (beyondlogic.org) 2. USB in a NutShell - Chapter 5 - USB Descriptors (beyondlogic.org)
- 10 Mar, 2022
UVC的视频格式协商流程-Video Probe&Commit Request
UVC设备与Host之间进行视频传输格式协商的通信流程,是Host与UVC设备的Video Streaming Interface来进行通信的。两者之间的通信数据包的格式如UVC协议SET/GET Request结构解析一文中的VideoStreaming Requests部分所述。 Probe&Commit工作流程 Video Streaming Interface在Host和UVC camera之间使用一种Probe+Commit的方式来实现两者之间传输的视频格式协商流程的实现。 大致的流程是: - UVC设备的USB描述符中,在Video Streaming Interface的声明上,包含了该设备所能够支持的所有YUV、MJPEG以及H.264等各种格式、不同分辨率帧率视频的列表,后续Host主要就是从这个列表中进行选择; - 在协商过程中,Host端基于USB描述符中的format和分辨率、帧率等信息,以及自己的支持情况,选择一组期望的视频格式参数,通过Video Probe Control/SET_CUR命令发送给Device; - Device收到以后Host发过来的视频格式参数后,对这个参数进行检查,看自己能不能完整支持: - 如果能够支持的话,就在这个参数结构中保持Host发过来的参数; - 如果无法支持就把对应的参数项设置为0,这样Host读回之后就会知道Device无法支持这个设置选项; - 然后Host端再通过Video Probe Control/GET_CUR命令把Device检查过的参数读回来; - 如果Host读回的参数跟自己使用SET_CUR命令设置的参数完全一致的话,就表示两者已经协商一致,下一步就可以通过Commit命令向Device确认这个协商过的参数,并启动device开始按照这个参数发送图像流了; - 如果Host读回的参数有部分选项被Device修改为0,就表示Device无法支持该选项,这个时候Host就需要重新回到第二步,把Device无法支持的选项指标参数调低,然后再通过Probe/Get_cur和Probe/Set_Cur命令重新进行协商,直至达成一致; - Host与Device按照以上Probe的协商流程达成一致后,就再通过Commit/SET_CUR指令向Device确认之前协商一致的参数,并启动图像流的传输; 简化版的工作流程如下图所示: !Untitled.png - 在以上流程中,Host与Device只进行了一次格式协商就达成一致; 更完整的协商流程图如下所示: !Untitled.png - 当Host读回的协商数据结构体出现不一致的情况下,就需要重新从头再进行协商。 协商数据结构体 | Offset | Field | Size | Description | | ------ | -------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 0 | bmHint | 2 | 这个参数用于指定在Host和Device在协商过程中,如果协商参数不一致、需要进一步协商的情况下,应该保持哪些属性不变。该参数由Host指定,对于Device而言是只读的。 | | 2 | bFormatIndex | 1 | 本次协商Host所选择的格式索引(YUV/MJPEG/H.264),Device支持的格式列表及其索引在USB配置描述符中。该参数由Host指定。 | | 3 | bFrameIndex | 1 | 本次协商Host所选择的图像帧分辨率索引,Device支持的分辨率参数列表及其索引在USB配置描述符中。该参数由Host指定。 | | 4 | dwFrameInterval | 4 | 本次协商Host所选择的帧率,以100ns为单位; | | 8 | wKeyFrameRate | 2 | 本次协商Host所选择的关键帧间隔帧数量。 | | 10 | wPFrameRate | 2 | 本次协商Host所选择的两个关键帧之间所包含的P Frame的数量。除了关键帧和P帧,剩下的就是B帧了。 | | 12 | wCompQuality | 2 | 本次协商Host所选择的图像压缩质量即Compression Quality。取值范围为1(图像质量最低)-10000(图像质量最高). | | 14 | wCompWindowSize | 2 | 本次协商Host所选择的计算平均码率的图像帧数量。UVC1.5协议中提供了一个例子,设置目标平均码率为100Kbps的情况下,当把wCompWindowSize设置为10的话,就表示单个帧的大小可以大于或者小于100Kbps,但是连续计算10个图像帧的平均码率的话,这个平均码率大致就是100Kbps。 | | 16 | wDelay | 2 | 从视频图像采集,到显示出来的图像延迟。以ms为单位。 | | 18 | dwMaxVideoFrameSize | 4 | Device与Host在进行视频数据传输时,一个图像帧的数据量大小的最大值。 | | 22 | dwMaxPayloadTransferSize | 4 | Device与Host在进行视频数据传输的过程中,一次传输的packet中包含的数据大小的最大值。该参数由Device端设置,Host只读。 | | 26 | dwClockFrequency | 4 | Device端设置的时钟频率,以Hz为单位。在设备端发给Host的图像流的Payloader Header中依据这个参数来计算时间戳信息。这个参数由Device端设置,Host只读。 | | 30 | bmFramingInfo | 1 | 与Device发给Host的每一个图像帧数据的payload header的设置有关的位设置。 | | 31 | bPreferedVersion | 1 | 该参数用于进行视频帧数据向Host传输的封装Payload格式的版本。每种Format可能会包含多个payload格式定义的版本,收发双方需要在这个版本上达成一致。Host端会把bPreferedVersion、bMinVersion和bMaxersion这三个参数在第一次进行Probe/Set的时候设置为0,具体的值由Device进行设置。然后Host在Probe/Get命令读取到Device端的设置值,在下次进行SET命令的时候设置自己期望使用的bPreferedVersion(min和max之间),但是bMinVersion和bMaxVersion必须保持为device设置的值。 | | 32 | bMinVersion | 1 | 参考bPreferedVersion的解释 | | 33 | bMaxVersion | 1 | 参考bPreferedVersion的解释 | | 34 | bUsage | 1 | Device与Host传输图像视频的视频流模式,包括实时流、广播、文件存储等工作模式。 | | 35 | bBitDepthLuma | 1 | bit_depth_luma_minus8 + 8 | | 36 | bmSettings | 1 | temporally encoded video stream类型的传输流(例如H.264)专用,与这类图像流传输的Payload设置有关。 | | 37 | bMaxNumberOfRefFramesPlus1 | 1 | Host端需要保存的最多参考帧的数量。 | | 38 | bmRateControlModes | 2 | 码率控制模式设置。最多可以支持同时传输4条独立的视频流,每条流的码率控制模式都可以单独设置,控制模式用4bit表示,总共就是两个字节。如果这条流不支持码率控制,应该设置为0。 | | 40 | bmLayoutPerStream | 8 | 视频编码算法的分层结构设置。最多可以支持同时传输4条独立的视频流,每条流的码率控制模式都可以单独设置,控制模式用2字节表示,总共就是八个字节。没有增强层的情况下,这个选项应该设置为0; | 协商数据结构体是Host和Device之间使用Probe/Commit命令进行数据交换的格式。 - UVC1.5和UVC1.1的这个数据结构体的定义不同,UVC1.5是48字节,UVC1.1是34字节。以下以UVC1.5为准进行该结构体各个Field的说明。 问题 _既然UVC设备对于视频格式的支持情况在其USB配置描述符中的Video Streaming Interface中已经包含了,对于Host而言,只需要从其中选择然后通过Commit直接设置即可,为什么还要通过这个来回反复的Probe/Set和Probe/Get命令来进行协商确定呢?_ 答案从以上协商数据中包含的各个Field的定义就可以看出来:通过Probe&Commit机制协商的视频图像参数,与USB配置描述符信息中所包含的信息并不一样。 这个媒体格式协商的机制就是在Device提供的Format和Frame的基础上进行选择,然后再在Probe&Commit的流程中对于可以协商的参数进行进一步明确和细化的完整通信流程。 参考资料: 1. UVC1.5 specification; 2. AN75779 - How to implement an image sensor interface using EZ-USB FX3 in a UVC framework_Framework-ApplicationNotes-v13_00-EN.pdf?fileId=8ac78c8c7cdc391c017d073ad2b85f0d) 3. Getting video stream from USB web-camera on Arduino Due - Part 1: Getting Started - CodeProject
- 03 Mar, 2022
USB传输类型之Interrupt/Bulk/Isochronous Transfer
本文是对usb in a nutshell相关章节的学习的基础上,整理出来的USB中断、Bulk和Isochronous三种类型的传输流程及其packet的组成。USB控制传输类型在USB传输类型之Control Transfer一文中中总结。 简单总结起来,中断、Bulk和Isochronous这三种类型的传输,相比于控制传输而言,相对要简单一些。 控制传输的完整流程包含了三个阶段,每个阶段都包含由多个Packet; 而中断、Bulk和Isochronous这三种类型没有Stage的概念,完整的一个Transaction由连续的2-3个Packet组成。 Interrupt 另外三种USB通信传输类型都是Host主动要向Device读取或者写入数据,中断类型为了解决Device有数据要向Host发送的应用场景,最典型的就是USB鼠标、键盘等类的应用,鼠标和键盘何时动作,没有办法提前预测,发生事件的时候Device能够马上知道,但是对于所有的通信都是由Host发起的USB通信总线而言,它是如何能够让Host尽快读走并处理数据以保证应用处理的实时性?这就是中断传输针对的应用场景。 简单的讲,对于注册到USB总线上的中断类型的端点,Host总线会预留通信带宽,按照USB枚举信息中定义的中断查询周期,定期对这个中断端点上的数据进行轮询。如果有数据的话立即读走处理,没有的话等待下个周期再读。如果这个定时查询的周期事件很短的话,就可以保证应用响应的实时性。 对于USB2.0高速设备而言,一次中断传输可以容纳的数据长度是1024字节。 中断端点的通信方向同样包含IN和OUT两种。但如以上应用场景所述,中断类型的传输主要是解决Device端有一些实时性数据需要及时向Host端上传的问题,因此最常用的中断端点传输类型是IN模式,它的OUT模式跟Bulk就比较类似了。 !Untitled.png - Interrupt IN: - 正常的工作流程包括三个packet:IN Token+Data Packet+ACK packet。 - Host按照中断端点描述符中定义的poll time定时对这个IN中断端点进行查询,看Device端是否有数据要发给Host: - 当Device端有数据要向Host发送的时候,就会回一个Data Packet,Host成功接收并处理以后,给Device回复一个ACK packet。整个传输就完成了; - 如果Device端在本次查询的时候没有数据要发送,就会直接回复一个NAK握手包。Host收到以后就等待下个轮询周期再去这个端点查询。 - Interrupt OUT: - Out类型的传输流程比较简单。当Host有数据要发给Device的话,先发一个Out Token Packet,然后再发一个Data Packet,Device端收到以后回复一个ACK。 - 这样的话Interrupt OUT就跟Bulk Out的区别不大了,想不出来用Interrupt Out的理由何在。 Bulk Bulk类型的传输是USB的四种传输类型中应用最普遍的类型。 Bulk传输最大的特点就是可靠传输+Best Effort。 - 可靠传输也就意味着,无论是IN传输还是OUT传输,双方发出的Data Packet都会被接收方通过发出ACK来进行应答,这样数据的发送方就能够知道数据是否被成功接收。如果没有收到ACK的话,发送方可以再进行重传,以确保接收方总是按照顺序可靠、正确的接收到了数据包。 - Best Effort则意味着Bulk传输不会预留通信带宽,而是只要有数据收发需求+有带宽,就会全力的占用可用的带宽传输数据。这样的话,当USB总线上有更高优先级的数据要传输,例如中断传输和Isochronous传输,USB总线就会优先传输以上两种类型的数据。因此Bulk传输适用于那些有大量数据要传输,但是对数据传输的实时性要求不高的应用场合。 对于USB2.0高速设备而言,Bulk传输的每个Data Packet可以容纳的数据长度最大为512个字节。 - 当发送的数据长度小于512字节的话,不需要用0填充剩余的字节。 在Bulk传输中,接收端在以下三种情况下会认为本次Bulk传输已完成: - 接收方接收到了它请求的数据大小; - 本次接收到的data packet的长度小于512字节; - 本次接收到的data packet是一个0字节长度的数据包; !Untitled.png - Bulk IN: - 正常的一次Bulk IN传输包含三个Packet:IN Token+data packet+Ack packet; - 当Host以Bulk IN的方式从Device读取数据的时候,首先发出一个IN Token,Device端回一个Data Packet,在其中包含有要发送给Host的数据,Host收到后通过ACK进行应答。整个通信过程完成。 - 错误处理: - 如果Device接收到的IN Token错误,device端不做任何处理; - 如果这个IN端点发送错误,Device端回复一个STALL packet; - 如果这个IN端点暂时没有数据可以发给Host,Device端回复一个NAK packet; - Bulk OUT: - 正常的一次Bulk OUT传输同样包含有三个packet:OUT Token+data packet+ACK packet; - 当Host以Bulk OUT的方式向Device发送数据的时候,首先发出一个IN Token,然后再发出一个Data Packet,在其中包含有要发送给Device的数据,deice收到后通过ACK进行应答。整个通信过程完成。 - 错误处理: - 如果device接收到的OUT Token或者Data Packet有错误,device端不做任何处理,直接忽略; - 如果这个OUT端点工作状态发生错误,Device端回复一个STALL packet; - 如果这个OUT端点非空(例如之前的数据尚未被读走),无法处理本次的接收到的数据,Device端回复一个NAK packet; Isochronous 在USB传输的四种传输类型中,Isochronous类型是在接收到数据后唯一不需要发送ACK应答包的,这也就意味着这种类型允许一定数量的丢包。即使发生丢包也不需要重传,实际上数据的发送端根本不知道接收端是否有正确的接收到数据。这一点是Isochronous类型传输的最大特点。 因此,Isochronous类型传输比较适合用于传输实时音视频这类对于传输数据的实时性要求很敏感、但是对于丢包要求不是很严苛的应用场合。例如UVC摄像头的音视频流就可以通过这种方式向Host传输。 !Untitled.png Isochronous IN和OUT传输的流程比较简单,就是一个由Host发出一个IN/OUT Token,然后紧接着是Host或者Device发出的Data Packet,数据的接收方不需要对接收数据做任何应答,发送方也就不清楚这个包是否被接收成功,因此不会有重传机制。 Isochronous类型一次数据传输可以容纳的数据长度在其端点描述符中进行指定,一般小于1024字节。但是需要注意:这个数据包的长度并非越大越好。设置的越大,也就意味着一次Isochronous传输需要花的事件越长,占用的传输带宽就越多。那么在USB总线本身比较繁忙的情况下,出现丢包的可能性也就越高。 因此,Host与Device之间进行Isochronous类型传输的丢包情况,由Host端根据USB总线的繁忙状态对其带宽进行管理决定。当总线比较繁忙的时候,Host就会选择给Isochronous传输设置较小的数据长度,避免占用过多带宽导致丢包;而总线空闲的时候,Host就会给Isochronous端点传输选择大一点的数据长度,来提升传输的效率。 如前所述,Isochronous端点的数据payload长度是在其端点描述符中指定好的,那么Host如何来对这个payload进行选择/设置呢? 答案就是,在isochronous类型的端点描述符声明中,一般需要通过alternative interface的方式,在包含有isochronous端点interface声明中,通过多个alternative interface+endpoint descriptor的方式来声明多个不同payload的端点配置,然后由Host进行选择并设置。 例如以下是Thinkpad X260自带的UVC摄像头的一部分USB枚举信息,其中在传输音视频数据的Video Streaming Interface就使用了Isochronous类型的端点,该端点的描述符信息定义如下: 可以看到,在Video Streaming Interface下面的这个isochronous端点描述符的定义上,包含了七组不同packet size的端点描述符,这样Host就可以根据当前的总线情况选择使用对应的packet size设置。 参考资料: - USB in a NutShell - Chapter 4 - Endpoint Types (beyondlogic.org)
- 02 Mar, 2022
USB UVC协议SET/GET Request结构解析
本文主要是在对UVC 1.5协议第四章Class-Specific Requests学习的基础上,整理出来的UVC SET和GET请求的数据结构,方便对UVC通信协议的实现过程进行完整的理解。 UVC Class Specific Request的通信流程 实际上UVC class specific request都是在端点0上进行的控制类传输(Control Transfer),按照Control Transfer的规范定义,这些请求主要包含由三个阶段组成:Setup Stage、Data Stage和Status Stage。而每个命令选项的SET和GET Request实际上也包含了以上三个阶段,都是从Host发出一个Setup Packet开始的: !Untitled.png 对于Set类请求而言(例如上图的SET_CUR),完整的通信流程是: - Host先发出一个Setup Packet,其中包含有要设置的选项的定位信息、选项类型、设置数据长度(对于每一个选项而言,数据长度都是确定的,具体的数据在Data Packet中传输)等; - 然后Host继续发出一个Data Packet,其中包含有具体的设置数据; - 如果Device能够在10ms之内返回状态信息,就给Host直接在控制传输的Status Stage直接返回状态;如果大于10ms,则需要通过接口注册的中断端点向Host返回状态信息; 而对于Get类请求而言(例如上图的GET_CUR),完整的通信流程是: - Host先发出一个Setup Packet,其中包含有要读取的选项的定位信息、选项类型、读取数据长度(对于每一个选项而言,数据长度都是确定的,具体的数据在Data Packet中传输)等; - Device收到以后,会向Host发回一个Data Packet,其中包含有具体的选项数据读取; - 最后Device继续在控制传输的Status Stage向Host返回状态包; 关于控制传输和Setup packet的内容可以参考: - USB传输类型之Control Transfer - USB控制传输中的Setup Packet 相关术语 - Control Selector:实际上就是要设置或者读取的具体选项类型。 - Entity:通信的目的实体,可以是一个接口Interface,也可以是接口中的一个单元Unit。一个Entity中可能有1个或者多个选项(Control Selector)可以存取。 UVC class specific request的总体数据结构 UVC class specific request总体上可以分为两类:Set类请求和Get类请求。前者用于设置UVC camera中的运行参数;后者则用户读取当前运行参数、参数的设置范围、默认值等。 Set Request !Untitled.png - bmRequestType: - bit7为0表示这个这个Packet是由Host发给Device; - bit6..5为0b01表示这个setup packet是一个class级别的包; - bit4..0:为1表示这个setup packet是要发给接口,为2则是要发给端点;具体要看这个设置命令在协议中是如何定义的; - bRequest: - 在UVC规范的Table A.8中有定义,因此此处的SET_CUR对应的就是0x01; !Untitled.png - wIndex和wValue配合起来用于定位本次Set请求是要发送到哪个接口/Unit/端点上,要设置具体的选项是什么; - 一般在wValue的高字节中传递要设置的选项的类型;如果通信目的的Entity有多个设置选项的话,使用wValue来定位是要设置哪个选项;如果Entity只有一个选项,可以把这个wValue用于传递其他的参数; - wIndex的低字节用于指定通信目的的接口编号或者端点地址,高字节用于指定要设置的Entity/Unit的编号或者0; - UVC Device收到的UVC Set/Get Request是发给Video Control interfac还是发给Video Streaming Interface的,就是由wIndex的低8位来决定。wIndex的低8位在此处就对应于Interface Index,与USB枚举信息中定义的两个接口的Index number相一致; - 所以结合wIndex和wValue就可以定位这个命令是要发送到什么地方,设置什么选项; - wLength:Data Stage的数据长度,每个要设置的选项参数长度不同 - Data:具体的设置数据,包含在Data Packet中。Setup Packet只包含前面的5个field; Get Request !Untitled.png - bmRequestType:与Set Request相同,区别是bit7为1,表示本次通信的Data Stage是要从Device端读取; - bRequest:在UVC规范的Table A.8中有定义 - wIndex和wValue的定义与Set Request相同 - wLength:Data Stage的数据长度,每个要读取的选项参数长度不同 - Data:具体的读取数据,包含在Data Packet中。Setup Packet只包含前面的5个field; VideoControl Requests 对于Video Control Interface的Request而言,包含两类请求:接口级别的Interface Control Requests,和端子/单元级别的Unit and Terminal Control Requests。 Interface Control Requests 这类命令是直接发给Video Control Interface,直接由interface来进行处理的: !Untitled.png - wValue指定要设置的接口选项的id,video control interface支持的接口级别的选项只有两个:Power Mode Control和Request Error Code Control,分别对应CS=0和CS=1; - wIndex设置为Video Control Interface的接口编号; - 其他Field与通用的Set Request和Get Request中的描述保持一致 Unit and Terminal Control Requests 这类命令是发给Video Control Interface下面的端子Terminal和各个单元Unit的,每个端子和单元所能支持的选项各自不同。 !Untitled.png - wValue指定要设置的选项id,Video Control Interface中包含的各个Terminal和Unit所支持的选项数量众多,通过这个CS(Control Selector)来区分是要对哪个选项进行操作; - ALL类型的request因为对整个Unit或者Terminal中包含的所有选项进行操作,所以直接设置wValue为0; - wIndex指定要是这的Unit和Terminal的索引编号,在UVC的配置描述符中进行定义; - 其他Field与通用的Set Request和Get Request中的描述保持一致 VideoStreaming Requests 因为Video Streaming Interface没有Unit和Terminal的概念,所以所有的请求命令都是直接发给interface级别来直接进行处理的。 !Untitled.png - wValue指定要存取的接口选项id,UVC device通过这个id来分析这个命令要访问的Video Streaming Interface的选项是什么; - wIndex设置Video Streaming Interface的接口编号; - 其他Field与通用的Set Request和Get Request中的描述保持一致 参考文档: - USB Device Class Definition for Video Devices V1.5:4 Class-Specific Requests
- 01 Mar, 2022
USB标准包类型总结
一次基本的USB通信业务(也就是所谓的USB Transaction)通常包含三个USB基本Packet: - Token Packet:由Host发起,其中包含有通信的意图、目的设备的device address、端点号等信息; - Data Packet(可选):由具体的通信意图确定,可能是从Host发给Device(Out Data Packet),也可能是Host从Device读取(IN Data Packet); - Status Packet:根据Data Packet的数据走向,由数据的接收方向发送方给出的应答包,告知数据是否被成功、正确的解释并处理。 因此本文对USB通信中用到的各种基本包类型进行总结。 常用的USB基本包类型主要包括以下四种: - Token Packet; - Data Packet; - Handshake Packet; - SOF Packet; 其中每种类型的包又可以分为多种子类型,而每个Packet内部又包含有多个Field。 USB Packet中的那些通用Field - Sync: - 所有的USB Packet都必须要从Sync开始。 - 在低速和全速设备上是8bit,在高速设备上是32bit。用于在Host和Device设备之间同步时钟,没有实质的通信意义。 - PID:Packet ID - 用于标记当前Packet的类型是什么。Packet ID实际上总共只有4bit,因此最多支持16种类型的packet,在具体通信的时候另外4bit是PID的反码,凑成一个8bit的PID字节。 !Untitled.png - ADDR: - USB Device的设备地址,长度为7bit,因此USB总线上最多可以支持127个设备。但是0号地址预留给枚举过程中尚未分配地址的设备,因此可用的Device address是126个。 - ENDP: - 通信的端点编号。长度为4bit,因此一个设备最多能够支持16个端点,其中的0号端点固定为控制传输端点,所有的控制传输通信都是与端点0进行通信。 - CRC: - 这个packet的CRC校验值。所有的Token Packet都使用5bit CRC校验值,所有的Data Packet都使用16bit校验值。 Token Packet Token Packet用于指示本次USB通信业务的具体类型和意图。 有3种类型的Token Packet: - Setup Token:表示本次Host发起的通信业务是一个USB控制传输通信业务,例如读取设备、配置描述符,设置地址等。 - IN Token:表示本次Host发起的通信业务是期望从Device的指定IN端点读取数据; - OUT Token:表示本次Host发起的通信业务是期望向Device的指定OUT端点写入数据; Token Packet的格式固定为: !Untitled.png - 因此Token Packet中包含的信息主要就是PID、设备地址、端点号。其中的PID在上面的Packet ID表中查询。 Data Packet Data Packet用于装载本次USB通信业务的数据负荷。 USB高速设备支持4种类型的Data Packet:Data0,Data1,Data2,MData。 USB高速设备支持的Data Packet中可以容纳的数据长度限制为1024个字节,超过这个限制就需要分为多个Data Packet进行传输。 Data Packet的格式为: !Untitled.png Handshake Packet Handshake Packet用于向数据发送方提供接收数据的应答信息,是否在通信中发生错误的状态信息等。 有3种类型的Handshake Packet: - ACK:向发送方应答数据已经成功接收并处理; - NAK:表示当前端点繁忙,暂时无法处理新的数据; - STALL:表示当前通信端点出错,需要Host端干预处理; Handshake Packet的格式为: !Untitled.png SOF Packet 在USB高速总线上每125us由Host发出一个SOF packet: !Untitled.png 参考资料: - USB in a NutShell - Chapter 3 - USB Protocols (beyondlogic.org)
- 01 Mar, 2022
USB传输类型之Control Transfer
USB的控制传输通常用于传输控制命令和状态信息数据。USB最重要的功能枚举功能就是通过控制传输来完成的。 USB的控制传输最多包含有3个通信阶段:Setup Stage、可选的Data Stage和Status Stage。每个Stage都包含有多个USB事务和通信包。 - 实际上每个Stage也就是一个所谓的事务Transaction,这样的话一个控制传输也就包含3个Transaction。每个Transaction/Stage则包含有多个Packet。 Setup Stage Setup Stage包含有三个USB packet:Setup token packet,data packet和ack packet。 !Untitled.png - Setup Token:就是一个标准的Setup token packet,使用PID(0b1101)进行标记,其中包含有device端的设备地址和端点号; - Data:Data部分实际上就是在内部包含了一个定长8字节的Setup Packet,在其中详细定义这个控制传输的请求类型; - ACK:最后的ACK包用于标记Device是否已经成功接收并处理了前面的两个包。 - 在device端成功接收并处理的情况下,会应答一个标准的ACK包; - 如果通信过程中出错的话Device不会发出NAK或者STALL包; 注意:Setup Token和Data packet中包含的Setup Packet尽管名称很类似,但这两者是完全不同的概念。 Setup Token是一个标准的USB token packet;其包结构为: !Untitled.png 而Setup Packet则是一个USB Data Packet;其包结构为: !Untitled.png Data Stage Data Stage是可选的。 Data Stage中可以包含一个或者多个IN或者OUT类型的数据包。例如USB枚举过程中,一般USB配置描述符信息比较大,在一个Data IN Packet中容纳不下,就需要分为多个IN Packet对描述符信息进行传输。 Data Stage中要传输的数据长度,在Setup Stage中的Data Packet中包含的Setup Packet wLength Field中指定。如果要传输的数据长度超过单个IN或者OUT Packet的最大支持长度,就需要分为多个包进行传输。 在Data Stage具体是用IN还是OUT类型的传输,要看这个控制传输的具体使用场景是什么。一般SET类的控制传输请求都是使用OUT类型的Data Stage,而GET类的控制传输请求都是使用IN类型的Data Stage。 !Untitled.png IN类型的Data Stage: - Host端在做好接收数据准备的情况下,发出一个标准的IN Token(PID=0b1011),其中包含有通信的目的device地址和端口号; - Device发回一个Data packet; - Host收到并正确处理后发出一个ACK信息; - 如果通信中Device端接收到的IN Token错误,Device端直接对其忽略,并不做任何响应; - 如果通信中Device端的IN端点发生错误,无法正确发出DATA packet的时候,Device会返回一个STALL Packet; - 如果通信中Device端的IN端点没有问题,但是目前Device端无数据可以发送,Device端会返回一个NAK Packet; - 如果Host有多个Data Packet要读取的话,都需要按照以上的IN-DATA-ACK的流程进行通信。 OUT类型的Data Stage: - Host端首先发出一个标准的OUT Token(PID=0b0001),其中包含有通信的目的Device地址和端口号; - Host端紧接着再发出一个Data Packet; - Device端正确的接收并处理以后发出一个ACK Packet; - 如果通信中OUT Token和Data Packet出现任何错误,Device端直接对其忽略,不做任何响应; - 如果通信中Device端的OUT端点buffer正在处理之前接收的数据,尚无法接收新数据的时候,Device端会返回一个NAK Packet; - 如果通信中Device端的OUT端点发生错误,无法正确接收数据的时候,Device端会返回一个STALL Packet; - 如果Host有多个Data Packet要发送的话,都需要按照以上的OUT-DATA-ACK的流程进行通信。 Status Stage Sattus Stage用于对本次完整的控制传输通信业务再进行一次总的应答和报告,这样Host和Device两者都能清楚的知晓本次控制通信的业务是否完整、正确完成。 根据Data Stage阶段Host是从Device读取数据,还是向Device发出数据,Status Stage也分为两种类型的状态应答: IN:当Host在Data Stage阶段通过发出IN Token从Device端读取数据的时候,就需要在Status Stage向Device发出信息,告知自己已经正确的接收并处理数据。 !Untitled.png - 具体的做法就是:Host端先发出一个OUT Token,然后紧跟着再发出一个长度为0的Data Packet。Device正确接收前面两个包以后,就会返回一个ACK packet。至此这次控制传输至此就完整的完成了。 OUT:当Host在Data Stage阶段通过发出OUT Token向Device端发送数据的时候,Device就需要在Status Stage向Host发出信息,告知自己已经正确的接收并处理数据。 !Untitled.png - 具体的做法就是:Host端先发出一个IN Token,然后紧跟着从Device端的IN端点上读取一个长度为0的Data Packet。如果以上通信正确,Host就会返回一个ACK packet。至此这次控制传输至此就完整的完成了。 读取设备描述符的完整控制传输例子 以Host在USB枚举阶段从Device端读取设备描述符的例子,来解释完整的控制传输的过程。 仍然是包括以上三个阶段: 1.Setup Stage !Untitled.png - 这个阶段总共有3个包:Host发出的Setup Token Packet和Data Packet,以及Device的ACK Handshake Packet。 - 通信的目的device地址和端点号包含在Setup Token Packet中; - 因为是控制传输类型,所以这里的端点号固定为0; - 读取设备描述符的请求是一个标准的Standard Setup Packet,定长8字节,封装在Data Packet中的Data0 Field中。 - Device接收到Setup token以后,也就知道在其后面紧跟的Data Packet中包含的就是一个标准的Setup Packet;然后Device端对这个Setup packet进行解析,就能够知道这次控制传输请求的的目的是什么,而Data Stage要读取的数据长度则包含在Setup Packet的wLength Field中; 2.Data Stage Device端接收到Setup Stage中包含的Setup Packet,并对其解析以后,就能够得知Host是要读取设备描述符。然后就在Data Stage中通过IN方式返回自己的设备描述符给Host。 !Untitled.png - 每个IN Data packet所包含的数据长度是有限制的,如果Host要读取的数据长度超过了这个限制,就需要分为多个IN Packet进行传输,而每个IN Packet的传输都需要包含IN Token-Data Pakcet-ACK Handshake三个阶段,直到所有数据全部发送完成。 - 上面的例子中,设备描述符的长度是12个字节,单个data packet的长度限制是8个字节,所以分为两个data packet发给host,第一个packet为8字节,第二个packet为剩下的4字节。 3.Status Stage Host端成功读取device端的设备描述符以后,就需要通过发出一个0长度的OUT Data Packet通知Device,至此这个读取设备描述符的控制传输过程就完整的完成了。 !Untitled.png 参考资料: - USB in a NutShell - Chapter 4 - Endpoint Types (beyondlogic.org)
- 25 Feb, 2022
USB控制传输中的Setup Packet
Setup Packet一般用于Host对Device进行的检测、配置,和执行特定的控制功能,例如设置USB的device address,读取device端的USB描述符、检查端点的状态等。除了以上标准的操作命令的处理以外,某些USB Class Driver也使用Setup Packet进行一些Class类型的控制操作,最典型的:UVC设备就是通过Setup Packet来对UVC摄像头的内部工作参数(亮度、对比度等)进行SET和GET操作。 所有的USB设备都必须要在端点0上响应Host发出的Setup Packet。 Setup Packet的结构 Setup Packet是固定的8字节长度,包含有5个Field: !Untitled.png - bmRequestType:长度为1字节。用于定义这个Setup Packet的数据传输方向(从Host流出还是流入)、类型(标准/usb class/厂商自定义)和接收处理对象(设备、接口还是端点); - bRequest、wValue和wIndex三个Field根据不同的命令类型的定义各有不同; - wLength:如有setup packet后面还有一个data stage的话,在此指定data stage的数据长度; 标准Setup Packet 标准设备请求包 !Untitled.png 标准接口请求 !Untitled.png 标准端点请求包 !Untitled.png Class类型的Setup Packet 如上所述,bmRequestType的D6..5为0b01的时候,表示这个Setup Packet是一个Class类型的Setup Packet。在不同的USB Class中队Setup Packet各个field的定义不同。 以下为UVC 1.5规范“4.1 Request Layout”所描述的UVC SET与GET请求中定义的Setup Packet结构: SET请求结构: !Untitled.png GET请求结构: !Untitled.png UVC协议是使用控制传输来实现对UVC camera进行控制命令和状态参数的读取,控制传输的第一个阶段就是Host发出一个Setup Packet,Host就通过这个Setup Packet来指定命令的目的地、具体的命令类型和后面第二个阶段的Data Packet中包含的数据长度。 参考资料: - USB in a NutShell - Chapter 6 - USB Requests (beyondlogic.org) - UVC 1.5 specification, 4.1 Request Layout
- 24 Jul, 2020
USB复合设备及UVC Profile的描述符详解
USB Composite Device 所谓的USB composite device就是一个USB设备中包含有多项功能,每项功能的具体实现都包含一个或者多个相互独立的Interface,但是整个设备只有一个PID和VID。多个设备功能通过内部逻辑和接口组合的形式形成一个对外的设备。 USB Composite device可以分为两种情况: - 该设备中的每个单独的功能function的实现都只用到一个Interface - 就是所谓的Composite device without multi-interface functions,例如:HID Transfer + MSC、 HID Transfer + HID Keyboard和HID Mouse + HID Keyboard; - 在这种情况下需要设置这个USB设备的设备描述符bDeviceClass、bDeviceSubClass、bDeviceProtocol这三个参数为0x00、0x00、0x00; - 这个设备的配置描述符中通过bNumInterfaces参数指定内部有多少个接口; - 然后在每个接口的接口描述符中通过bInterfaceClass、bInterfaceSubclass、bInterfaceProtocol三个参数指定这个接口提供的USB function的类型usb class; - 该设备中的某项单独功能需要用到多个Interface的组合 - 就是所谓的Composite device with multi-interface function,例如:VCOM + HID Transfer、VCOM + MSC、VCOM + HID Keyboard、Dual VCOM和Audio + HID Transfer。 - 这种情况下需要使用IAD描述符把multi interface功能的多个接口组合在一起,此时就要设置这个USB设备的设备描述符bDeviceClass、bDeviceSubClass、bDeviceProtocol这三个参数为0xEF、0x02、0x01。 USB Composite Device和USB Compound Device的区别: - USB Composite Device是一个USB设备,只有一个PID和VID,但是这个设备里面包含了多个功能,在内部逻辑上通过多个接口Interface来分别实现这些功能; - USB Compound Device内部包含一个USB Hub和多个USB功能设备,这些设备通过内部Hub与外部的USB Host进行连接,每个USB设备都有自己的PID和VID,相当于每个设备都是一个独立的外设,因此一个USB Compound Device包含多组PID/VID; - 在USB2.0的规范中定义如下: - When multiple functions are combined with a hub in a single package, they are referred to as a compound device. - A device that has multiple interfaces controlled independently of each other is referred to as a composite device. IAD描述符 USB的IAD描述符用于把一个USB设备中包含的多个interface合并为一个function提供出来。 - 因此可以把IAD描述符看成是对多个interface的分组操作,把多个interface分成一组来对外提供一个完整的功能function。 对于IAD设备而言,在这个USB设备的设备描述符中需要按照以下规则设置bDeviceClass、bDeviceSubClass、bDeviceProtocol等参数,USB Host才能够正确的识别和解析这个IAD设备后续的配置描述符信息: - bDeviceClass:0xEF - bDeviceSubClass:0x02b - DeviceProtocol:0x01。 而这个IAD描述符所指定的Function功能即USB class则通过IAD描述符中的bFunctionClass、bFunctionSubClass、bFunctionProtocol这三个参数进行指定,例如如果这个IAD描述符定义的是一个USB Video class的function,需要按照如下参数设置IAD描述符的相关信息: - bFunctionClass: 0x0E - bFunctionSubClass: 0x03 - bFunctionProtocol: 0x00 IAD描述符各个选项参数的定义: !Untitled.png - bFirstInterface表示这个IAD描述符所使用的第一个Interface的编号 - bInterfaceCount表示这个IAD描述符需要包含的interface数量 - bFunctionClass、bFunctionSubClass和bFunctionProtocol定义的是这个描述符所实现的是USB哪个class的功能; 在USB规范中定义需要使用IAD描述符的USB device class主要有: - USB Video Class Specification(class code=0x0E) - USB Audio Class Specification(class code=0x01) - USB Bluetooth Class Specification(class code=0xE0) 注意: - IAD描述符中指定使用的多个Interface的编号必须要是连续的,即这个IAD下面的Interface Group的各个Interface的编号必须是连续的; - 一个Composite USB设备中可以包含由多个IAD描述符,只需要使用IAD描述符中的接口配置信息定义清楚这个IAD功能所占用的接口,并且每个IAD描述符必须位于它所包含的多个接口描述符之前; UVC设备的接口与IAD描述符 所有的UVC设备都是多Interface设备,一个UVC设备最起码应该有两个Interface:VideoControl(VC)Interface和VideoStream(VS) Interface。 Spec明确要求一个具有可用的,具有实际UVC功能的设备要有一个VC Interface,一个或多个VS Interface。 - VCInterface用于进行配置,操控,设置UVC设备进入不同的功能状态; - VSInterface则负责定义这个UVC设备所支持的各种视频流的格式以及视频数据流的传输; - 完整的UVC功能需依赖VS Interface和VC Interface的配合才能实现。 因为UVC设备是需要把两个接口(VS+VC)结合在一起来提供音视频传输与控制的服务,因此UVC的Spec还明确要求UVC设备必须要使用一个Interface Association Descriptor(IAD)来描述这个包含了VC和VS的Interfaces集合。 - 在UVC的设备描述符中,也需要设置这个设备DeviceClass、Device Subclass以及Device Protocol为IAD设备; Video Control Interface Video Control Interface中包含的主要组件: - Input Terminal:描述这个设备的输入端,及其支持的功能; - Output Terminal:描述这个设备的输出端,及其支持的功能; - Camera Terminal:描述这个设备的相机功能,例如Focus、Zoom等功能; - Select Unit:实际上就是Mux复用组件; - Processing Unit:描述这个设备的图像处理功能,例如灰度、曝光、亮度控制的功能; - Extension Unit:描述这个设备支持的额外扩展性功能,可有可无; 一个Video Control Interface的例子: !Untitled.png 因此实际上Video Control Interface就是把上面的多种类型的Terminal和Unit连接起来组成的一个提供音视频流处理的pipeline,最终通过Output Terminal对外提供音视频流数据。 USB Host对UVC camera发送的所有控制类型的命令都是通过这个interface来完成的。 Video Streaming Interface Video Streaming Interface则专门负责用于传输UVC设备的Video数据到Host端。 一个UVC camera通常会支持多种不同的Format不同分辨率和帧率的图像传输格式,需要在Video Streaming Interface的接口描述中把支持的所有视频格式使用Video Streaming Frame Type描述符进行定义。 - 不同编码格式、分辨率、帧率对于USB传输带宽的要求各不相同,目前能够支持的主要的编码格式是YUV、MJPEG和H.264; - 要能够支持高清高帧率图像的UVC传输,就只能使用MJPEG和H.264这类压缩数据格式; 每个Video Streaming Interface必须要包含一个ISO或者Bulk端点用于传输Video Streaming数据,以及一个可选的Bulk端点用于传输静态图片数据(在UVC Camera中已经实现了静态图片拍照的机制的前提下)。 一个USB接口UVC Camera+HID设备的例子 参考资料USB Interface Association Descriptor中提供了一个包含有UVC Camera和HID功能的USB设备的例子。 该设备具有两部分功能: - Video Class,即UVC功能 - 该功能由一个IAD描述符定义,其中包含一个Video Control Interface(即Interface 0)和一个Video Streaming Interface(即Interface 1); - USB Host端解析到这个IAD描述及其下面的VC和VS Interface描述符后,会加载video class driver进行处理。 - HID功能 - 该功能包含有一个实现HID功能的Interface(即Interface 2); - USB Host解析该接口对应的描述符会后自动加载Host端的HID class driver来进行处理; 该设备的USB描述符结构: 设备描述符 - 表示这是一个包含有IAD描述符的multi function composite USB device; 配置描述符 - bNumInterfaces为其内部包含的USB接口数量,其中UVC功能通过IAD描述符包含有2个Interafce,HID包含一个Interface; IAD描述符 - bInterfaceCount表示这个IAD描述符需要包含的interface数量,这里是2个,也就是Video Control Interafce和Video Streaming Interface; - bFirstInterface表示这个IAD描述符所使用的第一个Interface的编号,这里是0,也就是说这个IAD用的两个Interface就是:Interface0和Interface1; - 后续的bFunctionClass、bFunctionSubClass和bFunctionProtocol定义了这是一个Video class的功能; Video Control Interface描述符 - 此后是Video Control Interface的内部描述信息(即这个VC Interface中包含的各个Terminal和Unit的组织情况)及这个接口的端点信息描述符; Video Streaming Interface描述符 此后是Video Streaming Interface的内部描述信息(即这个VS Interface中包含的各种Video Format的详细信息列表)及这个接口的端点信息描述符; HID功能对应的Interface描述符 最后是HID功能接口的详细配置信息及其对应的端点描述符信息; 参考资料 - UVC(USB Video Class)协议讲解 - USB Video Class 簡介 - USB Interface Association Descriptor