Linux&UVC驱动
+ -

LINUX&UVC视频格式协商VS_PROBE_CONTROLL

2024-04-01 7 0

UVC视频的协商其实走的是VS_PROBE_CONTROLL请求,使用该请求可以获取一个默认的视频格式、分辨率。当然,如果用户指定非默认的,会也使用VS_PROBE_CONTROLL请求来验证是否存在。无论是默认的还是新指定的,最终协商完成后,都会使用VS_COMMIT_CONTROL请求最后进行提交给设备。这时固件可以按提交的给格式来将视频的数据转换成该格式,并通过UVC负载头的要求进行打包,使用批量传输或者同步传输数据到主机了。

在LINUX&UVC驱动中,其汲及一部分ops请求,分别为:

const struct v4l2_ioctl_ops uvc_ioctl_ops = {
...
    .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap,
    .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
    .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap,
    .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out,

这其中分为两组,第一组为uvc_v4l2_set_format,第二组为uvc_v4l2_try_format。不过最终都会调用uvc_probe_video函数进行VS_PROBE_CONTROLL,而VS_COMMIT_CONTROL请求是start_streaming请求对应的uvc_start_streaming函数中调用uvc_video_start_streaming实现的。

协商使用的数据结构体为:

/* 4.3.1.1. Video Probe and Commit Controls */
struct uvc_streaming_control {
    __u16 bmHint;
    __u8  bFormatIndex;
    __u8  bFrameIndex;
    __u32 dwFrameInterval;
    __u16 wKeyFrameRate;
    __u16 wPFrameRate;
    __u16 wCompQuality;
    __u16 wCompWindowSize;
    __u16 wDelay;
    __u32 dwMaxVideoFrameSize;
    __u32 dwMaxPayloadTransferSize;
    __u32 dwClockFrequency;
    __u8  bmFramingInfo;
    __u8  bPreferedVersion;
    __u8  bMinVersion;
    __u8  bMaxVersion;
} __attribute__((__packed__));

关于以上各字段的详解见:https://www.usbzh.com/article/detail-45.html

这里对应的是UVC1.1的34字节数据格式,为什么不是48字节进行裁剪了,我估计是UVC1.5增加的字节这里没啥用。其实从代码也可以看到:

static int uvc_set_video_ctrl(struct uvc_streaming *stream,
    struct uvc_streaming_control *ctrl, int probe)
{
    u16 size = uvc_video_ctrl_size(stream);
    u8 *data;
    int ret;

    data = kzalloc(size, GFP_KERNEL);
    if (data == NULL)
        return -ENOMEM;

    *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
    data[2] = ctrl->bFormatIndex;
    data[3] = ctrl->bFrameIndex;
    *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
    *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
    *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
    *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
    *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
    *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
    put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
    put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);

    //这里只有UVC1.0和UVC1.1的区别,UVC1.5的扩展全部为0
    if (size >= 34) {
        put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
        data[30] = ctrl->bmFramingInfo;
        data[31] = ctrl->bPreferedVersion;
        data[32] = ctrl->bMinVersion;
        data[33] = ctrl->bMaxVersion;
    }

    //发起SET_CUR特定类请求
    ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
        probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL,
        data,size, uvc_timeout_param);
    if (ret != size) {
        uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
            "%d (exp. %u).\n", probe ? "probe" : "commit",
            ret, size);
        ret = -EIO;
    }

    kfree(data);
    return ret;
}

而uvc_video_ctrl_size则根据版本返回实际长度。

static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
{
    /*
     * Return the size of the video probe and commit controls, which depends
     * on the protocol version.
     */
    if (stream->dev->uvc_version < 0x0110)
        return 26;
    else if (stream->dev->uvc_version < 0x0150)
        return 34;
    else
        return 48;
}

0 篇笔记 写笔记

LINUX&UVC视频格式协商VS_PROBE_CONTROLL
UVC视频的协商其实走的是VS_PROBE_CONTROLL请求,使用该请求可以获取一个默认的视频格式、分辨率。当然,如果用户指定非默认的,会也使用VS_PROBE_CONTROLL请求来验证是否存在。无论是默认的还是新指定的,最终协商完成后,都会使用VS_COMMIT_CONTROL请求最后进行提......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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