Add vision_source_v4l2_{open,close}_devices 48/278848/3
authorKwanghoon Son <k.son@samsung.com>
Wed, 27 Jul 2022 02:09:20 +0000 (22:09 -0400)
committerKwanghoon Son <k.son@samsung.com>
Wed, 27 Jul 2022 03:09:25 +0000 (23:09 -0400)
[Version] : 0.0.3
[Issue type] New function

Add v4l2 backend open, close function

Change-Id: I2ced7b3fa7e2c41f959d67954cc16c72159bd720
Signed-off-by: Kwanghoon Son <k.son@samsung.com>
packaging/vision-source-v4l2.spec
src/vision_source_v4l2.c
test/test_vision_source_v4l2.cpp

index b34babd..e58a090 100644 (file)
@@ -2,7 +2,7 @@
 
 Name:        vision-source-v4l2
 Summary:     vision source-v4l2
-Version:     0.0.2
+Version:     0.0.3
 Release:     0
 Group:       Multimedia/Framework
 License:     Apache-2.0
index f310b6d..86cbcc7 100644 (file)
@@ -32,7 +32,6 @@
                        (fourcc >> 24) & 0xff
 
 static guint32 g_device_caps;
-static GMutex g_device_info_lock;
 
 static int __vision_source_get_format(guint32 fourcc, int *pixel_format)
 {
@@ -248,8 +247,6 @@ static int __vision_source_get_device_info_list(
        struct v4l2_capability v4l2_cap;
        vision_source_device_info_list_s *device_info_list = NULL;
 
-       g_mutex_lock(&g_device_info_lock);
-
        device_info_list = g_new0(vision_source_device_info_list_s, 1);
        if (!device_info_list) {
                LOGE("failed to alloc device info structure");
@@ -342,7 +339,6 @@ static int __vision_source_get_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)
@@ -371,6 +367,101 @@ static void __vision_source_release_handle(vision_source_v4l2_s *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;
+}
+
 int vision_source_v4l2_init(vision_source_h *handle)
 {
        LOGD("enter");
@@ -384,15 +475,19 @@ int vision_source_v4l2_init(vision_source_h *handle)
                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);
 
-       v4l2_handle->device_index = CAMERA_HAL_INITIAL_INDEX;
-       v4l2_handle->device_fd = CAMERA_HAL_INITIAL_FD;
-       v4l2_handle->buffer_thread = NULL;
-       v4l2_handle->device_info_list = NULL;
-
        *handle = v4l2_handle;
 
        return VISION_SOURCE_ERROR_NONE;
@@ -419,19 +514,103 @@ int vision_source_v4l2_enumerate_devices(
        VISION_SOURCE_NULL_ARG_CHECK(info_list);
 
        vision_source_v4l2_s *v4l2_handle = (vision_source_v4l2_s *) handle;
-       int ret;
 
-       if (!v4l2_handle->device_info_list)
-               ret = __vision_source_get_device_info_list(
+       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;
+               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;
 }
 
@@ -440,4 +619,6 @@ 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;
 }
\ No newline at end of file
index 8ea0f42..5dfa5f0 100644 (file)
@@ -22,4 +22,11 @@ TEST_F(VisionV4L2, EnumerateDev)
        ASSERT_EQ(vision_source_enumerate_devices(ms_handle, &dev_list),
                          VISION_SOURCE_ERROR_NONE);
        EXPECT_GT(dev_list.count, 0);
+}
+
+TEST_F(VisionV4L2, OpenDev0)
+{
+       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);
 }
\ No newline at end of file