UVC的视频格式协商流程-Video Probe&Commit Request

date
Mar 10, 2022
slug
2022-03-10-USB-UVC-Probe-Commit-Requests
status
Published
tags
USB
UVC
summary
本文对UVC协议下,Host与Device之间在传输Streaming之前进行媒体流格式、参数协商的Video Streaming Probe&Commit的过程做了一个简单地总结。
type
Post
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确认之前协商一致的参数,并启动图像流的传输;
简化版的工作流程如下图所示:
notion image
  • 在以上流程中,Host与Device只进行了一次格式协商就达成一致;
更完整的协商流程图如下所示:
notion image
  • 当Host读回的协商数据结构体出现不一致的情况下,就需要重新从头再进行协商。

协商数据结构体

协商数据结构体是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;
  1. AN75779 - How to implement an image sensor interface using EZ-USB FX3 in a UVC framework
  1. Getting video stream from USB web-camera on Arduino Due - Part 1: Getting Started - CodeProject

© Pavel Han 2020 - 2022