分享下debug uvccamera/libuvc这些so库遇到的卡死崩溃问题和思路
1.UVCCamera执行stopPreview或release时阻塞卡死
在多次重复打开关闭uvc摄像头的时候,上层调用stopPreview/release会概率性卡死,经过调试一步步定位调用函数和阻塞住的位置
android java层调用略,下面直接从so库的代码开始;
–>
UVCCamera/UVCCamera.cpp-stopPreview()
–>
UVCCamera/UVCPreView.cpp-stopPreview()
这里设置mIsRunning = false;停止预览帧处理;
调试发现,在下面这一句代码阻塞住没有往下走了:
pthread_join(preview_thread, NULL) != EXIT_SUCCESS;
pthread_join会阻塞到preview_thread预览线程执行结束为止,所以预览处理没有正常结束;
–>
UVCCamera/UVCPreview.cpp-do_preview()
结束预览时会停止libuvc的流处理uvc_stop_streaming(mDeviceHandle);,所以流处理没有正常结束;
–>
libuvc/stream.c-uvc_stop_streaming()
–>
libuvc/stream.c-uvc_stream_close()
–>
libuvc/stream.c-uvc_stream_stop()
这一步停止流的传输,并将所有流转换器都释放掉:
strmh->running = 0;并遍历调用libusb_cancel_transfer(strmh->transfers[i]);
至于关键的阻塞代码如下:
1 |
|
这里会一直循环等待所有流转换器都释放置空完成,而问题就在于偏偏有个别流转换器就是无法正常释放。
为什么没有正常释放完成,
是因为libusb_cancel_transfer失败返回LIBUSB_ERROR_NOT_FOUND的状态时,
转换器持有无效的buffer和指针,导致上面的循环代码一直不往下走。
一般释放正常时的Log如下:
1 |
|
但函数阻塞住时,我发现并没有看到index为6的transfer执行delete的Log,于是我怀疑是否跟transfer的数量有关。
这时查看源码里有一个transfer buffers的数量定义如下:
1 |
|
如果设置得太高,不仅会提高内存的占用,在处理速度慢的板子上也会有transfer浪费掉。
这里我尝试降低数量值为5,再次调试开关100次,stopPreview卡死的问题不再复现。
2.JNI DETECTED ERROR IN APPLICATION: jmethodID was NULL 空指针
由于java上层设置setFrameCallback(null, 0); iframecallback_fields.onFrame在另外一个线程被置为NULL
而以下这段代码没有判空,导致的空指针:
env->CallVoidMethod(mFrameCallbackObj, iframecallback_fields.onFrame, buf);
解决方法为增加空指针判断如下
1 |
|
3.UVCCamera could not open camera:err=-99
要检查打开的usb设备是否已经被其他进程打开了/其他进程持有没释放/打开的是不是UVC摄像头,是否打开了错误的其他usb设备
4.其他一些别人发现的bug和修复方法
https://github.com/saki4510t/UVCCamera/pull/520
https://github.com/saki4510t/UVCCamera/pull/328