V4L2驱动程序损坏Android OMAP5432上4个USB摄像头的缓冲区
我有OMAP5432 EVM运行安卓4.2,带有4个USB连接的Logitech C270摄像头。 我使用NDK C-code中的V4L2驱动程序在MJPEG模式下打开并从摄像机中传输数据。 一切都很好,除了在相机开机后 电源循环后,两个或有时三个摄像头正常工作,但其中一个开始吐出帧缓冲区,该缓冲区的开头缺少MJPEG SOI 0xFF、0xD8,而EOI 0xFF、0xD9存在 使用posix close()关闭并重新打开有问题的摄像头文件/dev/videoX,可以在下一次电源循环之前永久修复该问题 连接单个摄像头时不会发生这种情况,只有3个或4个摄像头 我尝试过更换USB集线器,直接连接摄像头,但没有效果V4L2驱动程序损坏Android OMAP5432上4个USB摄像头的缓冲区,android,camera,android-ndk,v4l2,omap,Android,Camera,Android Ndk,V4l2,Omap,我有OMAP5432 EVM运行安卓4.2,带有4个USB连接的Logitech C270摄像头。 我使用NDK C-code中的V4L2驱动程序在MJPEG模式下打开并从摄像机中传输数据。 一切都很好,除了在相机开机后 电源循环后,两个或有时三个摄像头正常工作,但其中一个开始吐出帧缓冲区,该缓冲区的开头缺少MJPEG SOI 0xFF、0xD8,而EOI 0xFF、0xD9存在 使用posix close()关闭并重新打开有问题的摄像头文件/dev/videoX,可以在下一次电源循环之前永久修
struct v4l2_format fm = {0};
fm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int r = xioctl(c->fd, VIDIOC_G_FMT, &fm);
if (r != 0) {
printf("VIDIOC_G_FMT %s r=%d error %d, %s", c->name, r, errno, strerror(errno));
return -1;
}
fm.fmt.pix.width = c->width; // 640
fm.fmt.pix.height = c->height; // 480
fm.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
fm.fmt.pix.field = V4L2_FIELD_ANY;
fm.fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
if (c->fm != V4L2_PIX_FMT_MJPEG) {
unsigned int min = fm.fmt.pix.width * 2;
if (fm.fmt.pix.bytesperline < min) {
fm.fmt.pix.bytesperline = min;
}
min = fm.fmt.pix.bytesperline * fm.fmt.pix.height;
if (fm.fmt.pix.sizeimage < min) {
fm.fmt.pix.sizeimage = min;
}
} else {
fm.fmt.pix.bytesperline = 0;
fm.fmt.pix.sizeimage = 0;
}
r = xioctl(c->fd, VIDIOC_S_FMT, &fm);
对于每个退出队列的缓冲区,数据都是相同的
是C270或V4L2有问题还是我的代码有问题?
有人遇到过类似的问题吗?好的,通过查看内核日志,我似乎找到了问题的根源:
adb shell sudo echo 8 > /proc/sys/kernel/printk
adb >/tmp/adb_klog.txt 2>/tmp/adb_klog.txt shell sudo cat /proc/kmsg
命令。看起来VIDIOC_G_FMT在没有向用户land ioctl()调用报告错误的情况下,四个摄像头中有一个或两个出现故障:
在内核日志中进一步研究后:usb 1-2.2.1.2:link qh16-0001/ca5bf1c0 start 1[1/0 us]uvcvideo:uvc_v4l2_ioctl(VIDIOC_G_FMT)uvcvideo:uvc_v4l2_ioctl(VIDIOC_FMT)uvcvideo:尝试格式0x47504a4d(MJPG):640x480。uvcvideo:使用默认帧间隔33333.3us(30.0fps)。usb 1-2.2.1.2:ep0out len=0/26 uvcvideo上超时:无法设置UVC探头控制:-110(实验26)。uvcvideo:uvc_v4l2_ioctl(视频IOC_G_FMT)uvcvideo:uvc_v4l2_ioctl(视频IOC_日志_状态)uvcvideo:Unknown ioctl 0x00005646,不向应用程序报告任何视频IOC_FMT故障。
missing FFD8 tag 0x688fb000 bytes=6946 length=213333
0x688fb000: AB 74 10 0C EE FD 34 FB B3 FA 3E D1 60 9D 33 B0 ?t????4???>?`?3?
0x688fb010: F1 83 7B 8A AF B8 F9 BF EF 33 EE FF 89 91 7F 9F ??{??????3?????
0x688fb020: 47 EF A4 B9 73 1C BC FB AD 46 6A D5 22 A2 2C 32 G???s????Fj?"?,2
0x688fb030: 2B A8 71 7E 56 56 73 23 15 7B 11 B2 F0 FA AA D3 +?q~VVs#?{??????
.............
0x688fcae2: 00 A2 80 0A 28 03 FF D5 C6 A2 80 0A 28 00 A2 80 ????(???????(???
0x688fcaf2: 0A 28 00 A2 80 0A 28 00 A2 80 0A 28 00 A2 80 0A ?(????(????(????
0x688fcb02: 28 03 FF D6 C6 A2 80 0A 28 00 A2 80 0A 28 00 A2 (???????(????(??
0x688fcb12: 80 0A 28 00 A2 80 0A 28 00 A2 80 0A 28 03 FF D9 ??(????(????(???
adb shell sudo echo 8 > /proc/sys/kernel/printk
adb >/tmp/adb_klog.txt 2>/tmp/adb_klog.txt shell sudo cat /proc/kmsg
<7>[ 7274.495178] uvcvideo: uvc_v4l2_open
<7>[ 7274.495239] ehci-omap ehci-omap.0: reused qh ca5bf1c0 schedule
<7>[ 7274.495269] usb 1-2.2.1.2: link qh16-0001/ca5bf1c0 start 1 [1/0 us]
<7>[ 7274.495330] uvcvideo: uvc_v4l2_ioctl(VIDIOC_G_FMT)
<7>[ 7274.495452] uvcvideo: uvc_v4l2_ioctl(VIDIOC_S_FMT)
<7>[ 7274.495483] uvcvideo: Trying format 0x47504a4d (MJPG): 640x480.
<7>[ 7274.495513] uvcvideo: Using default frame interval 33333.3 us (30.0 fps).
<7>[ 7279.495208] usb 1-2.2.1.2: .<process_name> timed out on ep0out len=0/26
<3>[ 7279.495239] uvcvideo: Failed to set UVC probe control : -110 (exp. 26).
<7>[ 7279.502746] uvcvideo: uvc_v4l2_ioctl(VIDIOC_G_FMT)
<7>[ 7279.507080] uvcvideo: uvc_v4l2_ioctl(VIDIOC_LOG_STATUS)
<7>[ 7279.507080] uvcvideo: Unknown ioctl 0x00005646
static bool has_bad_frames(camera_t* camera) {
/* Logitech C270 randomly spits corrupted MJPEGs after power cycle. Known workaround is to reopen camera */
camera_t_* c = (camera_t_*)camera;
camera_set_callback(c, empty_callback); // otherwise MJPEG frames are not going to be decompressed
camera_start(camera);
int retry = 300; // 3 seconds max
while (retry > 0 && c->good_frames == 0 && c->bad_frames == 0) {
nsleep(NANOSECONDS_IN_SECOND / 100); /* 1/100 second */
retry--;
}
bool ok = c->bad_frames == 0 && c->good_frames > 0;
camera_stop(camera);
return !ok;
}
int camera_open(void* that, camera_t* o, int id, int w, int h, int bpp) {
int r = try_to_open(that, o, id, w, h, bpp);
if (r == 0) {
if (has_bad_frames(*o)) {
camera_t_* c = (camera_t_*)*o;
if (c->bad_frames + c->good_frames == 0) {
trace("%s is not streaming; retrying...", c->name);
} else {
trace("%s spits corrupted frames. Probable VIDIOC_S_FMT silently failed; retrying...", c->name);
}
camera_close(*o);
*o = null;
return try_to_open(that, o, id, w, h, bpp);
}
}
return r;
}