Linux源码分析UVC摄像头的打开流程及抓包分析
2021-04-01
1735
0
和关闭摄像头类似,Linux使用uvc_video_start_streaming函数打开摄像头
int uvc_video_start_streaming(struct uvc_streaming *stream)
{
int ret;
ret = uvc_video_clock_init(stream);
if (ret < 0)
return ret;
/* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0)
goto error_commit;
ret = uvc_video_start_transfer(stream, GFP_KERNEL);
if (ret < 0)
goto error_video;
return 0;
error_video:
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
uvc_video_clock_cleanup(stream);
return ret;
}
从代码来看,首先要据当前的的配置使用选择子VS_COMMIT_CONTROL提交参数,后续就是开始传输。
开始传输的部分代码解释可参见前几节关于wMaxVideoFrameSize和dwMaxPayloadTransferSize参数的关系分析。这里只列出代码。
可以看到,这里区分了是同步传输还是批量传输。如果是同步传输,是需要根据dwMaxPayloadTransferSize选择合适的视频流端点的,如果是批量传输,则直接校验断该批量端点地址,后续就是分配相关的URB数据内存。
static int uvc_video_start_transfer(struct uvc_streaming *stream,
gfp_t gfp_flags)
{
struct usb_interface *intf = stream->intf;
struct usb_host_endpoint *ep;
struct uvc_urb *uvc_urb;
unsigned int i;
int ret;
stream->sequence = -1;
stream->last_fid = -1;
stream->bulk.header_size = 0;
stream->bulk.skip_payload = 0;
stream->bulk.payload_size = 0;
uvc_video_stats_start(stream);
if (intf->num_altsetting > 1) {
struct usb_host_endpoint *best_ep = NULL;
unsigned int best_psize = UINT_MAX;
unsigned int bandwidth;
unsigned int 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);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0],
stream->header.bEndpointAddress);
if (ep == NULL)
return -EIO;
ret = uvc_init_video_bulk(stream, ep, gfp_flags);
}
if (ret < 0)
return ret;
/* Submit the URBs. */
for_each_uvc_urb(uvc_urb, stream) {
ret = usb_submit_urb(uvc_urb->urb, gfp_flags);
if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n",
uvc_urb_index(uvc_urb), ret);
uvc_video_stop_transfer(stream, 1);
return ret;
}
}
/* The Logitech C920 temporarily forgets that it should not be adjusting
* Exposure Absolute during init so restore controls to stored values.
*/
if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
uvc_ctrl_restore_values(stream->dev);
return 0;
}
UVC摄像头同步传输的打开
其抓包分析内容如下:
Device Length Phase Data
------ -------- ----- ----------------------------------------------------- -------------
47.0 CTL a1 81 00 01 01 00 1a 00 GET CUR
47.0 26 IN 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL 21 01 00 01 01 00 1a 00 SET CUR
47.0 26 OUT 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL a1 81 00 01 01 00 1a 00 GET CUR
47.0 26 IN 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL a1 83 00 01 01 00 1a 00 GET MAX
47.0 26 IN 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
47.0 CTL a1 82 00 01 01 00 1a 00 GET MIN
47.0 26 IN 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............
47.0 CTL 21 01 00 01 01 00 1a 00 SET CUR
47.0 26 OUT 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL a1 81 00 01 01 00 1a 00 GET CUR
47.0 26 IN 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL 21 01 00 02 01 00 1a 00 SET CUR
47.0 26 OUT 01 00 01 03 15 16 05 00 00 00 00 00 00 00 00 00 .............
47.0 CTL 01 0b 01 00 01 00 00 00 SET INTERFACE
具体的分析过程可详见 UVC 打开UVC摄像头(特定类请求)数据分析
UVC摄像头批量传输的打开
Device Length Phase Data
44.0 CTL a1 81 00 01 02 00 22 00 GET CUR
44.0 34 IN 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL 21 01 00 01 02 00 22 00 SET CUR
44.0 34 OUT 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL a1 81 00 01 02 00 22 00 GET CUR
44.0 34 IN 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL a1 83 00 01 02 00 22 00 GET MAX
44.0 34 IN 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL a1 82 00 01 02 00 22 00 GET MIN
44.0 34 IN 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL 21 01 00 02 02 00 22 00 SET CUR
44.0 34 OUT 01 00 01 01 15 16 05 00 00 00 00 00 00 00 00 00 .............
44.0 CTL 01 0b 00 00 02 00 00 00 SET INTERFACE
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936