#########################################
# Turn off build breakable
-FixNamespaceComments: false
-ReflowComments: false
-SortIncludes: false # can break build; turning off
-SortUsingDeclarations: false # can break build; turning off
+FixNamespaceComments: true
+ReflowComments: true
+SortIncludes: true # can break build; turning off
+SortUsingDeclarations: true # can break build; turning off
# Enterprise guide
BeforeElse: false
# M16
- AfterEnum: true
- AfterStruct: true
- AfterUnion: true
+ AfterEnum: false
+ AfterStruct: false
+ AfterUnion: false
# by inquiry
AfterClass: true
AfterNamespace: true
AfterObjCDeclaration: true
- AfterExternBlock: true
+ AfterExternBlock: false # mediavision want false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
# from pptx
-ColumnLimit: 80
+ColumnLimit: 120 # mediavision want 120
# M11
SpaceAfterCStyleCast: true
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
KeepEmptyLinesAtTheStartOfBlocks: false
-NamespaceIndentation: Inner
+NamespaceIndentation: None # mediavision want None
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
cmake_minimum_required(VERSION 3.0.0)
project(vision-source-v4l2)
-OPTION(HAVE_LIBV4L2 "USE libv4l2" OFF)
-OPTION(BUILD_TEST "Build test binary" OFF)
+option(HAVE_LIBV4L2 "Option description" OFF)
+option(BUILD_TEST "Build test binary" OFF)
include(FindPkgConfig)
-if(HAVE_LIBV4L2)
- add_definitions(-DHAVE_LIBV4L2)
- pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED libv4l2 dlog vision-source glib-2.0)
-else()
- pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED dlog vision-source glib-2.0)
-endif()
+message("PROJECT_NAME = ${PROJECT_NAME}")
add_library(${PROJECT_NAME}
- src/vision_source_v4l2.c
+ src/vision_source_v4l2.cpp
)
-target_link_libraries(${PROJECT_NAME}
+set(LIB_DEP dlog capi-media-tool)
+
+if(BUILD_TEST)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -ggdb")
+else()
+ target_compile_definitions(${PROJECT_NAME} PRIVATE -DUSE_DL)
+ list(APPEND LIB_DEP vision-source)
+endif()
+
+if(HAVE_LIBV4L2)
+ target_compile_definitions(${PROJECT_NAME} PRIVATE -DHAVE_LIBV4L2)
+ list(APPEND LIB_DEP libv4l2)
+endif()
+
+pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED ${LIB_DEP})
+
+target_link_libraries(${PROJECT_NAME} PUBLIC
${${PROJECT_NAME}_DEP_LIBRARIES}
)
-target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_DEP_INCLUDE_DIRS})
+
+target_include_directories(${PROJECT_NAME} PRIVATE
+ ${${PROJECT_NAME}_DEP_INCLUDE_DIRS}
+ /usr/include/media
+)
# install packages
install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
if(BUILD_TEST)
-add_subdirectory(test)
-endif()
\ No newline at end of file
+ add_subdirectory(test)
+endif()
--- /dev/null
+# vision-source-v4l2
+
+## build option
+HAVE_LIBV4L2 - libv4l2 is LGPL. default is off
+BUILD_TEST - compiler optimazation -O0 -ggdb , NOT used dlopen
+
+## TODO
+- [ ] refactoring vision_source_v4l2_s
+- [ ] multi-handler, multi-thread
+- [ ] resource management when stop called.
+- [ ] refactoring function names
+- [ ] runtime format change
+- [ ] support more format
-%define enable_libv4l2 1
+%define enable_libv4l2 0
+%define build_test 0
Name: vision-source-v4l2
Summary: vision source-v4l2
-Version: 0.0.7
+Version: 1.0.0
Release: 0
Group: Multimedia/Framework
License: Apache-2.0
Source0: %{name}-%{version}.tar.gz
BuildRequires: cmake
-BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(libtbm)
BuildRequires: pkgconfig(iniparser)
-BuildRequires: pkgconfig(vision-source)
BuildRequires: pkgconfig(capi-media-tool)
-BuildRequires: gtest-devel
%if 0%{?enable_libv4l2}
BuildRequires: pkgconfig(libv4l2)
%endif
+%if 0%{?build_test}
+BuildRequires: gtest-devel
+BuildRequires: vision-source-devel
+%else
+BuildRequires: pkgconfig(vision-source)
+%endif # build_test
%description
Vision source v4l2
%if 0%{?enable_libv4l2}
-DHAVE_LIBV4L2=ON \
%endif
+%if 0%{?build_test}
+ -DBUILD_TEST=ON \
+%endif # build_test
.
make %{?jobs:-j%jobs}
%files
%{_libdir}/*.so
+%if 0%{?build_test}
+%{_bindir}/*
+%endif # build_test
%license LICENSE.APLv2
+++ /dev/null
-/*
- * vision_source_v4l2.c
- *
- * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Most of code is from hal_camera_v4l2
- */
-
-#include <glob.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "vision_source_v4l2_private.h"
-
-#define DEVICE_NODE_PATH_MAX 16
-#define DEVICE_NODE_PATH_PREFIX "/dev/video"
-#define FOURCC_FORMAT "%c%c%c%c"
-#define FOURCC_CONVERT(fourcc) \
- fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, \
- (fourcc >> 24) & 0xff
-
-static guint32 g_device_caps;
-
-static int __vision_source_get_format(guint32 fourcc, int *pixel_format)
-{
- if (!pixel_format) {
- LOGE("NULL parameter");
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- switch (fourcc) {
- case V4L2_PIX_FMT_RGB24:
- *pixel_format = VISION_SOURCE_PIXEL_FORMAT_RGB24;
- break;
- default:
- LOGE("unknown fourcc " FOURCC_FORMAT, FOURCC_CONVERT(fourcc));
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- LOGD("fourcc " FOURCC_FORMAT " -> %d", FOURCC_CONVERT(fourcc),
- *pixel_format);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_get_fourcc_plane_num(int pixel_format,
- guint32 *fourcc,
- guint32 *plane_num)
-{
- if (!fourcc || !plane_num) {
- LOGE("NULL parameter %p %p", fourcc, plane_num);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- switch (pixel_format) {
- case VISION_SOURCE_PIXEL_FORMAT_RGB24:
- *fourcc = V4L2_PIX_FMT_RGB24;
- *plane_num = 1;
- break;
- default:
- LOGE("unknown format %d", pixel_format);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- LOGD("format %d -> fourcc " FOURCC_FORMAT, pixel_format,
- FOURCC_CONVERT(*fourcc));
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static void __vision_source_get_fps_list(int device_fd, guint32 pixel_format,
- int width, int height,
- vision_source_fps_list_s *fps_list)
-{
- struct v4l2_frmivalenum ival;
-
- if (device_fd < 0 || !fps_list) {
- LOGE("invalid param %d %p", device_fd, fps_list);
- return;
- }
-
- ival.index = 0;
- ival.pixel_format = pixel_format;
- ival.width = width;
- ival.height = height;
-
- if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {
- LOGE("VIDIOC_ENUM_FRAMEINTERVALS failed[%d]", errno);
- return;
- }
-
- if (ival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
- LOGE("NOT V4L2_FRMIVAL_TYPE_DISCRETE -> [%u]", ival.type);
- return;
- }
-
- do {
- LOGI("\t\t\t\tFramerate[%u/%u]", ival.discrete.denominator,
- ival.discrete.numerator);
- fps_list->fps[ival.index++] = ival.discrete.denominator;
- } while (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
-
- fps_list->count = ival.index;
-}
-
-static int __vision_source_v4l2_qbuf(int device_fd, int type, int memory,
- int index)
-{
- struct v4l2_buffer v4l2_buf;
- struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
-
- if (device_fd < 0) {
- LOGE("invalid fd %d", device_fd);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
- memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
-
- v4l2_buf.index = index;
- v4l2_buf.type = type;
- v4l2_buf.memory = memory;
- v4l2_buf.m.planes = v4l2_planes;
-
- if (v4l2_ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
- LOGE("qbuf failed. [i: %d, t: %d, m: %d] errno %d", index, type,
- memory, errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /*LOGD("QBUF done [i: %d, t: %d, m: %d]", index, type, memory);*/
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int
-__vision_source_get_device_info(int device_index, int device_fd,
- vision_source_device_info_s *device_info,
- char *node_path)
-{
- int resolution_index = 0;
- int resolution_count = 0;
- int pixel_format = 0;
- struct v4l2_fmtdesc v4l2_format;
- struct v4l2_frmsizeenum v4l2_frame;
-
- if (device_fd < 0 || !device_info || !node_path) {
- LOGE("invalid param %d %p %p", device_fd, device_info, node_path);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- LOGD("Get Supported format and resolution");
-
- int pixel_index = 0;
- int pixel_count = 0;
-
- while (1) {
- memset(&v4l2_format, 0x0, sizeof(struct v4l2_fmtdesc));
-
- v4l2_format.index = pixel_index;
- v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FMT, &v4l2_format) < 0) {
- LOGW("\tformat : end of enumeration");
- break;
- }
-
- LOGD("\tformat[%d] " FOURCC_FORMAT " (emulated:%d)", pixel_index,
- FOURCC_CONVERT(v4l2_format.pixelformat),
- ((v4l2_format.flags & V4L2_FMT_FLAG_EMULATED) ? 1 : 0));
-
- if (__vision_source_get_format(v4l2_format.pixelformat,
- &pixel_format) !=
- VISION_SOURCE_ERROR_NONE) {
- pixel_index++;
- continue;
- }
-
- device_info->pixel_list.pixels[pixel_count].pixel_format = pixel_format;
-
- resolution_index = 0;
- resolution_count = 0;
- while (1) {
- memset(&v4l2_frame, 0x0, sizeof(struct v4l2_frmsizeenum));
-
- v4l2_frame.index = resolution_index;
- v4l2_frame.pixel_format = v4l2_format.pixelformat;
-
- if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMESIZES, &v4l2_frame) <
- 0) {
- LOGW("\t\tframe : end of enumeration ");
- break;
- }
-
- vision_source_resolution_match_fps_s *rmf =
- &device_info->pixel_list.pixels[pixel_count]
- .resolution_list.resolutions[resolution_count];
-
- switch (v4l2_frame.type) {
- case V4L2_FRMSIZE_TYPE_DISCRETE:
- rmf->resolution.width = v4l2_frame.discrete.width;
- rmf->resolution.height = v4l2_frame.discrete.height;
-
- LOGD("\t\tsize[%d] %ux%u", resolution_index,
- v4l2_frame.discrete.width, v4l2_frame.discrete.height);
-
- __vision_source_get_fps_list(device_fd, v4l2_frame.pixel_format,
- v4l2_frame.discrete.width,
- v4l2_frame.discrete.height,
- &rmf->fps_list);
- resolution_count++;
- break;
- case V4L2_FRMSIZE_TYPE_CONTINUOUS:
- LOGW("\t\tsize[%d] %ux%u - %ux%u", resolution_index,
- v4l2_frame.stepwise.min_width,
- v4l2_frame.stepwise.min_height,
- v4l2_frame.stepwise.max_width,
- v4l2_frame.stepwise.max_height);
- break;
- case V4L2_FRMSIZE_TYPE_STEPWISE:
- LOGW("\t\tsize[%d] %ux%u - %ux%u (step %ux%u)",
- resolution_index, v4l2_frame.stepwise.min_width,
- v4l2_frame.stepwise.min_height,
- v4l2_frame.stepwise.max_width,
- v4l2_frame.stepwise.max_height,
- v4l2_frame.stepwise.step_width,
- v4l2_frame.stepwise.step_height);
- break;
- default:
- LOGE("\t\tunknown frame type %d", v4l2_frame.type);
- break;
- }
- resolution_index++;
- }
-
- device_info->pixel_list.pixels[pixel_count].resolution_list.count =
- resolution_index;
- LOGD("\t\tresolution count [%d]", resolution_index);
- pixel_index++;
- pixel_count++;
- }
-
- device_info->index = device_index;
- device_info->pixel_list.count = pixel_count;
- snprintf(device_info->name, sizeof(device_info->name), "V4L2_CAMERA");
- snprintf(device_info->node_path, sizeof(device_info->node_path), "%s",
- node_path);
-
- LOGD("\tformat count [%d]", pixel_count);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_get_device_info_list(
- vision_source_device_info_list_s **h_device_info_list)
-{
- int i = 0;
- int ret = 0;
- int device_count = 0;
- int device_fd = CAMERA_HAL_INITIAL_FD;
-#ifdef HAVE_LIBV4L2
- int libv4l2_fd = CAMERA_HAL_INITIAL_FD;
-#endif /* HAVE_LIBV4L2 */
- glob_t glob_buf;
- struct v4l2_capability v4l2_cap;
- vision_source_device_info_list_s *device_info_list = NULL;
-
- device_info_list = g_new0(vision_source_device_info_list_s, 1);
- if (!device_info_list) {
- LOGE("failed to alloc device info structure");
- ret = VISION_SOURCE_ERROR_INTERNAL;
- goto _GET_DEVICE_INFO_LIST_DONE;
- }
-
- memset(&glob_buf, 0x0, sizeof(glob_t));
-
- ret = glob(DEVICE_NODE_PATH_PREFIX "*", 0, 0, &glob_buf);
- if (ret != 0) {
- switch (ret) {
- case GLOB_NOSPACE:
- LOGE("out of memory");
- ret = VISION_SOURCE_ERROR_INTERNAL;
- goto _GET_DEVICE_INFO_LIST_DONE;
- case GLOB_ABORTED:
- LOGE("read error");
- ret = VISION_SOURCE_ERROR_INTERNAL;
- goto _GET_DEVICE_INFO_LIST_DONE;
- case GLOB_NOMATCH:
- LOGE("match not found");
- ret = VISION_SOURCE_ERROR_INTERNAL;
- goto _GET_DEVICE_INFO_LIST_DONE;
- default:
- LOGE("unknown error : %d", ret);
- ret = VISION_SOURCE_ERROR_INTERNAL;
- goto _GET_DEVICE_INFO_LIST_DONE;
- }
- }
-
- LOGD("device node count : %zu", glob_buf.gl_pathc);
-
- for (i = 0; i < glob_buf.gl_pathc; i++) {
- LOGD("[%d] check device [%s]", i, glob_buf.gl_pathv[i]);
-
- device_fd = open(glob_buf.gl_pathv[i], O_RDWR);
- if (device_fd < 0) {
- LOGE("open failed [%s] errno %d", glob_buf.gl_pathv[i], errno);
- continue;
- }
-
-#ifdef HAVE_LIBV4L2
- libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
-
- LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
-
- if (libv4l2_fd != CAMERA_HAL_INITIAL_FD)
- device_fd = libv4l2_fd;
-#endif /* HAVE_LIBV4L2 */
-
- memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
-
- if (v4l2_ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
- LOGE("querycap failed. errno %d", errno);
- v4l2_close(device_fd);
- continue;
- }
-
- if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
- g_device_caps = v4l2_cap.device_caps;
- else
- g_device_caps = v4l2_cap.capabilities;
-
- if (!(g_device_caps &
- (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
- (g_device_caps &
- (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))) {
- LOGW("[%s] is not a capture device 0x%x", glob_buf.gl_pathv[i],
- g_device_caps);
- v4l2_close(device_fd);
- continue;
- }
-
- ret = __vision_source_get_device_info(
- device_count, device_fd,
- &device_info_list->device_info[device_count],
- glob_buf.gl_pathv[i]);
-
- v4l2_close(device_fd);
-
- if (ret == VISION_SOURCE_ERROR_NONE)
- device_count++;
- }
-
- device_info_list->count = device_count;
- *h_device_info_list = device_info_list;
-
- LOGD("new h_device_info_list %p - device count %d", *h_device_info_list,
- device_count);
-
-_GET_DEVICE_INFO_LIST_DONE:
- LOGD("ret 0x%x", ret);
- globfree(&glob_buf);
-
- if (ret != VISION_SOURCE_ERROR_NONE)
- g_free(device_info_list);
-
- return ret;
-}
-
-static void __vision_source_release_handle(vision_source_v4l2_s *handle)
-{
- if (!handle) {
- LOGW("NULL handle");
- return;
- }
-
- g_mutex_clear(&handle->lock);
- g_mutex_clear(&handle->buffer_lock);
- g_cond_clear(&handle->buffer_cond);
- if (handle->device_info_list)
- g_free(handle->device_info_list);
-
- LOGD("vision_source_v4l2_s %p destroy", handle);
-
- g_free(handle);
-
- return;
-}
-
-static int __vision_source_v4l2_stream(int device_fd, int type, gboolean onoff)
-{
- if (device_fd < 0) {
- LOGE("invalid fd %d", device_fd);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- if (v4l2_ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF,
- &type) < 0) {
- LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- LOGD("stream %d done [t:%d]", onoff, type);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_v4l2_reqbufs(int device_fd, int type, int memory,
- uint32_t count, uint32_t *result_count)
-{
- struct v4l2_requestbuffers v4l2_reqbuf;
-
- if (device_fd < 0) {
- LOGE("invalid fd %d", device_fd);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- if (!result_count) {
- LOGE("NULL parameter");
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers));
-
- v4l2_reqbuf.type = type;
- v4l2_reqbuf.memory = memory;
- v4l2_reqbuf.count = count;
-
- if (v4l2_ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) {
- LOGE("REQBUFS[count %d] failed. errno %d", count, errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- if (v4l2_reqbuf.count != count)
- LOGW("different count [req:%d, result:%d]", count, v4l2_reqbuf.count);
-
- *result_count = v4l2_reqbuf.count;
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_stop_stream(vision_source_v4l2_s *handle,
- uint32_t buffer_count)
-{
- int i = 0;
- int ret = VISION_SOURCE_ERROR_NONE;
-
- if (!handle) {
- LOGE("NULL handle");
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- LOGD("buffer count[%d]", buffer_count);
-
- /* stream off */
- ret = __vision_source_v4l2_stream(handle->device_fd, handle->buffer_type,
- FALSE);
-
- LOGD("stream off : 0x%x", ret);
-
- /* munmap */
- for (i = 0; i < buffer_count; i++) {
- if (handle->vision_source_buffers[i].planes[0].data != NULL) {
- LOGW("munmap %p", handle->vision_source_buffers[i].planes[0].data);
-
- v4l2_munmap(handle->vision_source_buffers[i].planes[0].data,
- handle->vision_source_buffers[i].planes[0].size);
-
- handle->vision_source_buffers[i].planes[0].data = 0;
- handle->vision_source_buffers[i].planes[0].size = 0;
- } else {
- LOGW("NULL data [index %d]", i);
- }
- }
-
- /* reqbufs 0 */
- ret = __vision_source_v4l2_reqbufs(handle->device_fd, handle->buffer_type,
- V4L2_MEMORY_MMAP, 0, &buffer_count);
-
- LOGD("reqbufs 0 : 0x%x", ret);
-
- return ret;
-}
-
-static int __vision_source_set_stream(vision_source_v4l2_s *handle,
- vision_source_pixel_format_e pixel_format,
- vision_source_resolution_s *resolution,
- uint32_t fps,
- uint32_t request_buffer_count)
-{
- struct v4l2_format v4l2_fmt;
- struct v4l2_streamparm v4l2_parm;
-
- guint32 fourcc = 0;
- guint32 plane_num = 0;
-
- if (!handle || !resolution) {
- LOGE("NULL param %p %p", handle, resolution);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /* S_FMT */
- int ret = __vision_source_get_fourcc_plane_num(pixel_format, &fourcc,
- &plane_num);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("get fourcc failed [format %d]", pixel_format);
- return ret;
- }
-
- memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
-
- v4l2_fmt.type = handle->buffer_type;
- if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) {
- v4l2_fmt.fmt.pix_mp.width = resolution->width;
- v4l2_fmt.fmt.pix_mp.height = resolution->height;
- v4l2_fmt.fmt.pix_mp.pixelformat = fourcc;
- v4l2_fmt.fmt.pix_mp.num_planes = plane_num;
- } else {
- v4l2_fmt.fmt.pix.width = resolution->width;
- v4l2_fmt.fmt.pix.height = resolution->height;
- v4l2_fmt.fmt.pix.pixelformat = fourcc;
- v4l2_fmt.fmt.pix.bytesperline = resolution->width;
- }
-
- if (v4l2_ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
- LOGE("S_FMT failed. errno %d", errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) {
- for (int i = 0; i < v4l2_fmt.fmt.pix_mp.num_planes; i++) {
- LOGD("plane[%d] stride %u, sizeimage %u", i,
- v4l2_fmt.fmt.pix_mp.plane_fmt[i].bytesperline,
- v4l2_fmt.fmt.pix_mp.plane_fmt[i].sizeimage);
- }
- } else {
- for (int i = 0; i < request_buffer_count; i++) {
- handle->vision_source_buffers[i].planes[0].align_width =
- v4l2_fmt.fmt.pix.bytesperline;
- handle->vision_source_buffers[i].planes[0].size =
- v4l2_fmt.fmt.pix.sizeimage;
- }
- LOGD("stride %d, sizeimage %d", v4l2_fmt.fmt.pix.bytesperline,
- v4l2_fmt.fmt.pix.sizeimage);
- }
-
- /* G_PARM */
- memset(&v4l2_parm, 0x0, sizeof(struct v4l2_streamparm));
-
- v4l2_parm.type = handle->buffer_type;
-
- if (v4l2_ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) {
- LOGE("G_PARM failed. errno %d", errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /* S_PARM to set fps */
- v4l2_parm.parm.capture.timeperframe.numerator = 1;
- v4l2_parm.parm.capture.timeperframe.denominator = fps;
-
- if (v4l2_ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) {
- LOGE("S_PARM failed. errno %d", errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_v4l2_dqbuf(int device_fd, int type, int memory,
- int *index, unsigned int *used_size)
-{
- int ret = VISION_SOURCE_ERROR_NONE;
- struct v4l2_buffer v4l2_buf;
- struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
-
- if (device_fd < 0) {
- LOGE("invalid fd %d", device_fd);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- if (!index) {
- LOGE("NULL parameter");
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
- memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
-
- v4l2_buf.type = type;
- v4l2_buf.memory = memory;
- v4l2_buf.m.planes = v4l2_planes;
-
- ret = v4l2_ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
- if (ret < 0) {
- if (errno != EIO) {
- LOGE("dqbuf failed. [t: %d, m: %d] errno %d", type, memory, errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
- }
-
- *index = v4l2_buf.index;
- *used_size = v4l2_buf.bytesused;
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __vision_source_v4l2_wait_frame(int device_fd, int wait_time)
-{
- int ret = VISION_SOURCE_ERROR_NONE;
- fd_set fds;
- struct timeval timeout;
-
- if (device_fd < 0) {
- LOGE("invalid fd %d", device_fd);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- FD_ZERO(&fds);
- FD_SET(device_fd, &fds);
-
- memset(&timeout, 0x0, sizeof(struct timeval));
-
- timeout.tv_sec = wait_time;
- timeout.tv_usec = 0;
-
- /*LOGD("select : %d sec", wait_time);*/
-
- ret = select(device_fd + 1, &fds, NULL, NULL, &timeout);
- if (ret == -1) {
- if (EINTR == errno) {
- LOGD("select error : EINTR");
- return VISION_SOURCE_ERROR_NONE;
- }
- LOGE("select failed. errno %d", errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- if (ret == 0) {
- LOGE("select timeout.");
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /*LOGD("select done");*/
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int
-__vision_source_start_stream(vision_source_v4l2_s *handle,
- vision_source_pixel_format_e pixel_format,
- vision_source_resolution_s *resolution,
- uint32_t fps, uint32_t request_buffer_count)
-{
- vision_source_buffer_s *buffer = NULL;
- struct v4l2_buffer v4l2_buf;
- struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
-
- int ret = __vision_source_set_stream(handle, pixel_format, resolution, fps,
- request_buffer_count);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- return ret;
- }
-
- /* request buffer */
- ret = __vision_source_v4l2_reqbufs(handle->device_fd, handle->buffer_type,
- V4L2_MEMORY_MMAP, request_buffer_count,
- &handle->buffer_count);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- return ret;
- }
-
- LOGD("buffer count : request %d -> result %d", request_buffer_count,
- handle->buffer_count);
-
- /* query buffer, mmap and qbuf */
- for (int i = 0; i < handle->buffer_count; i++) {
- memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
- memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
-
- v4l2_buf.type = handle->buffer_type;
- v4l2_buf.memory = V4L2_MEMORY_MMAP;
- v4l2_buf.index = i;
- v4l2_buf.m.planes = v4l2_planes;
- v4l2_buf.length = 0;
-
- if (v4l2_ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
- LOGE("[%d] query buf failed. errno %d", i, errno);
- goto _START_STREAM_FAILED;
- }
-
- buffer = &handle->vision_source_buffers[i];
-
- buffer->index = i;
- buffer->pixel_format = pixel_format;
- buffer->resolution.width = resolution->width;
- buffer->resolution.height = resolution->height;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) {
- buffer->num_planes = v4l2_buf.length;
- } else {
- buffer->num_planes = 1;
- buffer->planes[0].size = buffer->total_size = v4l2_buf.length;
- }
-
- buffer->planes[0].data =
- v4l2_mmap(0, v4l2_buf.length, PROT_READ | PROT_WRITE,
- MAP_SHARED, handle->device_fd, v4l2_buf.m.offset);
-
- if (buffer->planes[0].data == MAP_FAILED) {
- LOGE("[%d] mmap failed (errno %d)", i, errno);
- goto _START_STREAM_FAILED;
- }
-
- if (__vision_source_v4l2_qbuf(handle->device_fd, handle->buffer_type,
- V4L2_MEMORY_MMAP,
- i) != VISION_SOURCE_ERROR_NONE) {
- LOGE("[%d] qbuf failed (errno %d)", i, errno);
- goto _START_STREAM_FAILED;
- }
- }
-
- /* stream on */
- ret = __vision_source_v4l2_stream(handle->device_fd, handle->buffer_type,
- TRUE);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("stream on failed");
- goto _START_STREAM_FAILED;
- }
-
- return VISION_SOURCE_ERROR_NONE;
-
-_START_STREAM_FAILED:
- __vision_source_stop_stream(handle, handle->buffer_count);
- return ret;
-}
-
-int vision_source_v4l2_init(vision_source_h *handle)
-{
- LOGD("enter");
-
- VISION_SOURCE_NULL_ARG_CHECK(handle);
-
- vision_source_v4l2_s *v4l2_handle = g_new0(vision_source_v4l2_s, 1);
- if (!v4l2_handle) {
- LOGE("failed to alloc camera hal handle");
- // tbm_bufmgr_deinit(bufmgr);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- int ret = __vision_source_get_device_info_list(
- &v4l2_handle->device_info_list);
-
- if (ret != VISION_SOURCE_ERROR_NONE) {
- g_free(v4l2_handle);
- LOGE("get device info failed");
- return ret;
- }
-
- g_mutex_init(&v4l2_handle->lock);
- g_mutex_init(&v4l2_handle->buffer_lock);
- g_cond_init(&v4l2_handle->buffer_cond);
-
- *handle = v4l2_handle;
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int vision_source_v4l2_exit(vision_source_h handle)
-{
- if (!handle) {
- LOGE("NULL handle");
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- __vision_source_release_handle(v4l2_handle);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int vision_source_v4l2_enumerate_devices(
- vision_source_h handle, vision_source_device_info_list_s *info_list)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
- VISION_SOURCE_NULL_ARG_CHECK(info_list);
-
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- if (!v4l2_handle->device_info_list) {
- int ret = __vision_source_get_device_info_list(
- &v4l2_handle->device_info_list);
-
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("get device info failed");
- return ret;
- }
- }
-
- memcpy(info_list, v4l2_handle->device_info_list,
- sizeof(vision_source_device_info_list_s));
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int vision_source_v4l2_open_device(vision_source_h handle, int device_index)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
-
- int device_fd = CAMERA_HAL_INITIAL_FD;
-#ifdef HAVE_LIBV4L2
- int libv4l2_fd = CAMERA_HAL_INITIAL_FD;
-#endif /* HAVE_LIBV4L2 */
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&v4l2_handle->lock);
-
- if (!v4l2_handle->device_info_list) {
- LOGE("NO DEVICE INFO");
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- if (device_index >= v4l2_handle->device_info_list->count) {
- LOGE("invalid index %d [info:%d]", device_index,
- v4l2_handle->device_info_list->count);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
-
- char *node_path =
- v4l2_handle->device_info_list->device_info[device_index].node_path;
-
- device_fd = open(node_path, O_RDWR);
- if (device_fd < 0) {
- LOGE("open [%s] failed [errno %d]", node_path, errno);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- if (g_device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
- v4l2_handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
- else
- v4l2_handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE;
-
-#ifdef HAVE_LIBV4L2
- libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
-
- LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
-
- if (libv4l2_fd != CAMERA_HAL_INITIAL_FD)
- device_fd = libv4l2_fd;
-#endif /* HAVE_LIBV4L2 */
-
- v4l2_handle->device_index = device_index;
- v4l2_handle->device_fd = device_fd;
-
- LOGD("[%d] device[%s] opened [fd %d, type %d]", device_index, node_path,
- device_fd, v4l2_handle->buffer_type);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int vision_source_v4l2_close_device(vision_source_h handle)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&v4l2_handle->lock);
-
- int ret =
- __vision_source_stop_stream(v4l2_handle, v4l2_handle->buffer_count);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("failed to stop stream");
- return ret;
- }
-
- if (v4l2_handle->device_fd >= 0) {
- LOGD("close fd %d", v4l2_handle->device_fd);
-
- v4l2_close(v4l2_handle->device_fd);
- v4l2_handle->device_fd = CAMERA_HAL_INITIAL_FD;
- } else {
- LOGW("invalid fd %d", v4l2_handle->device_fd);
- }
-
- LOGD("device [%d] closed", v4l2_handle->device_index);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int vision_source_v4l2_set_stream_format(vision_source_h handle,
- vision_source_format_s *format)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
- VISION_SOURCE_NULL_ARG_CHECK(format);
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
- int i = 0;
- int j = 0;
- int ret = VISION_SOURCE_ERROR_NONE;
- gboolean capability_check = FALSE;
- vision_source_device_info_s *device_info = NULL;
-
- g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&v4l2_handle->lock);
-
- if (!v4l2_handle->device_info_list) {
- LOGE("no device info list");
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /* check capability */
- device_info = &v4l2_handle->device_info_list
- ->device_info[v4l2_handle->device_index];
-
- /* format */
- for (i = 0; i < device_info->pixel_list.count; i++) {
- if (format->pixel_format ==
- device_info->pixel_list.pixels[i].pixel_format) {
- LOGD("format matched %d, check resolution.", format->pixel_format);
-
- vision_source_resolution_match_fps_list_s *res_match =
- &device_info->pixel_list.pixels[i].resolution_list;
-
- /* resolution */
- for (j = 0; j < res_match->count; j++) {
- if (format->resolution.width ==
- res_match->resolutions[j].resolution.width &&
- format->resolution.height ==
- res_match->resolutions[j].resolution.height) {
- LOGD("resolution matched %dx%d", format->resolution.width,
- format->resolution.height);
- capability_check = TRUE;
- break;
- }
- }
-
- break;
- }
- }
-
- if (!capability_check) {
- LOGE("capability failed - %d, %dx%d", format->pixel_format,
- format->resolution.width, format->resolution.height);
- return VISION_SOURCE_ERROR_INTERNAL;
- }
-
- /* compare with current settings */
- if (v4l2_handle->stream_format.pixel_format == format->pixel_format &&
- v4l2_handle->stream_format.resolution.width ==
- format->resolution.width &&
- v4l2_handle->stream_format.resolution.height ==
- format->resolution.height &&
- v4l2_handle->stream_format.fps == format->fps) {
- LOGD("no need to restart preview stream");
- return VISION_SOURCE_ERROR_NONE;
- }
-
- LOGD("Preview setting is changed. Restart preview now.");
-
- /* stop preview stream to change it */
- ret = __vision_source_stop_stream(v4l2_handle, v4l2_handle->buffer_count);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("failed to stop stream");
- return ret;
- }
-
- ret = __vision_source_set_stream(v4l2_handle, format->pixel_format,
- &format->resolution, format->fps,
- BUFFER_MAX);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("failed to set stream");
- return ret;
- }
-
- memcpy(&v4l2_handle->stream_format, format, sizeof(vision_source_format_s));
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static int __convert_buffer_to_fmt(vision_source_buffer_s *buffer,
- media_format_h fmt)
-{
- media_format_mimetype_e mime;
- switch (buffer->pixel_format) {
- case VISION_SOURCE_PIXEL_FORMAT_RGB24:
- mime = MEDIA_FORMAT_RGB888;
- break;
-
- default:
- LOGE("Not supported format %d", buffer->pixel_format);
- return VISION_SOURCE_ERROR_INVALID_PARAMETER;
- }
- if (media_format_set_video_mime(fmt, mime) != MEDIA_FORMAT_ERROR_NONE)
- return VISION_SOURCE_ERROR_INTERNAL;
- media_format_set_video_width(fmt, buffer->resolution.width);
- media_format_set_video_height(fmt, buffer->resolution.height);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-static void __pkt_dispose_cb(media_packet_h packet, void *user_data)
-{
- packet_context_s *pkt_ctx = (packet_context_s *) user_data;
- if (__vision_source_v4l2_qbuf(pkt_ctx->device_fd, pkt_ctx->type,
- pkt_ctx->memory,
- pkt_ctx->index) != VISION_SOURCE_ERROR_NONE) {
- LOGE("qbuf failed with device_fd: %d, type: %d, memory: %d, index: %d",
- pkt_ctx->device_fd, pkt_ctx->type, pkt_ctx->memory,
- pkt_ctx->index);
- }
-
- free(pkt_ctx);
-}
-
-static media_packet_h __make_media_packet(vision_source_buffer_s *buffer,
- int device_fd, int buffer_type,
- int index)
-{
- media_packet_h pkt;
- media_format_h fmt;
- media_format_create(&fmt);
- if (__convert_buffer_to_fmt(buffer, fmt) != VISION_SOURCE_ERROR_NONE) {
- media_format_unref(fmt);
- return NULL;
- }
-
- packet_context_s *pkt_ctx =
- (packet_context_s *) malloc(sizeof(packet_context_s));
- if (!pkt_ctx) {
- LOGE("packet_context_s malloc failed");
- media_format_unref(fmt);
- return NULL;
- }
-
- pkt_ctx->device_fd = device_fd;
- pkt_ctx->type = buffer_type;
- pkt_ctx->memory = V4L2_MEMORY_MMAP;
- pkt_ctx->index = index;
-
- media_packet_new_from_external_memory(fmt, buffer->planes[0].data,
- buffer->planes[0].used_size,
- __pkt_dispose_cb, pkt_ctx, &pkt);
-
- media_format_unref(fmt);
- return pkt;
-}
-
-static void *__fetch_buffer_and_callback(gpointer data)
-{
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) data;
- int index;
- unsigned int byte_size;
-
- /* run buffer thread */
- g_mutex_lock(&v4l2_handle->buffer_lock);
-
- while (v4l2_handle->buffer_thread_run) {
- g_mutex_unlock(&v4l2_handle->buffer_lock);
-
- if (__vision_source_v4l2_wait_frame(v4l2_handle->device_fd, 5) !=
- VISION_SOURCE_ERROR_NONE) {
- LOGE("frame wait failed");
- g_mutex_lock(&v4l2_handle->buffer_lock);
- break;
- }
-
- g_mutex_lock(&v4l2_handle->buffer_lock);
-
- if (v4l2_handle->buffer_thread_run == FALSE) {
- LOGW("stop buffer handler thread");
- break;
- }
- if (__vision_source_v4l2_dqbuf(v4l2_handle->device_fd,
- v4l2_handle->buffer_type,
- V4L2_MEMORY_MMAP, &index, &byte_size) !=
- VISION_SOURCE_ERROR_NONE) {
- LOGE("dqbuf failed");
- break;
- }
- g_mutex_unlock(&v4l2_handle->buffer_lock);
- vision_source_buffer_s *buffer =
- &v4l2_handle->vision_source_buffers[index];
- buffer->planes[0].used_size = byte_size;
-
- if (v4l2_handle->stream_callback) {
- media_packet_h pkt =
- __make_media_packet(buffer, v4l2_handle->device_fd,
- v4l2_handle->buffer_type, index);
- if (!pkt)
- return NULL;
- v4l2_handle->stream_callback(pkt,
- v4l2_handle->stream_callback_data);
- media_packet_unref(pkt);
- }
- sched_yield();
-
- g_mutex_lock(&v4l2_handle->buffer_lock);
- }
-
- g_mutex_unlock(&v4l2_handle->buffer_lock);
-
- return NULL;
-}
-
-int source_v4l2_start_stream(vision_source_h handle, stream_cb callback,
- void *user_data)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
-
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&v4l2_handle->lock);
-
- int ret = __vision_source_start_stream(
- v4l2_handle, v4l2_handle->stream_format.pixel_format,
- &v4l2_handle->stream_format.resolution,
- v4l2_handle->stream_format.fps, BUFFER_MAX);
- if (ret != VISION_SOURCE_ERROR_NONE) {
- LOGE("__vision_source_start_stream failed[0x%x]", ret);
- g_mutex_unlock(&v4l2_handle->lock);
- return ret;
- }
-
- g_mutex_lock(&v4l2_handle->buffer_lock);
-
- v4l2_handle->buffer_thread_run = TRUE;
- v4l2_handle->stream_callback = callback;
- v4l2_handle->stream_callback_data = user_data;
-
- v4l2_handle->buffer_thread = g_thread_try_new("vision_source_buffer_thread",
- __fetch_buffer_and_callback,
- (gpointer) v4l2_handle, NULL);
- if (!v4l2_handle->buffer_thread) {
- LOGE("failed to create buffer handler thread");
- g_mutex_unlock(&v4l2_handle->buffer_lock);
- __vision_source_stop_stream(v4l2_handle, v4l2_handle->buffer_count);
-
- return ret;
- }
-
- g_mutex_unlock(&v4l2_handle->buffer_lock);
-
- LOGD("start preview done");
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-int source_v4l2_stop_stream(vision_source_h handle)
-{
- VISION_SOURCE_NULL_ARG_CHECK(handle);
-
- vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-
- LOGD("start");
- g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&v4l2_handle->lock);
-
- g_mutex_lock(&v4l2_handle->buffer_lock);
-
- v4l2_handle->buffer_thread_run = FALSE;
-
- g_mutex_unlock(&v4l2_handle->buffer_lock);
-
- int ret =
- __vision_source_stop_stream(v4l2_handle, v4l2_handle->buffer_count);
-
- /* wait for preview thread exit */
- if (v4l2_handle->buffer_thread)
- g_thread_join(v4l2_handle->buffer_thread);
- v4l2_handle->buffer_thread = NULL;
-
- LOGD("stop preview done [0x%x]", ret);
-
- return VISION_SOURCE_ERROR_NONE;
-}
-
-void attach_backend(vision_source_func_s *funcp)
-{
- funcp->init = vision_source_v4l2_init;
- funcp->exit = vision_source_v4l2_exit;
- funcp->enumerate_devices = vision_source_v4l2_enumerate_devices;
- funcp->open_device = vision_source_v4l2_open_device;
- funcp->close_device = vision_source_v4l2_close_device;
- funcp->set_stream_format = vision_source_v4l2_set_stream_format;
- funcp->start_stream = source_v4l2_start_stream;
- funcp->stop_stream = source_v4l2_stop_stream;
-}
\ No newline at end of file
--- /dev/null
+/*
+ * vision_source_v4l2.c
+ *
+ * Copyright (c) 2022 - 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Most of code is from hal_camera_v4l2
+ */
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <dlog.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <linux/videodev2.h>
+#include <media_packet.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <vision_source_interface.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "VISION_SOURCE_V4L2"
+#ifdef HAVE_LIBV4L2
+#include <libv4l2.h>
+#else
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#define v4l2_fd_open(fd, flags) (fd)
+#define v4l2_close close
+#define v4l2_dup dup
+#define v4l2_ioctl ioctl
+#define v4l2_read read
+#define v4l2_mmap mmap
+#define v4l2_munmap munmap
+#endif /* ENABLE_LIBV4L2 */
+
+#define VISION_SOURCE_CHECK_CONDITION(condition, error, msg) \
+ do { \
+ if (!(condition)) { \
+ LOGE("[%s] %s(0x%08x)", __FUNCTION__, msg, error); \
+ return error; \
+ } \
+ } while (0)
+
+#define VISION_SOURCE_NULL_ARG_CHECK(arg) \
+ VISION_SOURCE_CHECK_CONDITION(arg != NULL, VISION_SOURCE_ERROR_INVALID_PARAMETER, \
+ "VISION_SOURCE_ERROR_INVALID_PARAMETER")
+
+#define VISION_SOURCE_INITIAL_FD -1
+#define BUFFER_MAX 4
+
+#define DEVICE_NODE_PATH_PREFIX "/dev/video"
+#define FOURCC_FORMAT "%c%c%c%c"
+#define FOURCC_CONVERT(fourcc) fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff
+
+#ifdef USE_DL
+#define vision_source_init vision_source_v4l2_init
+#define vision_source_exit vision_source_v4l2_exit
+#define vision_source_list_devices vision_source_v4l2_list_devices
+#define vision_source_get_device_cap vision_source_v4l2_get_device_cap
+#define vision_source_open_device vision_source_v4l2_open_device
+#define vision_source_close_device vision_source_v4l2_close_device
+#define vision_source_set_stream_format vision_source_v4l2_set_stream_format
+#define vision_source_start_stream vision_source_v4l2_start_stream
+#define vision_source_stop_stream vision_source_v4l2_stop_stream
+#define vision_source_set_stream_cb vision_source_v4l2_set_stream_cb
+#else
+#include <vision_source.h>
+#endif
+
+using namespace std;
+
+struct fmt_info {
+ media_format_mimetype_e type;
+ uint32_t width;
+ uint32_t height;
+ uint32_t fps;
+
+ bool operator==(const fmt_info &rhs)
+ {
+ return (type == rhs.type) && (width == rhs.width) && (height == rhs.height) && (fps == rhs.fps);
+ }
+};
+
+struct pkt_dispose_cb_data {
+ int fd;
+ int index;
+};
+
+struct vision_source_v4l2_s {
+ /* device */
+ vision_source_device_info_s *dev_info {};
+ media_format_h **fmt {};
+ vector<string> dev_name {};
+ vector<vector<fmt_info> > fmt_list {};
+
+ /* current user setting */
+ int device_index = VISION_SOURCE_INITIAL_FD;
+ int device_fd = VISION_SOURCE_INITIAL_FD;
+ int fmt_index = VISION_SOURCE_INITIAL_FD;
+ vision_source_status_e status;
+
+ /* buffer */
+ vector<v4l2_buffer> v4l2_buf {};
+ vector<void *> mmap_addr {};
+ struct pkt_dispose_cb_data pkt_data[BUFFER_MAX];
+
+ /* thead */
+ thread buffer_thread;
+ atomic_bool buffer_thread_run {};
+ stream_cb stream_callback {};
+ void *stream_user_data {};
+};
+
+static int __vision_source_get_format(uint32_t fourcc, int *pixel_format)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_RGB24:
+ *pixel_format = MEDIA_FORMAT_RGB888;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ *pixel_format = MEDIA_FORMAT_YUYV;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ *pixel_format = MEDIA_FORMAT_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ *pixel_format = MEDIA_FORMAT_NV21;
+ break;
+ default:
+ LOGW("unknown fourcc " FOURCC_FORMAT, FOURCC_CONVERT(fourcc));
+ return VISION_SOURCE_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ LOGD("fourcc " FOURCC_FORMAT " -> %d", FOURCC_CONVERT(fourcc), *pixel_format);
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_get_fourcc_plane_num(media_format_mimetype_e pixel_format, uint32_t *fourcc)
+{
+ switch (pixel_format) {
+ case MEDIA_FORMAT_RGB888:
+ *fourcc = V4L2_PIX_FMT_RGB24;
+ break;
+ case MEDIA_FORMAT_YUYV:
+ *fourcc = V4L2_PIX_FMT_YUYV;
+ break;
+ case MEDIA_FORMAT_NV12:
+ *fourcc = V4L2_PIX_FMT_NV12;
+ break;
+ case MEDIA_FORMAT_NV21:
+ *fourcc = V4L2_PIX_FMT_NV21;
+ break;
+ default:
+ LOGE("unknown format %d", pixel_format);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ LOGD("format %d -> fourcc " FOURCC_FORMAT, pixel_format, FOURCC_CONVERT(*fourcc));
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static vector<uint32_t> __vision_source_get_fps_list(int device_fd, uint32_t pixel_format, int width, int height)
+{
+ vector<uint32_t> fps_list;
+ struct v4l2_frmivalenum ival;
+
+ ival.index = 0;
+ ival.pixel_format = pixel_format;
+ ival.width = width;
+ ival.height = height;
+
+ if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {
+ LOGE("VIDIOC_ENUM_FRAMEINTERVALS failed[%d]", errno);
+ return fps_list;
+ }
+
+ if (ival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
+ LOGE("NOT V4L2_FRMIVAL_TYPE_DISCRETE -> [%u]", ival.type);
+ return fps_list;
+ }
+
+ do {
+ LOGI("\t\t\t\tFramerate[%u/%u]", ival.discrete.denominator, ival.discrete.numerator);
+ fps_list.push_back(ival.discrete.denominator);
+ ival.index++;
+ } while (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
+
+ return fps_list;
+}
+
+static int __vision_source_v4l2_qbuf(int device_fd, int type, int memory, int index)
+{
+ struct v4l2_buffer v4l2_buf;
+
+ memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+
+ v4l2_buf.index = index;
+ v4l2_buf.type = type;
+ v4l2_buf.memory = memory;
+
+ if (v4l2_ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
+ LOGE("qbuf failed. [i: %d, t: %d, m: %d] errno %d", index, type, memory, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ // LOGD("QBUF done [i: %d, t: %d, m: %d]", index, type, memory);
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_get_valid_fmt(int device_fd, vector<fmt_info> &found_fmt)
+{
+ int pixel_format = 0;
+ int pixel_index = 0;
+ int pixel_count = 0;
+
+ while (1) {
+ struct v4l2_fmtdesc v4l2_format;
+ memset(&v4l2_format, 0x0, sizeof(struct v4l2_fmtdesc));
+
+ v4l2_format.index = pixel_index;
+ v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FMT, &v4l2_format) < 0) {
+ LOGW("\tformat : end of enumeration");
+ break;
+ }
+
+ LOGD("\tformat[%d] " FOURCC_FORMAT " (emulated:%d)", pixel_index, FOURCC_CONVERT(v4l2_format.pixelformat),
+ ((v4l2_format.flags & V4L2_FMT_FLAG_EMULATED) ? 1 : 0));
+
+ if (__vision_source_get_format(v4l2_format.pixelformat, &pixel_format) != VISION_SOURCE_ERROR_NONE) {
+ pixel_index++;
+ continue;
+ }
+
+ int resolution_index = 0;
+ int resolution_count = 0;
+
+ while (1) {
+ struct v4l2_frmsizeenum v4l2_frame;
+ memset(&v4l2_frame, 0x0, sizeof(struct v4l2_frmsizeenum));
+
+ v4l2_frame.index = resolution_index;
+ v4l2_frame.pixel_format = v4l2_format.pixelformat;
+
+ if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMESIZES, &v4l2_frame) < 0) {
+ LOGW("\t\tframe : end of enumeration ");
+ break;
+ }
+
+ // TODO : support other type
+ if (v4l2_frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
+ LOGW("\t\tframe type %d needs to support", v4l2_frame.type);
+ return VISION_SOURCE_ERROR_NONE;
+ }
+
+ uint32_t width = v4l2_frame.discrete.width;
+ uint32_t height = v4l2_frame.discrete.height;
+
+ LOGD("\t\tsize[%d] %ux%u", resolution_index, width, height);
+
+ auto fps_list = __vision_source_get_fps_list(device_fd, v4l2_frame.pixel_format, width, height);
+ if (fps_list.empty()) {
+ return VISION_SOURCE_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+ resolution_count++;
+ resolution_index++;
+
+ for (auto fps : fps_list) {
+ fmt_info fmt { (media_format_mimetype_e) pixel_format, width, height, fps };
+ found_fmt.push_back(fmt);
+ }
+ }
+
+ LOGD("\t\tresolution count [%d]", resolution_count);
+ pixel_index++;
+ pixel_count++;
+ }
+
+ LOGD("\tformat count [%d]", pixel_count);
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __dev_info_from_path(const char *path, vector<fmt_info> &fmt_list)
+{
+ LOGD("check device [%s]", path);
+ int ret = VISION_SOURCE_ERROR_NONE;
+
+ int device_fd = open(path, O_RDWR);
+ if (device_fd < 0) {
+ LOGE("open failed [%s] errno %d", path, errno);
+ return ret;
+ }
+
+#ifdef HAVE_LIBV4L2
+ int libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+
+ LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
+
+ if (libv4l2_fd > 0)
+ device_fd = libv4l2_fd;
+#endif /* HAVE_LIBV4L2 */
+
+ struct v4l2_capability v4l2_cap;
+ memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
+
+ if (v4l2_ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
+ LOGE("querycap failed. errno %d", errno);
+ v4l2_close(device_fd);
+ return ret;
+ }
+
+ unsigned int dev_caps;
+
+ if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
+ dev_caps = v4l2_cap.device_caps;
+ else
+ dev_caps = v4l2_cap.capabilities;
+
+ if (!(dev_caps & V4L2_CAP_VIDEO_CAPTURE) || (dev_caps & V4L2_CAP_VIDEO_OUTPUT)) {
+ LOGW("[%s] is not a capture device 0x%x", path, dev_caps);
+ v4l2_close(device_fd);
+ return ret;
+ }
+
+ ret = __vision_source_get_valid_fmt(device_fd, fmt_list);
+
+ v4l2_close(device_fd);
+ return ret;
+}
+
+static int __vision_source_list_devices(vision_source_v4l2_s *vs_handle)
+{
+ glob_t glob_buf;
+ memset(&glob_buf, 0x0, sizeof(glob_t));
+ int ret = glob(DEVICE_NODE_PATH_PREFIX "*", 0, 0, &glob_buf);
+ if (ret != 0) {
+ switch (ret) {
+ case GLOB_NOSPACE:
+ LOGE("out of memory");
+ return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
+ case GLOB_ABORTED:
+ LOGE("read error");
+ return VISION_SOURCE_ERROR_INTERNAL;
+ case GLOB_NOMATCH:
+ LOGE("match not found");
+ return VISION_SOURCE_ERROR_NO_DATA;
+ }
+ }
+
+ LOGD("device node count : %zu", glob_buf.gl_pathc);
+
+ vector<string> &dev_name = vs_handle->dev_name;
+ vector<vector<fmt_info> > &dev_fmt_list = vs_handle->fmt_list;
+
+ for (size_t i = 0; i < glob_buf.gl_pathc; i++) {
+ vector<fmt_info> fmt_list;
+ ret = __dev_info_from_path(glob_buf.gl_pathv[i], fmt_list);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ break;
+ }
+
+ if (!fmt_list.empty()) {
+ dev_name.push_back(glob_buf.gl_pathv[i]);
+ dev_fmt_list.push_back(fmt_list);
+ }
+ }
+ globfree(&glob_buf);
+
+ if (dev_name.empty())
+ return ret;
+
+ size_t dev_count = dev_name.size();
+
+ vs_handle->dev_info = (vision_source_device_info_s *) calloc(dev_count, sizeof(vision_source_device_info_s));
+ if (!vs_handle->dev_info) {
+ return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ vs_handle->fmt = (media_format_h **) calloc(dev_count, sizeof(media_format_h *));
+ if (!vs_handle->fmt) {
+ return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (size_t i = 0; i < dev_count; i++) {
+ vs_handle->dev_info[i].index = i;
+ strncpy(vs_handle->dev_info[i].name, dev_name[i].c_str(), DEVICE_NAME_LENGTH_MAX);
+ vs_handle->fmt[i] = (media_format_h *) calloc(dev_fmt_list[i].size(), sizeof(media_format_h));
+ if (!vs_handle->fmt[i]) {
+ return VISION_SOURCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (size_t j = 0; j < dev_fmt_list[i].size(); j++) {
+ media_format_h fmt;
+ media_format_create(&fmt);
+ media_format_set_video_mime(fmt, dev_fmt_list[i][j].type);
+ media_format_set_video_width(fmt, dev_fmt_list[i][j].width);
+ media_format_set_video_height(fmt, dev_fmt_list[i][j].height);
+ media_format_set_video_frame_rate(fmt, dev_fmt_list[i][j].fps);
+ vs_handle->fmt[i][j] = fmt;
+ }
+ }
+
+ return ret;
+}
+
+static int __vision_source_v4l2_stream(int device_fd, int type, bool onoff)
+{
+ if (v4l2_ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type) < 0) {
+ LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ LOGD("stream %d (1:on, 0:off) done [t:%d]", onoff, type);
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t count, uint32_t *result_count)
+{
+ struct v4l2_requestbuffers v4l2_reqbuf;
+
+ memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers));
+
+ v4l2_reqbuf.type = type;
+ v4l2_reqbuf.memory = memory;
+ v4l2_reqbuf.count = count;
+
+ if (v4l2_ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) {
+ LOGE("REQBUFS[count %d] failed. errno %d", count, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ if (v4l2_reqbuf.count != count) {
+ LOGE("different count [req:%d, result:%d]", count, v4l2_reqbuf.count);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ *result_count = v4l2_reqbuf.count;
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_stop_stream(vision_source_v4l2_s *handle)
+{
+ LOGD("__vision_source_stop_stream");
+
+ /* stream off */
+ int ret = __vision_source_v4l2_stream(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, false);
+
+ /* munmap */
+ for (size_t i = 0; i < handle->mmap_addr.size(); i++) {
+ v4l2_munmap(handle->mmap_addr[i], handle->v4l2_buf[i].length);
+ }
+ handle->v4l2_buf.clear();
+ handle->mmap_addr.clear();
+
+ /* reqbufs 0 */
+ uint32_t buffer_count;
+ ret = __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, 0,
+ &buffer_count);
+
+ LOGD("reqbufs 0 : 0x%x", ret);
+
+ return ret;
+}
+
+static int __vision_source_set_stream(vision_source_v4l2_s *handle)
+{
+ fmt_info &fmt = handle->fmt_list[handle->device_index][handle->fmt_index];
+ struct v4l2_format v4l2_fmt;
+
+ unsigned int fourcc = 0;
+
+ int ret = __vision_source_get_fourcc_plane_num(fmt.type, &fourcc);
+ if (ret != VISION_SOURCE_ERROR_NONE)
+ return ret;
+
+ memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+ v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_fmt.fmt.pix.width = fmt.width;
+ v4l2_fmt.fmt.pix.height = fmt.height;
+ v4l2_fmt.fmt.pix.pixelformat = fourcc;
+
+ if (v4l2_ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
+ LOGE("S_FMT failed. errno %d", errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ struct v4l2_streamparm v4l2_parm;
+ /* G_PARM */
+ memset(&v4l2_parm, 0x0, sizeof(struct v4l2_streamparm));
+
+ v4l2_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (v4l2_ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) {
+ LOGE("G_PARM failed. errno %d", errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ /* S_PARM to set fps */
+ v4l2_parm.parm.capture.timeperframe.numerator = 1;
+ v4l2_parm.parm.capture.timeperframe.denominator = fmt.fps;
+
+ if (v4l2_ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) {
+ LOGE("S_PARM failed. errno %d", errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_v4l2_dqbuf(int device_fd, int type, int memory, int *index, unsigned int *used_size)
+{
+ struct v4l2_buffer v4l2_buf;
+ memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+
+ v4l2_buf.type = type;
+ v4l2_buf.memory = memory;
+
+ int ret = v4l2_ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
+ if (ret < 0) {
+ ret = errno;
+ LOGE("dqbuf failed. [t: %d, m: %d] errno %d", type, memory, ret);
+ if (ret == EIO)
+ LOGE("EIO is internal hw error");
+
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ *index = v4l2_buf.index;
+ *used_size = v4l2_buf.bytesused;
+
+ return ret;
+}
+
+static int __vision_source_v4l2_wait_frame(int device_fd, int wait_time)
+{
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(device_fd, &fds);
+
+ struct timeval timeout;
+ memset(&timeout, 0x0, sizeof(struct timeval));
+
+ timeout.tv_sec = wait_time;
+ timeout.tv_usec = 0;
+
+ /*LOGD("select : %d sec", wait_time);*/
+
+ int ret = select(device_fd + 1, &fds, NULL, NULL, &timeout);
+ if (ret == -1) {
+ ret = errno;
+ if (ret == EINTR) {
+ LOGD("select error : EINTR");
+ return VISION_SOURCE_ERROR_NONE;
+ }
+ LOGE("select failed. errno %d", ret);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+ if (ret == 0) {
+ LOGE("select timeout.");
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static int __vision_source_mmap(vision_source_v4l2_s *handle)
+{
+ /* query buffer, mmap and qbuf */
+ for (int i = 0; i < BUFFER_MAX; i++) {
+ struct v4l2_buffer v4l2_buf;
+ memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buf.index = i;
+
+ if (v4l2_ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
+ LOGE("[%d] query buf failed. errno %d", i, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ handle->v4l2_buf.push_back(v4l2_buf);
+
+ void *data =
+ v4l2_mmap(0, v4l2_buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, handle->device_fd, v4l2_buf.m.offset);
+
+ if (data == MAP_FAILED) {
+ LOGE("[%d] mmap failed (errno %d)", i, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ handle->mmap_addr.push_back(data);
+
+ if (__vision_source_v4l2_qbuf(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, i) !=
+ VISION_SOURCE_ERROR_NONE) {
+ LOGE("[%d] qbuf failed (errno %d)", i, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+ }
+
+ /* stream on */
+ return __vision_source_v4l2_stream(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, true);
+}
+
+static int __vision_source_start_stream(vision_source_v4l2_s *handle)
+{
+ uint32_t buffer_count = 0;
+ /* request buffer */
+ int ret = __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, BUFFER_MAX,
+ &buffer_count);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ return ret;
+ }
+
+ LOGD("buffer count : request %d -> result %d", BUFFER_MAX, buffer_count);
+
+ ret = __vision_source_mmap(handle);
+ if (ret != VISION_SOURCE_ERROR_NONE)
+ __vision_source_v4l2_reqbufs(handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, 0,
+ &buffer_count);
+
+ return ret;
+}
+
+int vision_source_init(vision_source_h *handle)
+{
+ vision_source_v4l2_s *v4l2_handle = new vision_source_v4l2_s;
+
+ int ret = __vision_source_list_devices(v4l2_handle);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ free(v4l2_handle);
+ LOGE("get device info failed");
+ return ret;
+ }
+
+ v4l2_handle->status = VISION_SOURCE_STATUS_INITIALIZED;
+ *handle = v4l2_handle;
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static void __vision_source_release_handle(vision_source_v4l2_s *handle)
+{
+ for (size_t i = 0; i < handle->fmt_list.size(); i++) {
+ for (size_t j = 0; j < handle->fmt_list[i].size(); j++) {
+ media_format_unref(handle->fmt[i][j]);
+ }
+ free(handle->fmt[i]);
+ }
+ free(handle->fmt);
+ free(handle->dev_info);
+
+ LOGD("vision_source_v4l2_s %p destroy", handle);
+
+ return;
+}
+
+int vision_source_exit(vision_source_h handle)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->dev_info)
+ __vision_source_release_handle(v4l2_handle);
+ delete v4l2_handle;
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+int vision_source_list_devices(vision_source_h handle, vision_source_device_info_s **dev_list, int *dev_count)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ *dev_list = v4l2_handle->dev_info;
+ *dev_count = v4l2_handle->dev_name.size();
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+int vision_source_get_device_cap(vision_source_h handle, int dev_index, media_format_h **fmt_list, int *fmt_count)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (dev_index < 0 || (size_t) dev_index >= v4l2_handle->fmt_list.size())
+ return VISION_SOURCE_ERROR_INVALID_PARAMETER;
+
+ *fmt_list = v4l2_handle->fmt[dev_index];
+ *fmt_count = v4l2_handle->fmt_list[dev_index].size();
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+int vision_source_open_device(vision_source_h handle, int dev_index)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->status != VISION_SOURCE_STATUS_INITIALIZED) {
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+ }
+
+ if (dev_index < 0 || (size_t) dev_index >= v4l2_handle->fmt_list.size())
+ return VISION_SOURCE_ERROR_INVALID_PARAMETER;
+
+ int device_fd = VISION_SOURCE_INITIAL_FD;
+#ifdef HAVE_LIBV4L2
+ int libv4l2_fd = VISION_SOURCE_INITIAL_FD;
+#endif /* HAVE_LIBV4L2 */
+
+ char *node_path = v4l2_handle->dev_info[dev_index].name;
+
+ device_fd = open(node_path, O_RDWR);
+ if (device_fd < 0) {
+ LOGE("open [%s] failed [errno %d]", node_path, errno);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+#ifdef HAVE_LIBV4L2
+ libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+
+ LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
+
+ if (libv4l2_fd != VISION_SOURCE_INITIAL_FD)
+ device_fd = libv4l2_fd;
+#endif /* HAVE_LIBV4L2 */
+
+ v4l2_handle->device_index = dev_index;
+ v4l2_handle->device_fd = device_fd;
+ v4l2_handle->status = VISION_SOURCE_STATUS_OPENDED;
+
+ LOGD("[%d] device[%s] opened [fd %d]", dev_index, node_path, device_fd);
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+int vision_source_close_device(vision_source_h handle)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+ }
+
+ if (v4l2_handle->device_fd < 0) {
+ LOGE("invalid fd %d", v4l2_handle->device_fd);
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ LOGD("close fd %d", v4l2_handle->device_fd);
+
+ v4l2_close(v4l2_handle->device_fd);
+
+ v4l2_handle->status = VISION_SOURCE_STATUS_INITIALIZED;
+ LOGD("device [%d] closed", v4l2_handle->device_index);
+ v4l2_handle->device_fd = VISION_SOURCE_INITIAL_FD;
+ v4l2_handle->device_index = VISION_SOURCE_INITIAL_FD;
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+int vision_source_set_stream_format(vision_source_h handle, media_format_h fmt)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (!v4l2_handle->fmt || v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
+ LOGE("Invalid state");
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+ }
+
+ media_format_mimetype_e mimetype;
+ int width, height, fps;
+ int ret = media_format_get_video_info(fmt, &mimetype, &width, &height, nullptr, nullptr);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ LOGE("media_format_get_video_info failed");
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+ ret = media_format_get_video_frame_rate(fmt, &fps);
+ if (ret != MEDIA_FORMAT_ERROR_NONE) {
+ LOGE("media_format_get_video_info failed");
+ return VISION_SOURCE_ERROR_INTERNAL;
+ }
+
+ LOGI("Try set format width: %d, height: %d, fps: %d", width, height, fps);
+
+ fmt_info request { mimetype, (uint32_t) width, (uint32_t) height, (uint32_t) fps };
+ vector<fmt_info> &vec = v4l2_handle->fmt_list[v4l2_handle->device_index];
+ const auto pos = find(vec.begin(), vec.end(), request);
+ if (pos == vec.end()) {
+ LOGE("Not supported format");
+ return VISION_SOURCE_ERROR_INVALID_PARAMETER;
+ }
+
+ auto index = distance(vec.begin(), pos);
+ if (v4l2_handle->fmt_index == index) {
+ LOGD("no need to restart preview stream");
+ return VISION_SOURCE_ERROR_NONE;
+ }
+
+ v4l2_handle->fmt_index = index;
+
+ ret = __vision_source_set_stream(v4l2_handle);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ LOGE("failed to set stream");
+ return ret;
+ }
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+static void __vision_source_pkt_dispose_cb(media_packet_h packet, void *user_data)
+{
+ pkt_dispose_cb_data *data = (pkt_dispose_cb_data *) user_data;
+
+ int ret = __vision_source_v4l2_qbuf(data->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, data->index);
+ if (ret != VISION_SOURCE_ERROR_NONE)
+ LOGE("qbuf failed");
+}
+
+static void __fetch_buffer_and_callback(vision_source_v4l2_s *v4l2_handle)
+{
+ LOGD("__fetch_buffer_and_callback");
+
+ int index;
+ unsigned int byte_size;
+ int ret;
+
+ for (size_t i = 0; i < BUFFER_MAX; i++) {
+ v4l2_handle->pkt_data[i].fd = v4l2_handle->device_fd;
+ v4l2_handle->pkt_data[i].index = i;
+ }
+
+ while (v4l2_handle->buffer_thread_run) {
+ LOGD("__fetch_buffer_and_callback: waiting for buffer");
+ ret = __vision_source_v4l2_wait_frame(v4l2_handle->device_fd, 5);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ LOGE("frame wait failed");
+ break;
+ }
+
+ if (v4l2_handle->buffer_thread_run == false) {
+ LOGD("stop buffer handler thread");
+ break;
+ }
+ ret = __vision_source_v4l2_dqbuf(v4l2_handle->device_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_MEMORY_MMAP, &index,
+ &byte_size);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ LOGE("dqbuf failed");
+ break;
+ }
+
+ media_format_h fmt = v4l2_handle->fmt[v4l2_handle->device_index][v4l2_handle->fmt_index];
+
+ media_packet_h pkt;
+ ret = media_packet_new_from_external_memory(fmt, v4l2_handle->mmap_addr[index], byte_size,
+ __vision_source_pkt_dispose_cb, &v4l2_handle->pkt_data[index],
+ &pkt);
+ if (ret != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("media_packet_new_from_external_memory failed");
+ continue;
+ }
+ if (v4l2_handle->stream_callback) {
+ v4l2_handle->stream_callback(pkt, v4l2_handle->stream_user_data);
+ }
+
+ media_packet_unref(pkt);
+ sched_yield();
+ }
+
+ return;
+}
+
+int vision_source_start_stream(vision_source_h handle)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED) {
+ LOGE("status is not VISION_SOURCE_STATUS_OPENDED");
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+ }
+ if (v4l2_handle->fmt_index < 0) {
+ LOGE("format is not set");
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+ }
+
+ int ret = __vision_source_start_stream(v4l2_handle);
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ LOGE("__vision_source_start_stream failed[0x%x]", ret);
+ return ret;
+ }
+
+ v4l2_handle->buffer_thread_run = true;
+ v4l2_handle->buffer_thread = thread(__fetch_buffer_and_callback, v4l2_handle);
+
+ v4l2_handle->status = VISION_SOURCE_STATUS_STARTED;
+ LOGD("start preview done");
+
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+/*
+ * TODO: buffer_thread has some problem, what happend to buffer?
+ */
+int vision_source_stop_stream(vision_source_h handle)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->status != VISION_SOURCE_STATUS_STARTED)
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+
+ v4l2_handle->buffer_thread_run = false;
+ v4l2_handle->buffer_thread.join();
+ LOGI("buffer thread stopped and joined");
+
+ int ret = __vision_source_stop_stream(v4l2_handle);
+ if (ret != VISION_SOURCE_ERROR_NONE)
+ LOGE("__vision_source_stop_stream failed, but buffer thread will be stopped");
+
+ v4l2_handle->fmt_index = VISION_SOURCE_INITIAL_FD;
+ v4l2_handle->stream_callback = nullptr;
+ v4l2_handle->stream_user_data = nullptr;
+ v4l2_handle->status = VISION_SOURCE_STATUS_OPENDED;
+ LOGD("stop preview done [0x%x]", ret);
+
+ return ret;
+}
+
+/* TODO: run-time callback change*/
+int vision_source_set_stream_cb(vision_source_h handle, stream_cb callback, void *user_data)
+{
+ vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
+
+ if (v4l2_handle->status != VISION_SOURCE_STATUS_OPENDED)
+ return VISION_SOURCE_ERROR_INVALID_OPERATION;
+
+ v4l2_handle->stream_callback = callback;
+ v4l2_handle->stream_user_data = user_data;
+ return VISION_SOURCE_ERROR_NONE;
+}
+
+#ifdef USE_DL
+void attach_backend(vision_source_func_s *funcp)
+{
+ funcp->init = vision_source_v4l2_init;
+ funcp->exit = vision_source_v4l2_exit;
+ funcp->list_devices = vision_source_v4l2_list_devices;
+ funcp->get_device_cap = vision_source_v4l2_get_device_cap;
+ funcp->open_device = vision_source_v4l2_open_device;
+ funcp->close_device = vision_source_v4l2_close_device;
+ funcp->set_stream_format = vision_source_v4l2_set_stream_format;
+ funcp->start_stream = vision_source_v4l2_start_stream;
+ funcp->stop_stream = vision_source_v4l2_stop_stream;
+ funcp->set_stream_cb = vision_source_v4l2_set_stream_cb;
+}
+#endif
+++ /dev/null
-/**
- * Copyright (c) 2022s Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __VISION_SOURCE_V4L2_PRIVATE_H__
-#define __VISION_SOURCE_V4L2_PRIVATE_H__
-
-#include <vision_source_interface.h>
-#include <glib.h>
-#include <linux/videodev2.h>
-#include <dlog.h>
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#ifdef HAVE_LIBV4L2
-#include <libv4l2.h>
-#else
-#define v4l2_fd_open(fd, flags) (fd)
-#define v4l2_close close
-#define v4l2_dup dup
-#define v4l2_ioctl ioctl
-#define v4l2_read read
-#define v4l2_mmap mmap
-#define v4l2_munmap munmap
-#endif /* ENABLE_LIBV4L2 */
-
-#define LOG_TAG "VISION_SOURCE_V4L2"
-
-#define VISION_SOURCE_CHECK_CONDITION(condition, error, msg) \
- do { \
- if (!(condition)) { \
- LOGE("[%s] %s(0x%08x)", __FUNCTION__, msg, error); \
- return error; \
- } \
- } while (0)
-
-#define VISION_SOURCE_NULL_ARG_CHECK(arg) \
- VISION_SOURCE_CHECK_CONDITION(arg != NULL, \
- VISION_SOURCE_ERROR_INVALID_PARAMETER, \
- "VISION_SOURCE_ERROR_INVALID_PARAMETER")
-
-#define CAMERA_HAL_INITIAL_INDEX -1
-#define CAMERA_HAL_INITIAL_FD -1
-#define MESSAGE_CALLBACK_MAX 10
-#define BUFFER_MAX 4
-#define V4L2_PLANES_MAX 4
-#define EXTRA_PREVIEW_STREAM_MAX 10
-
-typedef struct _vision_source_v4l2_s
-{
- /* device */
- gint32 device_index;
- gint32 device_fd;
- vision_source_device_info_list_s *device_info_list;
-
- /* buffer */
- guint32 buffer_dequeued_count;
- GThread *buffer_thread;
- gboolean buffer_thread_run;
- guint32 buffer_count;
- struct vision_source_buffer vision_source_buffers[BUFFER_MAX];
- enum v4l2_buf_type buffer_type;
- GMutex buffer_lock;
- GCond buffer_cond;
-
- /* stream */
- struct vision_source_format stream_format;
- stream_cb stream_callback;
- gpointer stream_callback_data;
-
- /* etc */
- GMutex lock;
-} vision_source_v4l2_s;
-
-typedef struct _packet_context_s
-{
- int device_fd;
- int type;
- int memory;
- int index;
-} packet_context_s;
-#endif /* __VISION_SOURCE_V4L2_PRIVATE_H__ */
\ No newline at end of file
project(test-vision-source-v4l2)
include(FindPkgConfig)
-pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED vision-source)
add_executable(${PROJECT_NAME}
test_vision_source_v4l2.cpp
)
-target_link_libraries(${PROJECT_NAME}
- ${${PROJECT_NAME}_DEP_LIBRARIES}
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ vision-source-v4l2
gtest gtest_main
)
-target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_DEP_INCLUDE_DIRS})
+
+target_include_directories(${PROJECT_NAME} PRIVATE
+ /usr/include/media
+)
# install packages
-INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
\ No newline at end of file
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
#include <gtest/gtest.h>
+#include <media_packet.h>
#include <vision_source.h>
class VisionV4L2 : public ::testing::Test
vision_source_h ms_handle;
};
-TEST_F(VisionV4L2, EnumerateDev)
+TEST_F(VisionV4L2, ListDevices)
{
- vision_source_device_info_list_s dev_list;
- ASSERT_EQ(vision_source_enumerate_devices(ms_handle, &dev_list),
- VISION_SOURCE_ERROR_NONE);
- EXPECT_GT(dev_list.count, 0);
+ vision_source_device_info_s *dev_list;
+ int dev_cnt;
+ ASSERT_EQ(vision_source_list_devices(ms_handle, &dev_list, &dev_cnt), VISION_SOURCE_ERROR_NONE);
+ EXPECT_GT(dev_cnt, 0);
+}
+
+TEST_F(VisionV4L2, DevCap)
+{
+ vision_source_device_info_s *dev_list;
+ media_format_h *fmt_list;
+ int fmt_count;
+ int dev_cnt;
+ ASSERT_EQ(vision_source_list_devices(ms_handle, &dev_list, &dev_cnt), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(dev_cnt, 0);
+ ASSERT_EQ(vision_source_get_device_cap(ms_handle, 0, &fmt_list, &fmt_count), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(fmt_count, 0);
}
TEST_F(VisionV4L2, OpenDev0)
{
- ASSERT_EQ(vision_source_open_device(ms_handle, 0),
- VISION_SOURCE_ERROR_NONE);
+ ASSERT_EQ(vision_source_open_device(ms_handle, 0), VISION_SOURCE_ERROR_NONE);
EXPECT_EQ(vision_source_close_device(ms_handle), VISION_SOURCE_ERROR_NONE);
}
+TEST_F(VisionV4L2, NotOpenDev)
+{
+ vision_source_device_info_s *dev_list;
+ media_format_h *fmt_list;
+ int fmt_count;
+ int dev_cnt;
+ ASSERT_EQ(vision_source_list_devices(ms_handle, &dev_list, &dev_cnt), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(dev_cnt, 0);
+ ASSERT_EQ(vision_source_get_device_cap(ms_handle, 0, &fmt_list, &fmt_count), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(fmt_count, 2);
+ EXPECT_EQ(vision_source_set_stream_format(ms_handle, fmt_list[2]), VISION_SOURCE_ERROR_INVALID_OPERATION);
+}
+
TEST_F(VisionV4L2, SetStream)
{
- vision_source_device_info_list_s dev_list;
- ASSERT_EQ(vision_source_enumerate_devices(ms_handle, &dev_list),
- VISION_SOURCE_ERROR_NONE);
- ASSERT_GT(dev_list.count, 0);
-
- ASSERT_GT(dev_list.device_info[0].pixel_list.count, 0);
- vision_source_format_s format;
- format.pixel_format =
- dev_list.device_info[0].pixel_list.pixels[0].pixel_format;
- ASSERT_GT(
- dev_list.device_info[0].pixel_list.pixels[0].resolution_list.count,
- 0);
-
- format.resolution.width = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .resolution.width;
- format.resolution.height = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .resolution.height;
- ASSERT_GT(dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .fps_list.count,
- 0);
- format.fps = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .fps_list.fps[0];
-
- ASSERT_EQ(vision_source_open_device(ms_handle, 0),
- VISION_SOURCE_ERROR_NONE);
- EXPECT_EQ(vision_source_set_stream_format(ms_handle, &format),
- VISION_SOURCE_ERROR_NONE);
+ vision_source_device_info_s *dev_list;
+ media_format_h *fmt_list;
+ int fmt_count;
+ int dev_cnt;
+ ASSERT_EQ(vision_source_list_devices(ms_handle, &dev_list, &dev_cnt), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(dev_cnt, 0);
+ ASSERT_EQ(vision_source_get_device_cap(ms_handle, 0, &fmt_list, &fmt_count), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(fmt_count, 2);
+ ASSERT_EQ(vision_source_open_device(ms_handle, 0), VISION_SOURCE_ERROR_NONE);
+ EXPECT_EQ(vision_source_set_stream_format(ms_handle, fmt_list[2]), VISION_SOURCE_ERROR_NONE);
EXPECT_EQ(vision_source_close_device(ms_handle), VISION_SOURCE_ERROR_NONE);
}
void SetUp() override
{
ASSERT_EQ(vision_source_init(&ms_handle), VISION_SOURCE_ERROR_NONE);
- vision_source_device_info_list_s dev_list;
- ASSERT_EQ(vision_source_enumerate_devices(ms_handle, &dev_list),
- VISION_SOURCE_ERROR_NONE);
- ASSERT_GT(dev_list.count, 0);
-
- ASSERT_GT(dev_list.device_info[0].pixel_list.count, 0);
- vision_source_format_s format;
- format.pixel_format =
- dev_list.device_info[0].pixel_list.pixels[0].pixel_format;
- ASSERT_GT(dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.count,
- 0);
-
- format.resolution.width = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .resolution.width;
- format.resolution.height = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .resolution.height;
- ASSERT_GT(dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .fps_list.count,
- 0);
- format.fps = dev_list.device_info[0]
- .pixel_list.pixels[0]
- .resolution_list.resolutions[0]
- .fps_list.fps[0];
-
- ASSERT_EQ(vision_source_open_device(ms_handle, 0),
- VISION_SOURCE_ERROR_NONE);
- EXPECT_EQ(vision_source_set_stream_format(ms_handle, &format),
- VISION_SOURCE_ERROR_NONE);
+ vision_source_device_info_s *dev_list;
+ media_format_h *fmt_list;
+ int fmt_count;
+ int dev_cnt;
+
+ ASSERT_EQ(vision_source_list_devices(ms_handle, &dev_list, &dev_cnt), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(dev_cnt, 0);
+ ASSERT_EQ(vision_source_get_device_cap(ms_handle, 0, &fmt_list, &fmt_count), VISION_SOURCE_ERROR_NONE);
+ ASSERT_GT(fmt_count, 2);
+
+ ASSERT_EQ(vision_source_open_device(ms_handle, 0), VISION_SOURCE_ERROR_NONE);
+ ASSERT_EQ(vision_source_set_stream_format(ms_handle, fmt_list[2]), VISION_SOURCE_ERROR_NONE);
}
void TearDown() override
{
- EXPECT_EQ(vision_source_close_device(ms_handle),
- VISION_SOURCE_ERROR_NONE);
+ EXPECT_EQ(vision_source_close_device(ms_handle), VISION_SOURCE_ERROR_NONE);
ASSERT_EQ(vision_source_exit(ms_handle), VISION_SOURCE_ERROR_NONE);
}
vision_source_h ms_handle;
TEST_F(VisionV4L2FixedFormat, OnlyStopStream)
{
- EXPECT_EQ(vision_source_stop_stream(ms_handle), VISION_SOURCE_ERROR_NONE);
+ EXPECT_EQ(vision_source_stop_stream(ms_handle), VISION_SOURCE_ERROR_INVALID_OPERATION);
}
TEST_F(VisionV4L2FixedFormat, StartStream)
{
- ASSERT_EQ(vision_source_start_stream(ms_handle, nullptr, nullptr),
- VISION_SOURCE_ERROR_NONE);
- sleep(1);
+ ASSERT_EQ(vision_source_start_stream(ms_handle), VISION_SOURCE_ERROR_NONE);
+ sleep(5);
EXPECT_EQ(vision_source_stop_stream(ms_handle), VISION_SOURCE_ERROR_NONE);
}
double delta_ms = (double) (end - *start) / CLOCKS_PER_SEC * 1000;
- snprintf(filename, 127, "out_%04u.data", (unsigned) delta_ms);
+ snprintf(filename, 127, "/opt/usr/home/owner/media/Images/out_%04u.data", (unsigned) delta_ms);
file = fopen(filename, "w");
- if (!file)
- return VISION_SOURCE_ERROR_INTERNAL;
- char *data;
+ void *data;
uint64_t size;
- media_packet_get_buffer_data_ptr(pkt, (void **) &data);
+ media_packet_get_buffer_data_ptr(pkt, &data);
media_packet_get_buffer_size(pkt, &size);
+
fwrite(data, sizeof(unsigned char), size, file);
fclose(file);
return 0;
TEST_F(VisionV4L2FixedFormat, StartWithCallback)
{
clock_t start = clock();
- ASSERT_EQ(vision_source_start_stream(ms_handle, test_cb, &start),
- VISION_SOURCE_ERROR_NONE);
- sleep(1);
+ ASSERT_EQ(vision_source_set_stream_cb(ms_handle, test_cb, &start), VISION_SOURCE_ERROR_NONE);
+ ASSERT_EQ(vision_source_start_stream(ms_handle), VISION_SOURCE_ERROR_NONE);
+ sleep(5);
EXPECT_EQ(vision_source_stop_stream(ms_handle), VISION_SOURCE_ERROR_NONE);
-}
\ No newline at end of file
+}