UVC摄像头技术笔记
+ -

UVC等时传输中的dwMaxVideoFrameSize和dwMaxPayloadTransferSize关系

2021-03-31 2099 0

在其整个视频流控制接口参数偏移地址18处的字段为一4字节的dwMaxVideoFrameSize,代表的是如果选择当前数据帧格式,其一帧图像的最大数据量大小,以字节为单位。

关于dwMaxVideoFrameSize的计算可以参考 YUV2摄像头相关数据大小计算。

这里我们主要说一下dwMaxVideoFrameSize和dwMaxPayloadTransferSize关系。
通过上节UVC等时传输中的dwMaxPayloadTransferSize可知道,在一次URB的传输过程中,可能包含多次的dwMaxPayloadTransferSize,那么这个多次具体是多少了,而且这个多次直接影响的是我们使用抓包工具如bushound进行抓包的总在大小。
在上一节初的Linux代码中,根据dwMaxPayloadTransferSize选择了合适的转换接口后,然后调用uvc_init_video_isoc(stream, best_ep, gfp_flags);来进行初始化同步/等时传输。在这个函数里就是说明了dwMaxVideoFrameSize和dwMaxPayloadTransferSize关系。

uvc_init_video_isoc源代码如下:

static int uvc_init_video_isoc(struct uvc_streaming *stream,
    struct usb_host_endpoint *ep, gfp_t gfp_flags)
{
    struct urb *urb;
    struct uvc_urb *uvc_urb;
    unsigned int npackets, i;
    u16 psize;
    u32 size;

    psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
    size = stream->ctrl.dwMaxVideoFrameSize;

    npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
    if (npackets == 0)
        return -ENOMEM;

    size = npackets * psize;

    for_each_uvc_urb(uvc_urb, stream) {
        urb = usb_alloc_urb(npackets, gfp_flags);
        if (urb == NULL) {
            uvc_video_stop_transfer(stream, 1);
            return -ENOMEM;
        }

        urb->dev = stream->dev->udev;
        urb->context = uvc_urb;
        urb->pipe = usb_rcvisocpipe(stream->dev->udev,
                ep->desc.bEndpointAddress);
#ifndef CONFIG_DMA_NONCOHERENT
        urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
        urb->transfer_dma = uvc_urb->dma;
#else
        urb->transfer_flags = URB_ISO_ASAP;
#endif
        urb->interval = ep->desc.bInterval;
        urb->transfer_buffer = uvc_urb->buffer;
        urb->complete = uvc_video_complete;
        urb->number_of_packets = npackets;
        urb->transfer_buffer_length = size;

        for (i = 0; i < npackets; ++i) {
            urb->iso_frame_desc[i].offset = i * psize;
            urb->iso_frame_desc[i].length = psize;
        }

        uvc_urb->urb = urb;
    }

    return 0;
}

通过uvc_init_video_isoc的源代码可知,其分配URB的buffer内存空间是通过uvc_alloc_urb_buffers来计算的,其源代码如下:


static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
    unsigned int size, unsigned int psize, gfp_t gfp_flags)
{
    unsigned int npackets;
    unsigned int i;

    /* Buffers are already allocated, bail out. */
    if (stream->urb_size)
        return stream->urb_size / psize;

    /* Compute the number of packets. Bulk endpoints might transfer UVC
     * payloads across multiple URBs.
     */
    npackets = DIV_ROUND_UP(size, psize);
    if (npackets > UVC_MAX_PACKETS)
        npackets = UVC_MAX_PACKETS;

    /* Retry allocations until one succeed. */
    for (; npackets > 1; npackets /= 2) {
        for (i = 0; i < UVC_URBS; ++i) {
            struct uvc_urb *uvc_urb = &stream->uvc_urb[i];

            stream->urb_size = psize * npackets;
#ifndef CONFIG_DMA_NONCOHERENT
            uvc_urb->buffer = usb_alloc_coherent(
                stream->dev->udev, stream->urb_size,
                gfp_flags | __GFP_NOWARN, &uvc_urb->dma);
#else
            uvc_urb->buffer =
                kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
#endif
            if (!uvc_urb->buffer) {
                uvc_free_urb_buffers(stream);
                break;
            }

            uvc_urb->stream = stream;
        }

        if (i == UVC_URBS) {
            uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
                "of %ux%u bytes each.\n", UVC_URBS, npackets,
                psize);
            return npackets;
        }
    }

    uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes "
        "per packet).\n", psize);
    return 0;
}

从上面的代码可知,如果定义了urb_size,则直接使用urb_size/psize (等时/同步传输中dwMaxPayloadTransferSize=psize),如果不存在,则使用size即dwMaxVideoFrameSize直接除以pssize,计算包的个数。这里可以看到,在一次URB传输过程中,效率最高的时候就是一个URB可以直接传输一帧图像的数据,使用多次即多个类似windows中的USBD_ISO_PACKET_DESCRIPTOR。

#define UVC_MAX_PACKETS        32

如果包大大,则最大不能超过32个,这样表示一个URB中最大可以传输32个ISO同步传输包,这样还可能存在一帧数据需要多个URB来传输完成。这样一帧图像可能包需要多个URB来传输,每个URB中最多不超过32个ISO传输。但实际在分配内存的时候,可能由于dwMaxPayloadTransferSize太大,导致一个URB直接分配32个dwMaxPayloadTransferSize的连续的整片内存分配失败,Linux做了拆半分配算法处理。

uvc_init_video_isoc函数的后半段可以看到,这里是分配urb空间,并对各个urb内部的iso_frame进行初始化,并设置相关该iso_frame的大小和偏移。

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......
USB 同步/等时传输方式
USB协议规定了四种传输类型:控制传输、批量传输、同步传输、中断传输。等时传输也有“同步传输”的叫法,一般用于要求数据连续、实时且数据量大的场合,其对传输延时十分敏感,类似用于USB摄像设备,USB语音设备等等。同步事务没有握手包。当一个同步传输中有多个事务时,最后一个事务之前的事务的数据长......
USB 同步/等时传输及反馈端点
USB的四种传输之一同步传输,用于数据实时性比较高,数据量较大但数据的完整性不是很严格的场合。由于时间是同步传输的关键部分,因此USB设计者了解这些不同实体在USB中如何处理时间是很重要的。在大部分的通讯系统中,数据的发送者和接收者以同步的方式进行数据收发。在异步通信系统中,允许数据发送者检测接收方......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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