LINUX&UVC视频格式协商VS_PROBE_CONTROLL
2024-04-01
129
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;
}