--- /dev/null
+cmake_minimum_required(VERSION 3.0.0)
+project(vision-source-v4l2)
+
+OPTION(HAVE_LIBV4L2 "Option description" 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()
+
+add_library(${PROJECT_NAME}
+ src/vision_source_v4l2.c
+)
+
+target_link_libraries(${PROJECT_NAME}
+ ${${PROJECT_NAME}_DEP_LIBRARIES}
+)
+target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_DEP_INCLUDE_DIRS})
+
+# install packages
+install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
+
+add_subdirectory(test)
\ No newline at end of file
--- /dev/null
+Copyright (c) 2000 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
--- /dev/null
+%define enable_libv4l2 1
+
+Name: vision-source-v4l2
+Summary: vision source-v4l2
+Version: 0.0.1
+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: gtest-devel
+%if 0%{?enable_libv4l2}
+BuildRequires: pkgconfig(libv4l2)
+%endif
+
+%description
+Vision source v4l2
+
+%prep
+%setup -q
+
+%build
+%if 0%{?sec_build_binary_debug_enable}
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+%endif
+
+%cmake \
+%if 0%{?enable_libv4l2}
+ -DHAVE_LIBV4L2=ON \
+%endif
+.
+
+make %{?jobs:-j%jobs}
+
+%install
+
+%make_install
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+
+%files
+%{_libdir}/*.so
+%{_bindir}/*
+%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 vision_source_device_info_list_s *g_device_info_list;
+static guint32 g_device_caps;
+static GMutex g_device_info_lock;
+
+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_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(void)
+{
+ 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;
+
+ g_mutex_lock(&g_device_info_lock);
+
+ if (g_device_info_list) {
+ LOGD("device info list is already existed");
+ ret = VISION_SOURCE_ERROR_NONE;
+ goto _GET_DEVICE_INFO_LIST_DONE;
+ }
+
+ 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;
+ g_device_info_list = device_info_list;
+
+ LOGD("new g_device_info_list %p - device count %d", g_device_info_list,
+ device_count);
+
+_GET_DEVICE_INFO_LIST_DONE:
+ g_mutex_unlock(&g_device_info_lock);
+ LOGD("ret 0x%x", ret);
+
+ 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);
+
+ LOGD("vision_source_v4l2_s %p destroy", handle);
+
+ g_free(handle);
+
+ return;
+}
+
+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;
+ }
+
+ g_mutex_init(&v4l2_handle->lock);
+ g_mutex_init(&v4l2_handle->buffer_lock);
+ g_cond_init(&v4l2_handle->buffer_cond);
+
+ v4l2_handle->device_index = CAMERA_HAL_INITIAL_INDEX;
+ v4l2_handle->device_fd = CAMERA_HAL_INITIAL_FD;
+ v4l2_handle->buffer_thread = NULL;
+
+ int ret = __vision_source_get_device_info_list();
+ if (ret != VISION_SOURCE_ERROR_NONE) {
+ LOGE("get device info failed");
+ goto _INIT_ERROR;
+ }
+
+ *handle = v4l2_handle;
+
+ return VISION_SOURCE_ERROR_NONE;
+
+_INIT_ERROR:
+ __vision_source_release_handle(v4l2_handle);
+
+ return ret;
+}
+
+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;
+}
+
+void attach_backend(vision_source_func_s *funcp)
+{
+ funcp->init = vision_source_v4l2_init;
+ funcp->exit = vision_source_v4l2_exit;
+}
--- /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;
+
+ /* 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;
+
+ /* etc */
+ GMutex lock;
+} vision_source_v4l2_s;
+
+#endif /* __VISION_SOURCE_V4L2_PRIVATE_H__ */
\ No newline at end of file
--- /dev/null
+cmake_minimum_required(VERSION 3.0.0)
+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}
+ gtest gtest_main
+)
+target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_DEP_INCLUDE_DIRS})
+
+# install packages
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
\ No newline at end of file
--- /dev/null
+#include <gtest/gtest.h>
+#include <vision_source.h>
+
+class VisionV4L2 : public ::testing::Test
+{
+protected:
+ void SetUp() override
+ {
+ ASSERT_EQ(vision_source_init(&ms_handle), VISION_SOURCE_ERROR_NONE);
+ }
+
+ void TearDown() override
+ {
+ ASSERT_EQ(vision_source_exit(ms_handle), VISION_SOURCE_ERROR_NONE);
+ }
+ vision_source_h ms_handle;
+};
+
+TEST_F(VisionV4L2, Base)
+{
+ ASSERT_EQ(1, 1);
+}
\ No newline at end of file