4 * Copyright (c) 2022 - 2023 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * Most of code is from hal_camera_v4l2
31 #include <linux/videodev2.h>
32 #include <media_packet.h>
35 #include <vision_source_interface.h>
41 #define LOG_TAG "VISION_SOURCE_V4L2"
45 #include <sys/ioctl.h>
48 #define v4l2_fd_open(fd, flags) (fd)
49 #define v4l2_close close
51 #define v4l2_ioctl ioctl
52 #define v4l2_read read
53 #define v4l2_mmap mmap
54 #define v4l2_munmap munmap
55 #endif /* ENABLE_LIBV4L2 */
57 #define VISION_SOURCE_CHECK_CONDITION(condition, error, msg) \
60 LOGE("[%s] %s(0x%08x)", __FUNCTION__, msg, error); \
65 #define VISION_SOURCE_NULL_ARG_CHECK(arg) \
66 VISION_SOURCE_CHECK_CONDITION(arg != NULL, VISION_SOURCE_ERROR_INVALID_PARAMETER, \
67 "VISION_SOURCE_ERROR_INVALID_PARAMETER")
69 #define VISION_SOURCE_INITIAL_FD -1
72 #define DEVICE_NODE_PATH_PREFIX "/dev/video"
73 #define FOURCC_FORMAT "%c%c%c%c"
74 #define FOURCC_CONVERT(fourcc) fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff
77 #define vision_source_init vision_source_v4l2_init
78 #define vision_source_exit vision_source_v4l2_exit
79 #define vision_source_list_devices vision_source_v4l2_list_devices
80 #define vision_source_list_device_caps vision_source_v4l2_list_device_caps
81 #define vision_source_open_device vision_source_v4l2_open_device
82 #define vision_source_close_device vision_source_v4l2_close_device
83 #define vision_source_set_stream_format vision_source_v4l2_set_stream_format
84 #define vision_source_start_stream vision_source_v4l2_start_stream
85 #define vision_source_stop_stream vision_source_v4l2_stop_stream
86 #define vision_source_set_stream_cb vision_source_v4l2_set_stream_cb
88 #include <vision_source.h>
94 media_format_mimetype_e type;
99 bool operator==(const fmt_info &rhs)
101 return (type == rhs.type) && (width == rhs.width) && (height == rhs.height) && (fps == rhs.fps);
105 struct pkt_dispose_cb_data {
110 struct vision_source_v4l2_s {
112 vision_source_device_info_s *dev_info {};
113 media_format_h **fmt {};
114 vector<string> dev_name {};
115 vector<vector<fmt_info> > fmt_list {};
117 /* current user setting */
118 int device_index = VISION_SOURCE_INITIAL_FD;
119 int device_fd = VISION_SOURCE_INITIAL_FD;
120 int fmt_index = VISION_SOURCE_INITIAL_FD;
121 vision_source_status_e status;
124 vector<v4l2_buffer> v4l2_buf {};
125 vector<void *> mmap_addr {};
126 struct pkt_dispose_cb_data pkt_data[BUFFER_MAX];
129 thread buffer_thread;
130 atomic_bool buffer_thread_run {};
131 stream_cb stream_callback {};
132 void *stream_user_data {};
135 static int __vision_source_get_format(uint32_t fourcc, int *pixel_format)
138 case V4L2_PIX_FMT_RGB24:
139 *pixel_format = MEDIA_FORMAT_RGB888;
141 case V4L2_PIX_FMT_YUYV:
142 *pixel_format = MEDIA_FORMAT_YUYV;
144 case V4L2_PIX_FMT_NV12:
145 *pixel_format = MEDIA_FORMAT_NV12;
147 case V4L2_PIX_FMT_NV21:
148 *pixel_format = MEDIA_FORMAT_NV21;
151 LOGW("unknown fourcc " FOURCC_FORMAT, FOURCC_CONVERT(fourcc));
152 return VISION_SOURCE_ERROR_NOT_SUPPORTED_FORMAT;
155 LOGD("fourcc " FOURCC_FORMAT " -> %d", FOURCC_CONVERT(fourcc), *pixel_format);
157 return VISION_SOURCE_ERROR_NONE;
160 static int __vision_source_get_fourcc_plane_num(media_format_mimetype_e pixel_format, uint32_t *fourcc)
162 switch (pixel_format) {
163 case MEDIA_FORMAT_RGB888:
164 *fourcc = V4L2_PIX_FMT_RGB24;
166 case MEDIA_FORMAT_YUYV:
167 *fourcc = V4L2_PIX_FMT_YUYV;
169 case MEDIA_FORMAT_NV12:
170 *fourcc = V4L2_PIX_FMT_NV12;
172 case MEDIA_FORMAT_NV21:
173 *fourcc = V4L2_PIX_FMT_NV21;
176 LOGE("unknown format %d", pixel_format);
177 return VISION_SOURCE_ERROR_INTERNAL;
180 LOGD("format %d -> fourcc " FOURCC_FORMAT, pixel_format, FOURCC_CONVERT(*fourcc));
182 return VISION_SOURCE_ERROR_NONE;
185 static vector<uint32_t> __vision_source_get_fps_list(int device_fd, uint32_t pixel_format, int width, int height)
187 vector<uint32_t> fps_list;
188 struct v4l2_frmivalenum ival;
191 ival.pixel_format = pixel_format;
193 ival.height = height;
195 if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {
196 LOGE("VIDIOC_ENUM_FRAMEINTERVALS failed[%d]", errno);
200 if (ival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
201 LOGE("NOT V4L2_FRMIVAL_TYPE_DISCRETE -> [%u]", ival.type);
206 LOGI("\t\t\t\tFramerate[%u/%u]", ival.discrete.denominator, ival.discrete.numerator);
207 fps_list.push_back(ival.discrete.denominator);
209 } while (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
214 static int __vision_source_v4l2_qbuf(int device_fd, int type, int memory, int index)
216 struct v4l2_buffer v4l2_buf;
218 memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
220 v4l2_buf.index = index;
221 v4l2_buf.type = type;
222 v4l2_buf.memory = memory;
224 if (v4l2_ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
225 LOGE("qbuf failed. [i: %d, t: %d, m: %d] errno %d", index, type, memory, errno);
226 return VISION_SOURCE_ERROR_INTERNAL;
229 // LOGD("QBUF done [i: %d, t: %d, m: %d]", index, type, memory);
231 return VISION_SOURCE_ERROR_NONE;
234 static int __vision_source_get_valid_fmt(int device_fd, vector<fmt_info> &found_fmt)
236 int pixel_format = 0;
241 struct v4l2_fmtdesc v4l2_format;
242 memset(&v4l2_format, 0x0, sizeof(struct v4l2_fmtdesc));
244 v4l2_format.index = pixel_index;
245 v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
247 if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FMT, &v4l2_format) < 0) {
248 LOGW("\tformat : end of enumeration");
252 LOGD("\tformat[%d] " FOURCC_FORMAT " (emulated:%d)", pixel_index, FOURCC_CONVERT(v4l2_format.pixelformat),
253 ((v4l2_format.flags & V4L2_FMT_FLAG_EMULATED) ? 1 : 0));
255 if (__vision_source_get_format(v4l2_format.pixelformat, &pixel_format) != VISION_SOURCE_ERROR_NONE) {
260 int resolution_index = 0;
261 int resolution_count = 0;
264 struct v4l2_frmsizeenum v4l2_frame;
265 memset(&v4l2_frame, 0x0, sizeof(struct v4l2_frmsizeenum));
267 v4l2_frame.index = resolution_index;
268 v4l2_frame.pixel_format = v4l2_format.pixelformat;
270 if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMESIZES, &v4l2_frame) < 0) {
271 LOGW("\t\tframe : end of enumeration ");
275 // TODO : support other type
276 if (v4l2_frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
277 LOGW("\t\tframe type %d needs to support", v4l2_frame.type);
278 return VISION_SOURCE_ERROR_NONE;
281 uint32_t width = v4l2_frame.discrete.width;
282 uint32_t height = v4l2_frame.discrete.height;
284 LOGD("\t\tsize[%d] %ux%u", resolution_index, width, height);
286 auto fps_list = __vision_source_get_fps_list(device_fd, v4l2_frame.pixel_format, width, height);
287 if (fps_list.empty()) {
288 return VISION_SOURCE_ERROR_NOT_SUPPORTED_FORMAT;
293 for (auto fps : fps_list) {
294 fmt_info fmt { (media_format_mimetype_e) pixel_format, width, height, fps };
295 found_fmt.push_back(fmt);
299 LOGD("\t\tresolution count [%d]", resolution_count);
304 LOGD("\tformat count [%d]", pixel_count);
306 return VISION_SOURCE_ERROR_NONE;
309 static int __dev_info_from_path(const char *path, vector<fmt_info> &fmt_list)
311 LOGD("check device [%s]", path);
312 int ret = VISION_SOURCE_ERROR_NONE;
314 int device_fd = open(path, O_RDWR);
316 LOGE("open failed [%s] errno %d", path, errno);
321 int libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
323 LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
326 device_fd = libv4l2_fd;
327 #endif /* HAVE_LIBV4L2 */
329 struct v4l2_capability v4l2_cap;
330 memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
332 if (v4l2_ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
333 LOGE("querycap failed. errno %d", errno);
334 v4l2_close(device_fd);
338 unsigned int dev_caps;
340 if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
341 dev_caps = v4l2_cap.device_caps;
343 dev_caps = v4l2_cap.capabilities;
345 if (!(dev_caps & V4L2_CAP_VIDEO_CAPTURE) || (dev_caps & V4L2_CAP_VIDEO_OUTPUT)) {
346 LOGW("[%s] is not a capture device 0x%x", path, dev_caps);
347 v4l2_close(device_fd);
351 ret = __vision_source_get_valid_fmt(device_fd, fmt_list);
353 v4l2_close(device_fd);
357 static int __vision_source_list_devices(vision_source_v4l2_s *vs_handle)
360 memset(&glob_buf, 0x0, sizeof(glob_t));
361 int ret = glob(DEVICE_NODE_PATH_PREFIX "*", 0, 0, &glob_buf);
365 LOGE("out of memory");
366 return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
369 return VISION_SOURCE_ERROR_INTERNAL;
371 LOGE("match not found");
372 return VISION_SOURCE_ERROR_NO_DATA;
376 LOGD("device node count : %zu", glob_buf.gl_pathc);
378 vector<string> &dev_name = vs_handle->dev_name;
379 vector<vector<fmt_info> > &dev_fmt_list = vs_handle->fmt_list;
381 for (size_t i = 0; i < glob_buf.gl_pathc; i++) {
382 vector<fmt_info> fmt_list;
383 ret = __dev_info_from_path(glob_buf.gl_pathv[i], fmt_list);
384 if (ret != VISION_SOURCE_ERROR_NONE) {
388 if (!fmt_list.empty()) {
389 dev_name.push_back(glob_buf.gl_pathv[i]);
390 dev_fmt_list.push_back(fmt_list);
395 if (dev_name.empty())
398 size_t dev_count = dev_name.size();
400 vs_handle->dev_info = (vision_source_device_info_s *) calloc(dev_count, sizeof(vision_source_device_info_s));
401 if (!vs_handle->dev_info) {
402 return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
405 vs_handle->fmt = (media_format_h **) calloc(dev_count, sizeof(media_format_h *));
406 if (!vs_handle->fmt) {
407 return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
410 for (size_t i = 0; i < dev_count; i++) {
411 vs_handle->dev_info[i].index = i;
412 strncpy(vs_handle->dev_info[i].name, dev_name[i].c_str(), DEVICE_NAME_LENGTH_MAX);
413 vs_handle->fmt[i] = (media_format_h *) calloc(dev_fmt_list[i].size(), sizeof(media_format_h));
414 if (!vs_handle->fmt[i]) {
415 return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
418 for (size_t j = 0; j < dev_fmt_list[i].size(); j++) {
420 media_format_create(&fmt);
421 media_format_set_video_mime(fmt, dev_fmt_list[i][j].type);
422 media_format_set_video_width(fmt, dev_fmt_list[i][j].width);
423 media_format_set_video_height(fmt, dev_fmt_list[i][j].height);
424 media_format_set_video_frame_rate(fmt, dev_fmt_list[i][j].fps);
425 vs_handle->fmt[i][j] = fmt;
432 static int __vision_source_v4l2_stream(int device_fd, int type, bool onoff)
434 if (v4l2_ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type) < 0) {
435 LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno);
436 return VISION_SOURCE_ERROR_INTERNAL;
439 LOGD("stream %d (1:on, 0:off) done [t:%d]", onoff, type);
441 return VISION_SOURCE_ERROR_NONE;
444 static int __vision_source_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t count, uint32_t *result_count)
446 struct v4l2_requestbuffers v4l2_reqbuf;
448 memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers));
450 v4l2_reqbuf.type = type;
451 v4l2_reqbuf.memory = memory;
452 v4l2_reqbuf.count = count;
454 if (v4l2_ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) {
455 LOGE("REQBUFS[count %d] failed. errno %d", count, errno);
456 return VISION_SOURCE_ERROR_INTERNAL;
459 if (v4l2_reqbuf.count != count) {
460 LOGE("different count [req:%d, result:%d]", count, v4l2_reqbuf.count);
461 return VISION_SOURCE_ERROR_INTERNAL;
464 *result_count = v4l2_reqbuf.count;
466 return VISION_SOURCE_ERROR_NONE;
469 static int __vision_source_stop_stream(vision_source_v4l2_s *handle)
471 LOGD("__vision_source_stop_stream");
474 int ret = __vision_source_v4l2_stream(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, false);
477 for (size_t i = 0; i < handle->mmap_addr.size(); i++) {
478 v4l2_munmap(handle->mmap_addr[i], handle->v4l2_buf[i].length);
480 handle->v4l2_buf.clear();
481 handle->mmap_addr.clear();
484 uint32_t buffer_count;
485 ret = __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, 0,
488 LOGD("reqbufs 0 : 0x%x", ret);
493 static int __vision_source_set_stream(vision_source_v4l2_s *handle)
495 fmt_info &fmt = handle->fmt_list[handle->device_index][handle->fmt_index];
496 struct v4l2_format v4l2_fmt;
498 unsigned int fourcc = 0;
500 int ret = __vision_source_get_fourcc_plane_num(fmt.type, &fourcc);
501 if (ret != VISION_SOURCE_ERROR_NONE)
504 memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
506 v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
507 v4l2_fmt.fmt.pix.width = fmt.width;
508 v4l2_fmt.fmt.pix.height = fmt.height;
509 v4l2_fmt.fmt.pix.pixelformat = fourcc;
511 if (v4l2_ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
512 LOGE("S_FMT failed. errno %d", errno);
513 return VISION_SOURCE_ERROR_INTERNAL;
516 struct v4l2_streamparm v4l2_parm;
518 memset(&v4l2_parm, 0x0, sizeof(struct v4l2_streamparm));
520 v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
521 if (v4l2_ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) {
522 LOGE("G_PARM failed. errno %d", errno);
523 return VISION_SOURCE_ERROR_INTERNAL;
526 /* S_PARM to set fps */
527 v4l2_parm.parm.capture.timeperframe.numerator = 1;
528 v4l2_parm.parm.capture.timeperframe.denominator = fmt.fps;
530 if (v4l2_ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) {
531 LOGE("S_PARM failed. errno %d", errno);
532 return VISION_SOURCE_ERROR_INTERNAL;
535 return VISION_SOURCE_ERROR_NONE;
538 static int __vision_source_v4l2_dqbuf(int device_fd, int type, int memory, int *index, unsigned int *used_size)
540 struct v4l2_buffer v4l2_buf;
541 memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
543 v4l2_buf.type = type;
544 v4l2_buf.memory = memory;
546 int ret = v4l2_ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
549 LOGE("dqbuf failed. [t: %d, m: %d] errno %d", type, memory, ret);
551 LOGE("EIO is internal hw error");
553 return VISION_SOURCE_ERROR_INTERNAL;
556 *index = v4l2_buf.index;
557 *used_size = v4l2_buf.bytesused;
562 static int __vision_source_v4l2_wait_frame(int device_fd, int wait_time)
566 FD_SET(device_fd, &fds);
568 struct timeval timeout;
569 memset(&timeout, 0x0, sizeof(struct timeval));
571 timeout.tv_sec = wait_time;
574 /*LOGD("select : %d sec", wait_time);*/
576 int ret = select(device_fd + 1, &fds, NULL, NULL, &timeout);
580 LOGD("select error : EINTR");
581 return VISION_SOURCE_ERROR_NONE;
583 LOGE("select failed. errno %d", ret);
584 return VISION_SOURCE_ERROR_INTERNAL;
587 LOGE("select timeout.");
588 return VISION_SOURCE_ERROR_INTERNAL;
591 return VISION_SOURCE_ERROR_NONE;
594 static int __vision_source_mmap(vision_source_v4l2_s *handle)
596 /* query buffer, mmap and qbuf */
597 for (int i = 0; i < BUFFER_MAX; i++) {
598 struct v4l2_buffer v4l2_buf;
599 memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
601 v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
602 v4l2_buf.memory = V4L2_MEMORY_MMAP;
605 if (v4l2_ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
606 LOGE("[%d] query buf failed. errno %d", i, errno);
607 return VISION_SOURCE_ERROR_INTERNAL;
610 handle->v4l2_buf.push_back(v4l2_buf);
613 v4l2_mmap(0, v4l2_buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, handle->device_fd, v4l2_buf.m.offset);
615 if (data == MAP_FAILED) {
616 LOGE("[%d] mmap failed (errno %d)", i, errno);
617 return VISION_SOURCE_ERROR_INTERNAL;
620 handle->mmap_addr.push_back(data);
622 if (__vision_source_v4l2_qbuf(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, i) !=
623 VISION_SOURCE_ERROR_NONE) {
624 LOGE("[%d] qbuf failed (errno %d)", i, errno);
625 return VISION_SOURCE_ERROR_INTERNAL;
630 return __vision_source_v4l2_stream(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, true);
633 static int __vision_source_start_stream(vision_source_v4l2_s *handle)
635 uint32_t buffer_count = 0;
637 int ret = __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, BUFFER_MAX,
639 if (ret != VISION_SOURCE_ERROR_NONE) {
643 LOGD("buffer count : request %d -> result %d", BUFFER_MAX, buffer_count);
645 ret = __vision_source_mmap(handle);
646 if (ret != VISION_SOURCE_ERROR_NONE)
647 __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, 0,
653 int vision_source_init(vision_source_h *handle)
655 vision_source_v4l2_s *v4l2_handle = new vision_source_v4l2_s;
657 int ret = __vision_source_list_devices(v4l2_handle);
658 if (ret != VISION_SOURCE_ERROR_NONE) {
660 LOGE("get device info failed");
664 v4l2_handle->status = VISION_SOURCE_STATUS_INITIALIZED;
665 *handle = v4l2_handle;
667 return VISION_SOURCE_ERROR_NONE;
670 static void __vision_source_release_handle(vision_source_v4l2_s *handle)
672 for (size_t i = 0; i < handle->fmt_list.size(); i++) {
673 for (size_t j = 0; j < handle->fmt_list[i].size(); j++) {
674 media_format_unref(handle->fmt[i][j]);
676 free(handle->fmt[i]);
679 free(handle->dev_info);
681 LOGD("vision_source_v4l2_s %p destroy", handle);
686 int vision_source_exit(vision_source_h handle)
688 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
690 if (v4l2_handle->dev_info)
691 __vision_source_release_handle(v4l2_handle);
694 return VISION_SOURCE_ERROR_NONE;
697 int vision_source_list_devices(vision_source_h handle, const vision_source_device_info_s **dev_list, int *dev_count)
699 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
701 *dev_list = v4l2_handle->dev_info;
702 *dev_count = v4l2_handle->dev_name.size();
704 return VISION_SOURCE_ERROR_NONE;
707 int vision_source_list_device_caps(vision_source_h handle, int dev_index, const media_format_h **fmt_list,
710 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
712 if (dev_index < 0 || (size_t) dev_index >= v4l2_handle->fmt_list.size())
713 return VISION_SOURCE_ERROR_INVALID_PARAMETER;
715 *fmt_list = v4l2_handle->fmt[dev_index];
716 *fmt_count = v4l2_handle->fmt_list[dev_index].size();
718 return VISION_SOURCE_ERROR_NONE;
721 int vision_source_open_device(vision_source_h handle, int dev_index)
723 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
725 if (v4l2_handle->status != VISION_SOURCE_STATUS_INITIALIZED) {
726 return VISION_SOURCE_ERROR_INVALID_OPERATION;
729 if (dev_index < 0 || (size_t) dev_index >= v4l2_handle->fmt_list.size())
730 return VISION_SOURCE_ERROR_INVALID_PARAMETER;
732 int device_fd = VISION_SOURCE_INITIAL_FD;
734 int libv4l2_fd = VISION_SOURCE_INITIAL_FD;
735 #endif /* HAVE_LIBV4L2 */
737 char *node_path = v4l2_handle->dev_info[dev_index].name;
739 device_fd = open(node_path, O_RDWR);
741 LOGE("open [%s] failed [errno %d]", node_path, errno);
742 return VISION_SOURCE_ERROR_INTERNAL;
746 libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
748 LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
750 if (libv4l2_fd != VISION_SOURCE_INITIAL_FD)
751 device_fd = libv4l2_fd;
752 #endif /* HAVE_LIBV4L2 */
754 v4l2_handle->device_index = dev_index;
755 v4l2_handle->device_fd = device_fd;
756 v4l2_handle->status = VISION_SOURCE_STATUS_OPENDED;
758 LOGD("[%d] device[%s] opened [fd %d]", dev_index, node_path, device_fd);
760 return VISION_SOURCE_ERROR_NONE;
763 int vision_source_close_device(vision_source_h handle)
765 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
767 if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
768 return VISION_SOURCE_ERROR_INVALID_OPERATION;
771 if (v4l2_handle->device_fd < 0) {
772 LOGE("invalid fd %d", v4l2_handle->device_fd);
773 return VISION_SOURCE_ERROR_INTERNAL;
776 LOGD("close fd %d", v4l2_handle->device_fd);
778 v4l2_close(v4l2_handle->device_fd);
780 v4l2_handle->status = VISION_SOURCE_STATUS_INITIALIZED;
781 LOGD("device [%d] closed", v4l2_handle->device_index);
782 v4l2_handle->device_fd = VISION_SOURCE_INITIAL_FD;
783 v4l2_handle->device_index = VISION_SOURCE_INITIAL_FD;
785 return VISION_SOURCE_ERROR_NONE;
788 int vision_source_set_stream_format(vision_source_h handle, media_format_h fmt)
790 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
792 if (!v4l2_handle->fmt || v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
793 LOGE("Invalid state");
794 return VISION_SOURCE_ERROR_INVALID_OPERATION;
797 media_format_mimetype_e mimetype;
798 int width, height, fps;
799 int ret = media_format_get_video_info(fmt, &mimetype, &width, &height, nullptr, nullptr);
800 if (ret != MEDIA_FORMAT_ERROR_NONE) {
801 LOGE("media_format_get_video_info failed");
802 return VISION_SOURCE_ERROR_INTERNAL;
804 ret = media_format_get_video_frame_rate(fmt, &fps);
805 if (ret != MEDIA_FORMAT_ERROR_NONE) {
806 LOGE("media_format_get_video_info failed");
807 return VISION_SOURCE_ERROR_INTERNAL;
810 LOGI("Try set format width: %d, height: %d, fps: %d", width, height, fps);
812 fmt_info request { mimetype, (uint32_t) width, (uint32_t) height, (uint32_t) fps };
813 vector<fmt_info> &vec = v4l2_handle->fmt_list[v4l2_handle->device_index];
814 const auto pos = find(vec.begin(), vec.end(), request);
815 if (pos == vec.end()) {
816 LOGE("Not supported format");
817 return VISION_SOURCE_ERROR_INVALID_PARAMETER;
820 auto index = distance(vec.begin(), pos);
821 if (v4l2_handle->fmt_index == index) {
822 LOGD("no need to restart preview stream");
823 return VISION_SOURCE_ERROR_NONE;
826 v4l2_handle->fmt_index = index;
828 ret = __vision_source_set_stream(v4l2_handle);
829 if (ret != VISION_SOURCE_ERROR_NONE) {
830 LOGE("failed to set stream");
834 return VISION_SOURCE_ERROR_NONE;
837 static void __vision_source_pkt_dispose_cb(media_packet_h packet, void *user_data)
839 pkt_dispose_cb_data *data = (pkt_dispose_cb_data *) user_data;
841 int ret = __vision_source_v4l2_qbuf(data->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, data->index);
842 if (ret != VISION_SOURCE_ERROR_NONE)
846 static void __fetch_buffer_and_callback(vision_source_v4l2_s *v4l2_handle)
848 LOGD("__fetch_buffer_and_callback");
851 unsigned int byte_size;
854 for (size_t i = 0; i < BUFFER_MAX; i++) {
855 v4l2_handle->pkt_data[i].fd = v4l2_handle->device_fd;
856 v4l2_handle->pkt_data[i].index = i;
859 while (v4l2_handle->buffer_thread_run) {
860 LOGD("__fetch_buffer_and_callback: waiting for buffer");
861 ret = __vision_source_v4l2_wait_frame(v4l2_handle->device_fd, 5);
862 if (ret != VISION_SOURCE_ERROR_NONE) {
863 LOGE("frame wait failed");
867 if (v4l2_handle->buffer_thread_run == false) {
868 LOGD("stop buffer handler thread");
871 ret = __vision_source_v4l2_dqbuf(v4l2_handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, &index,
873 if (ret != VISION_SOURCE_ERROR_NONE) {
874 LOGE("dqbuf failed");
878 media_format_h fmt = v4l2_handle->fmt[v4l2_handle->device_index][v4l2_handle->fmt_index];
881 ret = media_packet_new_from_external_memory(fmt, v4l2_handle->mmap_addr[index], byte_size,
882 __vision_source_pkt_dispose_cb, &v4l2_handle->pkt_data[index],
884 if (ret != MEDIA_PACKET_ERROR_NONE) {
885 LOGE("media_packet_new_from_external_memory failed");
888 if (v4l2_handle->stream_callback) {
889 v4l2_handle->stream_callback(pkt, v4l2_handle->stream_user_data);
892 media_packet_unref(pkt);
899 int vision_source_start_stream(vision_source_h handle)
901 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
903 if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
904 LOGE("status is not VISION_SOURCE_STATUS_OPENDED");
905 return VISION_SOURCE_ERROR_INVALID_OPERATION;
907 if (v4l2_handle->fmt_index < 0) {
908 LOGE("format is not set");
909 return VISION_SOURCE_ERROR_INVALID_OPERATION;
912 int ret = __vision_source_start_stream(v4l2_handle);
913 if (ret != VISION_SOURCE_ERROR_NONE) {
914 LOGE("__vision_source_start_stream failed[0x%x]", ret);
918 v4l2_handle->buffer_thread_run = true;
919 v4l2_handle->buffer_thread = thread(__fetch_buffer_and_callback, v4l2_handle);
921 v4l2_handle->status = VISION_SOURCE_STATUS_STARTED;
922 LOGD("start preview done");
924 return VISION_SOURCE_ERROR_NONE;
928 * TODO: buffer_thread has some problem, what happend to buffer?
930 int vision_source_stop_stream(vision_source_h handle)
932 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
934 if (v4l2_handle->status != VISION_SOURCE_STATUS_STARTED)
935 return VISION_SOURCE_ERROR_INVALID_OPERATION;
937 v4l2_handle->buffer_thread_run = false;
938 v4l2_handle->buffer_thread.join();
939 LOGI("buffer thread stopped and joined");
941 int ret = __vision_source_stop_stream(v4l2_handle);
942 if (ret != VISION_SOURCE_ERROR_NONE)
943 LOGE("__vision_source_stop_stream failed, but buffer thread will be stopped");
945 v4l2_handle->fmt_index = VISION_SOURCE_INITIAL_FD;
946 v4l2_handle->stream_callback = nullptr;
947 v4l2_handle->stream_user_data = nullptr;
948 v4l2_handle->status = VISION_SOURCE_STATUS_OPENDED;
949 LOGD("stop preview done [0x%x]", ret);
954 /* TODO: run-time callback change*/
955 int vision_source_set_stream_cb(vision_source_h handle, stream_cb callback, void *user_data)
957 vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
959 if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED)
960 return VISION_SOURCE_ERROR_INVALID_OPERATION;
962 v4l2_handle->stream_callback = callback;
963 v4l2_handle->stream_user_data = user_data;
964 return VISION_SOURCE_ERROR_NONE;
968 void attach_backend(vision_source_func_s *funcp)
970 funcp->init = vision_source_v4l2_init;
971 funcp->exit = vision_source_v4l2_exit;
972 funcp->list_devices = vision_source_v4l2_list_devices;
973 funcp->list_device_caps = vision_source_v4l2_list_device_caps;
974 funcp->open_device = vision_source_v4l2_open_device;
975 funcp->close_device = vision_source_v4l2_close_device;
976 funcp->set_stream_format = vision_source_v4l2_set_stream_format;
977 funcp->start_stream = vision_source_v4l2_start_stream;
978 funcp->stop_stream = vision_source_v4l2_stop_stream;
979 funcp->set_stream_cb = vision_source_v4l2_set_stream_cb;