ndk实例总结补充:使用libuvc采集usb图像分析

ndk实例总结补充:使⽤libuvc采集usb图像分析
ndk实例总结补充
ndk实例总结:jni实例
ndk实例总结:opencv图像处理
ndk实例总结:安卓Camera与usbCamera原始图像处理
ndk实例总结补充:使⽤V4L2采集usb图像分析
ndk实例总结:使⽤fmpeg播放rtsp流
ndk实例总结:基于libuvc的双usbCamera处理
ndk实例总结补充:使⽤libuvc采集usb图像分析
ndk实例总结:jni⽇志存储
前⾔
<
本⽂是对ndk实例总结:基于libuvc的双usbCamera处理中jni部分的补充,主要分析下使⽤libuvc采集usb图像的流程
libuvc介绍
libuvc是⽤于USB视频设备的跨平台库,⽀持USB Video Class(UVC)设备(例如⽤户⽹络摄像头)的枚举,控制和流传输
有以下特性:
UVC设备发现和管理API
具有异步/回调和同步/轮询模式的视频流(从设备到主机)
对标准设备设置的读/写访问
各种格式之间的转换:RGB,YUV,JPEG等
代码实现分析加工pcb板
这⾥分析下ndk实例总结:基于libuvc的双usbCamera处理中的jni代码,主要是摄像头的打开关闭,预
览与拍照,以及更改摄像头参数
初始化摄像头
⾸先是初始化摄像头
int connect(int index, int vid, int pid, int fd, int busNum, int devAddr, std::string c_usbfs) {
uvc_error_t res = uvc_init2(&ctx[index], NULL, c_usbfs.c_str());
if (res < 0) {
LOGE("connect uvc_init2 error, res %d, index %d", res, index);
return JNI_ERR;
}
LOGI("connect UVC initialized, index %d", index);
res = uvc_get_device_with_fd(ctx[index], &dev[index], vid, pid, NULL, fd, busNum, devAddr);
if (res < 0) {
LOGE("connect uvc_get_device_with_fd error, res %d , index %d", res, index);
//        close(fd);
return JNI_ERR;
} else {
LOGI("connect Device found, index %d", index);
res = uvc_open(dev[index], &devh[index]);
if (res < 0) {
LOGE("connect uvc_open error, res %d, index %d", res, index);
uvc_unref_device(dev[index]);
dev[index] = nullptr;
devh[index] = nullptr;
//            close(fd);
::fd[index] = 0;
return JNI_ERR;
} else {
LOGI("connect Device opened, index %d", index);
}
}
手机背光源
if (res == 0) {
::fd[index] = fd;
is_connect[index] = true;
}
res = start_stream(index);
LOGI("connect, res %d, index %d", res, index);
return res;
}
初始化摄像头主要关注三个核⼼⽅法:uvc_init2、uvc_get_device_with_fd、uvc_open
uvc_init2是UVCCamera中特有的函数,在libuvc本⾝的uvc_init基础上加上了usbfs参数来实现uvc context的初始化
uvc_get_device_with_fd也是UVCCamera特有的函数,作⽤是获取通过vid、pid、fd、busNum、devAddr这些信息来标识的摄像头uvc_open就是打开摄像头
打开视频流
打开摄像头成功后,就需要设置视频流参数和打开视频流了
uvc_error_t start_stream(int index) {
uvc_error_t res = uvc_get_stream_ctrl_format_size_fps(
devh[index], &ctrl[index], UVC_FRAME_FORMAT_MJPEG, IMG_WIDTH, IMG_HEIGHT, 1, 30);
LOGI("start_stream, stream_mode %d, index %d", stream_mode, index);
if (res < 0) {
LOGE("start_stream uvc_get_stream_ctrl_format_size_fps error, res %d, index %d", res,
index);
return res;
}
if (stream_mode) {
res = uvc_stream_open_ctrl(devh[index], &strmhp[index], &ctrl[index]);
LOGI("start_stream uvc_stream_open_ctrl, res %d, index %d", res, index);
res = uvc_stream_start_bandwidth(strmhp[index], NULL, NULL, 0.49, 0);
LOGI("start_stream uvc_stream_start_bandwidth, res %d, index %d", res, index);
uvc_frame_t *frame;
res = uvc_stream_get_frame(strmhp[index], &frame, 50 * 1000);
LOGI("start_stream uvc_stream_get_frame, res %d, frame %p, index %d", res, frame, index);
} else {
res = uvc_start_streaming_bandwidth(
devh[index], &ctrl[index], uvc_preview_frame_callback, (int *) index, 0.49, 0);
LOGI("start_stream uvc_start_streaming_bandwidth, res %d, index %d", res, index);
}
if (res == 0) {
is_start_stream[index] = true;
} else {
LOGE("start_stream error, res %d, index %d", res, index);
}
return res;
}
uvc_get_stream_ctrl_format_size_fps也是UVCCamera特有的函数,作⽤是与摄像头协商视频流的图像帧的格式、宽⾼,与libuvc本⾝的uvc_get_stream_ctrl_format_size函数相⽐多了最⼩和最⼤帧率参数
libuvc本⾝⽀持两种获取视频流的⽅式,⼀种是异步回调⽅式,另⼀种是主动轮询⽅式
主动轮询⽅式需要先调⽤uvc_stream_open_ctrl函数后再调⽤uvc_stream_start_bandwidth函数,uvc
_stream_start_bandwidth不需要传⼊callback函数和⽤户指针,使⽤uvc_stream_get_frame函数来获取⼀帧图像
异步回调⽅式需要调⽤uvc_start_streaming_bandwidth函数,在第三个参数中传⼊callback函数和⽤户指针(区分多个摄像头)
void uvc_preview_frame_callback(uvc_frame_t *frame, void *ptr) {
int index = (int) ptr;
_mutex[index].lock();
if (data_list[index].size() >= 2) {
uvc_frame_t *front = data_list[index].front();
uvc_free_frame(front);
data_list[index].pop_front();
}
uvc_frame_t *copy = uvc_allocate_frame(frame->data_bytes);
uvc_duplicate_frame(frame, copy);
data_list[index].push_back(copy);
_mutex[index].unlock();
}
这样摄像头的每帧图像就会通过这个回调来提供,在这个回调中将图像复制⼀帧后放⼊缓冲队列⾥,作为缓冲帧
获取视频帧
打开视频流后就能获取视频帧了,同样也是异步与同步两种⽅式
int get_frame(uvc_frame_t *rgb565, int index) {
if (stream_mode) {
uvc_frame_t *frame;
uvc_error_t res;
_mutex[index].lock();
res = uvc_stream_get_frame(strmhp[index], &frame, 50 * 1000);
if (res || !frame) {
_mutex[index].unlock();
uvc_perror(res, "get_frame uvc_stream_get_frame error");
LOGE("get_frame uvc_stream_get_frame error, res %d, frame %p, index %d", res, frame,
index);
return -1;
}
uvc_frame_t *copy = uvc_allocate_frame(frame->data_bytes);
uvc_duplicate_frame(frame, copy);巴特沃斯滤波器
_mutex[index].unlock();
res = uvc_mjpeg2rgb565(copy, rgb565);
if (res) {
uvc_perror(res, "get_frame uvc_mjpeg2rgb565 error");
LOGE("get_frame uvc_mjpeg2rgb565 error, res %d, index %d", res, index);
uvc_free_frame(copy);
return -1;
}
uvc_free_frame(copy);
} else {
_mutex[index].lock();
if (data_list[index].empty()) {
_mutex[index].unlock();
return -1;
服务器硬件检测
}
uvc_frame_t *front = data_list[index].front();
data_list[index].pop_front();
_mutex[index].unlock();
uvc_error_t res;
res = uvc_mjpeg2rgb565(front, rgb565);
if (res) {
uvc_perror(res, "get_frame uvc_mjpeg2rgb565 error");
LOGE("get_frame uvc_mjpeg2rgb565 error, res %d, index %d", res, index);
uvc_free_frame(front);
return -1;
}
uvc_free_frame(front);
}
return 0;
}
同步⽅式通过uvc_stream_get_frame函数获取⼀帧图像,然后复制帧,转成rgb565格式(Android 预览使⽤)异步⽅式直接从缓冲队列⾥取出第⼀帧,直接转成rgb565格式
拍照
拍照的流程和获取视频帧类似,区别只是不转成rgb565格式,⽽是直接将视频帧保存成jpg⽂件存在本地
bool take_photo(int index, std::string path) {
if (!is_start_stream[index]) {
LOGE("take photo error, not start_stream, index %d", index);
return false;
}
uvc_frame_t *copy;
_mutex[index].lock();
if (stream_mode) {
uvc_frame_t *frame;
uvc_frame_t *frame_test;
uvc_error_t res = uvc_stream_get_frame(strmhp[index], &frame, 50 * 1000);
数据监控
uvc_error_t res_test = uvc_stream_get_frame(strmhp[index], &frame_test, 50 * 1000);
if (res || res_test || !frame || !frame_test) {
_mutex[index].unlock();
uvc_perror(res, "take_photo uvc_stream_get_frame error");
LOGE("take_photo uvc_stream_get_frame error, res %d, frame %p, frame_test %p, index %d",
res, frame, frame_test, index);
return false;
}
copy = uvc_allocate_frame(frame->data_bytes);
uvc_duplicate_frame(frame, copy);
} else {
if (data_list[index].empty()) {
_mutex[index].unlock();
LOGE("take_photo error, data_list empty, index %d", index);
return false;
}
uvc_frame_t *frame = data_list[index].back();
copy = uvc_allocate_frame(frame->data_bytes);
uvc_duplicate_frame(frame, copy);
}
_mutex[index].unlock();
unsigned char *buf = (unsigned char *) copy->data;
store_MJPG_image(path.c_str(), buf, copy->data_bytes);
uvc_free_frame(copy);
return true;
设置摄像头参数
设置摄像头参数使⽤的都是libuvc⾃⼰的api,这⾥实现了曝光⽅式、曝光时间、增益和亮度,其他参数可以⾃⾏参考⽂档libuvc

本文发布于:2024-09-23 13:17:22,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/1/138706.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:摄像头   参数   图像   视频流   实例   设置
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议