最近在做一项目,正常点亮一拖四usbCamera,开发版是用的是MTK8173,应用方面参考https://github.com/saki4510t/UVCCamera
单个摄像头点亮无问题,不同厂商,型号的四个摄像头同时点亮,预览,拍照,录像也是正常的。但当相同厂商,型号,也即读取的摄像头descriptor完全相同,问题就出现了,只有先挂载的可以正常预览,相同规格摄像头的第二个就无法出预览图。
出现问题的log中,明显的错误如下:
01-02 04:24:45.286 3519 3572 I libUVCCamera: [3572*UVCPreview.cpp:492:prepare_preview]:frameSize=(640,480)@MJPEG
01-02 04:24:45.294 3519 3572 E libuvc/stream: [3572*stream.c:1605:uvc_stream_start_bandwidth]:fail
01-02 04:24:45.294 3519 3572 W libUVCCamera: [3572*diag.c:88:uvc_perror]:failed start_streaming:Unknown error (-99)
提示uvc_stream_start_bandwidth出错。同样,在github上能找到的issue里,最接近的是
https://github.com/saki4510t/UVCCamera/issues/8
遗憾的是从头看到尾,目前作者没有给到很好的解决方案。
没办法,还得从代码去找问题,追logcat却也看不出来问题,就想到从kernel角度看下,其log如下:
<6>[ 235.960068] (1)[1394:CameraThread]usb 1-2.1.4: zzz,usbdev_do_ioctl: SETINTERFACE
<3>[ 235.961266] (1)[1394:CameraThread]usb 1-2.1.4: zzz111,proc_setintf come here
<3>[ 235.962165] (1)[1394:CameraThread]usb 1-2.1.4: zzz222,proc_setintf come here
<3>[ 235.963069] (1)[1394:CameraThread]usb 1-2.1.4: zzz333,proc_setintf come here
<3>[235.963956] (1)[1394:CameraThread]usb 1-2.1.4: zzz,proc_setintfproc_setintf here setintf.interface=1,setintf.altsetting=1
<6>[ 235.965366] (1)[1394:CameraThread]usb 1-2.1.4: zzz,usb_set_interface come,interface=1,alternate=1
<6>[ 235.966485] (1)[1394:CameraThread]usbfs 1-2.1.4:1.1: zzz,intf->altsetting[i].desc.bAlternateSetting=0, altnum=1
<6>[ 235.967797] (1)[1394:CameraThread]usbfs 1-2.1.4:1.1: zzz,intf->altsetting[i].desc.bAlternateSetting=1, altnum=1
<6>[ 235.969389] (1)[1394:CameraThread]usb 1-2.1.4: zzz,usb_set_interface product=USB 2.0 HD Camera ,manufacturer=(null),serial=(null),devnum=7,desc.bInterfaceNumber=1
<6>[ 235.971774] (5)[1394:CameraThread]usb 1-2.1.4: zzz,cur_alt && new_alt is true come here
<3>[ 235.972890] (5)[1394:CameraThread]xhci-hcd xhci-hcd.1.auto: zzz3,xhci_mtk_add_ep_quirk() type:1, speed:3, mpkt:1024, dir:1, ep:ffffffc076e62800
<3>[ 235.974508] (5)[1394:CameraThread]xhci-hcd xhci-hcd.1.auto: zzz,Not enough bandwidth!
<6>[ 235.975501] (5)[1394:CameraThread]usb 1-2.1.4: zzzzz,Not enough bandwidth for altsetting 1,ret=-28
<4>[ 236.049537] (0)[104:kworker/u12:1]mfg_2d: Power-off latency exceeded, new value 162616 ns
<4>[ 242.132057] (1)[140:kworker/u12:4]mfg_2d: Power-off latency exceeded, new value 174231 ns<222 -> 1338>
同样是提示带宽不足,错误序号-28(/* No space left on device */):
<3>[ 235.974508] (5)[1394:CameraThread]xhci-hcd xhci-hcd.1.auto: zzz,Not enough bandwidth!
<6>[ 235.975501] (5)[1394:CameraThread]usb 1-2.1.4: zzzzz,Not enough bandwidth for altsetting 1,ret=-28
至此,对于usb带宽和协议不是很了解的情况下,依然不晓得,应该怎样修复此问题。
从https://github.com/saki4510t/UVCCamera/issues/8得知,即使相同规格,有部分摄像头是可以满足同时出图的。恰好手头有深蓝科技的一组摄像头,就可以正常使用,其kernel log如下:
<3>[ 9617.289236] (1)[1498:CameraThread]usb 1-2.1.2: zzz,proc_setintfproc_setintf here setintf.interface=1,setintf.altsetting=2
<6>[ 9617.290630] (1)[1498:CameraThread]usb 1-2.1.2: zzz,usb_set_interface come,interface=1,alternate=2
<6>[ 9617.291982] (1)[1498:CameraThread]usbfs 1-2.1.2:1.1: zzz,intf->altsetting[i].desc.bAlternateSetting=0, altnum=2
<6>[ 9617.293637] (1)[1498:CameraThread]usbfs 1-2.1.2:1.1: zzz,intf->altsetting[i].desc.bAlternateSetting=1, altnum=2
<6>[ 9617.295322] (1)[1498:CameraThread]usbfs 1-2.1.2:1.1: zzz,intf->altsetting[i].desc.bAlternateSetting=2, altnum=2
<6>[ 9617.296613] (1)[1498:CameraThread]usb 1-2.1.2: zzz,usb_set_interface product=USB2.0_CAM1,manufacturer=D-vitec,serial=0000,devnum=9,desc.bInterfaceNumber=1
<6>[ 9617.298352] (1)[1498:CameraThread]usb 1-2.1.2: cur_alt && new_alt is true come here
<3>[ 9617.299343] (1)[1498:CameraThread]xhci-hcd xhci-hcd.1.auto: zzz3,xhci_mtk_add_ep_quirk() type:1, speed:3, mpkt:512, dir:1, ep:ffffffc06f0dd800
通过上述log,发现GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc))这个值不一样,手头出错的 mpkt:1024, 深蓝科技的mpkt:512,通过代码追踪,在libusb的驱动文件中stream.c的uvc_stream_start_bandwidth方法
uvc_error_t uvc_stream_start_bandwidth(uvc_stream_handle_t *strmh, uvc_frame_callback_t *cb, void *user_ptr, float bandwidth_factor, uint8_t flags) {
......
/* Find the endpoint with the number specified in the VS header */
for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) {
endpoint = altsetting->endpoint + ep_idx;
if (endpoint->bEndpointAddress==format_desc->parent->bEndpointAddress){
endpoint_bytes_per_packet = endpoint->wMaxPacketSize; LOGE("zzz11,endpoint_bytes_per_packet=%d",endpoint_bytes_per_packet); // wMaxPacketSize: [unused:2 (multiplier-1):3 size:11]
// bit10…0: maximum packet size
// bit12…11: the number of additional transaction opportunities per microframe for high-speed
// 00 = None (1 transaction per microframe)
// 01 = 1 additional (2 per microframe)
// 10 = 2 additional (3 per microframe)
// 11 = Reserved
//*/new add here
if ((endpoint_bytes_per_packet & 0x07ff) > 512) {
endpoint_bytes_per_packet = endpoint_bytes_per_packet/2;
}
//*/
endpoint_bytes_per_packet = (endpoint_bytes_per_packet & 0x07ff) * (((endpoint_bytes_per_packet >> 11) & 3) + 1); LOGE("zzz22,endpoint_bytes_per_packet=%d",endpoint_bytes_per_packet); break;
}
}
......
}
从endpoint->wMaxPacketSize; 得到的值的前11位的值即为我们log中的mptk,在这边当此值大于512时,强行赋一半的值给它,则问题解决,两种完全相同规格的摄像头可以同时出预览图。
由于对驱动模块不是很熟悉,对USB协议相关的知识也知之甚少,以上仅从当前代码的角度,提供一拖四或一拖二usbCamera相同规格摄像头不能同时出图的一种思路。但是应该有更好的,更彻底的解决方案。