UVC摄像头技术笔记
+ -

UVC等时传输中的dwMaxPayloadTransferSize

2021-03-31 3122 0

UVC视频流接口控制请求的数据大小可为26字节,34字节和48字节,其分别对应的是UVC的1.0,1,1和UVC1.5版本。
在其整个视频流控制接口参数偏移地址22处的字段为一4字节的dwMaxPayloadTransferSize,根据其字段解释为“指定设备在单个有效负载传输中可以传输或接收的最大字节数。必须支持此字段。此字段由设备设置,仅从主机读取。某些主机实现限制此字段允许的最大值。主机应通过重新配置设备来避免单个有效负载传输大小的超调。(例如,通过更新比特率、分辨率等)”关于这个字段,经常有人理解不清楚,这里我们专门来解释一下。

LINUX中UVC驱动关于它的计算方法如下:

    interval = (ctrl->dwFrameInterval > 100000) ? ctrl->dwFrameInterval:frame->dwFrameInterval[0];

        /* Compute a bandwidth estimation by multiplying the frame
         * size by the number of video frames per second, divide the
         * result by the number of USB frames (or micro-frames for
         * high-speed devices) per second and add the UVC header size
         * (assumed to be 12 bytes long).
         */
        //一帧大小
        bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
        //1秒大小
        bandwidth *= 10000000 / interval + 1;

        //1ms大小
        bandwidth /= 1000;

        //一个微帧大小
        if (stream->dev->udev->speed == USB_SPEED_HIGH)
            bandwidth /= 8;

        //加上负载头
        bandwidth += 12;

        /* The bandwidth estimate is too low for many cameras. Don't use
         * maximum packet sizes lower than 1024 bytes to try and work
         * around the problem. According to measurements done on two
         * different camera models, the value is high enough to get most
         * resolutions working while not preventing two simultaneous
         * VGA streams at 15 fps.
         */

        //该值最小是1024字节
        //所以这是计算一帧或者一个微帧最大传输的大小?
        bandwidth = max_t(u32, bandwidth, 1024);

        ctrl->dwMaxPayloadTransferSize = bandwidth;

USB端点的大小

通过UVC规范的学习可以知道,UVC在视频数据的传输只支持批量传输和等时/同步传输。对于等时传输,假如我们使用的是USB2.0高速,那么根据USB规范可知,其等时传输的端点数据包大小最大为1024字节(具体可参见USB规范端点描述符一节),但是为了提高数据的传输效率,在USB等时传输支持额外的传输次数,这里额外的传输次数最大为2。故在USB2.0高速的传输过程中,一个同步/等时传输端点的一次可最大传输字节数为1024*(2+1)=3072=0x0c00的字节数。所以这里的这个字节数就是dwMaxPayloadTransferSize即单个有效负载传输中可以传输或接收的最大字节数。

USB的等时传输

由于是同步/等时传输,为了提高数据的传输效率,一个URB可以含有多个单次有效负载传输传输,这里我们记为N。这样在一个URB的数据传输过程中,最大可以传输N*有效负载传输中可以传输,这个计算出来的数据就是一个抓包的数据大小。

抓包是按一个URB进行抓包的。

Linux源代码分析

在Linux的源代码uvc_video_start_transfer函数(linux-5.6.11\linux-5.6.11\drivers\media\usb\uvc\uvc_video.c:1810)中,在初始化时的代码如下:

if (intf->num_altsetting > 1) {
        struct usb_host_endpoint *best_ep = NULL;
        unsigned int best_psize = UINT_MAX;
        unsigned int bandwidth;
        unsigned int uninitialized_var(altsetting);
        int intfnum = stream->intfnum;

        /* Isochronous endpoint, select the alternate setting. */
        bandwidth = stream->ctrl.dwMaxPayloadTransferSize;

        if (bandwidth == 0) {
            uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
                "bandwidth, defaulting to lowest.\n");
            bandwidth = 1;
        } else {
            uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
                "B/frame bandwidth.\n", bandwidth);
        }

        for (i = 0; i < intf->num_altsetting; ++i) {
            struct usb_host_interface *alts;
            unsigned int psize;

            alts = &intf->altsetting[i];
            ep = uvc_find_endpoint(alts,
                stream->header.bEndpointAddress);
            if (ep == NULL)
                continue;

            /* Check if the bandwidth is high enough. */
            psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
            if (psize >= bandwidth && psize <= best_psize) {
                altsetting = alts->desc.bAlternateSetting;
                best_psize = psize;
                best_ep = ep;
            }
        }

        if (best_ep == NULL) {
            uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
                "for requested bandwidth.\n");
            return -EIO;
        }

        uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
            "(%u B/frame bandwidth).\n", altsetting, best_psize);

        ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
        if (ret < 0)
            return ret;

        ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
    }

在其源代码中首先将dwMaxPayloadTransferSize赋值给bandwidth,在各个视频流转换接口中的同步/等时端点中查找一个带宽大于等于其bandwidth的端点,然后选择其对应的接口。
计算其端点带宽的函数uvc_endpoint_max_bpi代码如下:

static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
                     struct usb_host_endpoint *ep)
{
    u16 psize;
    u16 mult;

    switch (dev->speed) {
    case USB_SPEED_SUPER:
    case USB_SPEED_SUPER_PLUS:
        return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
    case USB_SPEED_HIGH:
        psize = usb_endpoint_maxp(&ep->desc);
        mult = usb_endpoint_maxp_mult(&ep->desc);
        return psize * mult;
    case USB_SPEED_WIRELESS:
        psize = usb_endpoint_maxp(&ep->desc);
        return psize;
    default:
        psize = usb_endpoint_maxp(&ep->desc);
        return psize;
    }
}

可以看到,对于高带设备USB_SPEED_HIGH,获取其端点的大小和mult(额外传输的次数+1),最后的乘积就是最大带宽即单次传输大小。

usb_endpoint_maxp_mult(const struct usb_endpoint_descriptor *epd)
{
    int maxp = __le16_to_cpu(epd->wMaxPacketSize);

    return USB_EP_MAXP_MULT(maxp) + 1;
}
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 等时传输中的URB_ISOCH_TRANSFER
通过UVC规范可知,视频图像数据的读取可使用两种端点传输方式,分别为:BULK 块/批量传输方式ISO 等时/同步传输方式在Windows内核中,USB数据的读取是通过URB来进行传输的,其结构体是一个大大的共用体,根据数据传输的方式对应其不同的结构体,其内容如下:typedef _Struct_s......
UVC等时传输中的dwMaxPayloadTransferSize
UVC的视频流接口控制请求的数据大小可为26字节,34字节和48字节,其分别对应的是UVC的1.0,1,1和UVC1.5版本。在其整个视频流控制接口参数偏移地址22处的字段为一4字节的dwMaxPayloadTransferSize,根据其字段解释为“指定设备在单个有效负载传输中可以传输或接收的最大......
UVC等时传输中的dwMaxVideoFrameSize和dwMaxPayloadTransferSize关系
在其整个视频流控制接口参数偏移地址18处的字段为一4字节的dwMaxVideoFrameSize,代表的是如果选择当前数据帧格式,其一帧图像的最大数据量大小,以字节为单位。关于dwMaxVideoFrameSize的计算可以参考 YUV2摄像头相关数据大小计算。这里我们主要说一下dwMaxVideo......
UVC批量传输中的dwMaxVideoFrameSize和dwMaxPayloadTransferSize关系
上一节看了UVC等时/同步传输的关系,这里我们介绍一相批量传输。批量传输在这里相对于同步传输要简单的多。uvc_video_start_transfer中的代码如下: else { /* Bulk endpoint, proceed to URB initialization. */ ......
USB 等时/同步传输、块传输与转换设置在UVC摄像头驱动中的探讨
最近在Windows10 x64环境下,开发了一个虚拟UVC摄像头驱动。确切的来说这不是摄像头驱动,而是一个虚拟USB总线驱动。使用该虚拟总线驱动使用应用软件通过IOCTL控制总线子设备的创建与卸载。框架设计驱动安装完成后,是一个单纯的USB虚拟总线。应用软件通过发送自定义IOCTL码IOCTL......
USB 同步/等时传输方式
USB协议规定了四种传输类型:控制传输、批量传输、同步传输、中断传输。等时传输也有“同步传输”的叫法,一般用于要求数据连续、实时且数据量大的场合,其对传输延时十分敏感,类似用于USB摄像设备,USB语音设备等等。同步事务没有握手包。当一个同步传输中有多个事务时,最后一个事务之前的事务的数据长......
USB超高速 同步传输
正如USB2.0一样,超速同步传输类型是用来支持想要能容忍错误,周期性的轮询服务的传输流。超速跟USB2.0一样不发送起始帧,但是时序信息要通过同步时间戳包(ITP)被发送给设备。这个规格的协议层章详细描述了用来完成同步传输的包,总线事务和事务处理流程。也描述了怎么样传送时序信息给设备。超速同步传输......
USB 同步/等时传输及反馈端点
USB的四种传输之一同步传输,用于数据实时性比较高,数据量较大但数据的完整性不是很严格的场合。由于时间是同步传输的关键部分,因此USB设计者了解这些不同实体在USB中如何处理时间是很重要的。在大部分的通讯系统中,数据的发送者和接收者以同步的方式进行数据收发。在异步通信系统中,允许数据发送者检测接收方......
再谈USB摄像头UVC视频流接口控制请求dwMaxVideoFrameSize和dwMaxPayloadTransferSize
刚开始的时候,我们做一件事是认真,一丝不苟。对于各个数据的考量力求做到精度,其实这个追求可能并不是因为我们因为项目上的要求,而是我们为了弄清一个事实,有了这个事实我们就可以随处吹牛逼,也成了我们在做新的类似的项目上的优势之资。言归正转,以前在windows下通过USB总线驱动虚拟的UVC摄像头都只......
基于UVC规范的USB摄像头数据传输模式的总结
根据UVC(USB VIDEO CLASS)规范,UVC视频数据传输方式支持:同步传输即ISO传输批量传输即BULK传输但是不同的操作系统对UVC规范的支持不一定是全量支持的:Windows操作系统对于windows操作系统,对UVC版本的支持情况如下:UVC 版本Windows ......
手动分析使用BUSHOUND抓取同步传输的URB
BUSHOUND大家太熟了,使用它来进行数据抓包那不太太方便。但在BUSHOUND的抓取配置项中,有一个叫了URB的东西,我相信大家都没有选中过,因为一般来说,对WINDOWS USB驱动开发人员来说都不一定有用,更何况大家也只是用来抓取一下几个数据的输入输出,更没有必要进行USB的分析了。本人今天......
USB 同步传输端点的数据包PID序列及额外传输端点大小
对于同步传输:如果输入端点提供的负载数据小于端点描述符指定的最大负载数据,则主机端将不再该端点提供进一步的输入事务。这是因为所对USB设备来说,所有的数据传输都是由主机发起的。对于数据输入IN事务,虽然数据的传输方向为设备端到主机,但是该事务却是由主机发起。由于设备的输入端点提供的负载数据小于该......
USB摄像头同步传输的完成后URB参数
这几天不是闲来无事,一个工作的任务就是对手中一个USB摄像头进行驱动开发,并进行视频格式的转换。通过分析该USB摄像头可知,其采用的是同步传输,所以本人在开发的驱动中,使用同步的URB进行下发请求数据,然后在完成例程中获取数据。同步传输的URB本人在 手动分析使用BUSHOUND抓取同步传输的URB......
UAC麦克风同步传输的URB分析
之前写过同步传输的UVC摄像头的URB,文章名称为:手动分析使用BUSHOUND抓取同步传输的URB 。今天恰好手中有一个UVC麦克风,所以也拿来分析。也许和之前的文章有所重复,但是因为侧重点的不同,也许会有意想不到的小收获取。言归正转,我们知道,在UAC音频规范中,数据的传输不像UVC摄像头那样,......
USB摄像头同步传输H264遇到的花屏问题
以往拿到的摄像头数据传输都是批量传输,本人也只在音频驱动的开发中使用了同步传输。这次突然拿到一个摄像头,数据采用的是同步传输,本以为很简单的代码移植,却没有想到还是遇到了一个坑,自己花费了大力气来排查,在这期间自己也看了大量的资料,今天在这里做一个简单的总结。以前的摄像头拿到的USB摄像头如批量传......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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