Add vision_source_v4l2_set_stream_format 77/278877/1 accepted/tizen/unified/20220729.131711 submit/tizen/20220728.094515
authorKwanghoon Son <k.son@samsung.com>
Wed, 27 Jul 2022 08:20:43 +0000 (04:20 -0400)
committerKwanghoon Son <k.son@samsung.com>
Wed, 27 Jul 2022 08:20:43 +0000 (04:20 -0400)
[Version] : 0.0.4
[Issue type] New function

Add v4l2 backend set stream function

Change-Id: Ibbf304853303557c96fee066b17541e87d114bbb
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 e58a090..8619d87 100644 (file)
@@ -2,7 +2,7 @@
 
 Name:        vision-source-v4l2
 Summary:     vision source-v4l2
-Version:     0.0.3
+Version:     0.0.4
 Release:     0
 Group:       Multimedia/Framework
 License:     Apache-2.0
index 86cbcc7..35d5221 100644 (file)
@@ -462,6 +462,83 @@ static int __vision_source_stop_stream(vision_source_v4l2_s *handle,
        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 {
+               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;
+}
+
 int vision_source_v4l2_init(vision_source_h *handle)
 {
        LOGD("enter");
@@ -614,6 +691,94 @@ int vision_source_v4l2_close_device(vision_source_h handle)
        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;
+}
+
 void attach_backend(vision_source_func_s *funcp)
 {
        funcp->init = vision_source_v4l2_init;
@@ -621,4 +786,5 @@ void attach_backend(vision_source_func_s *funcp)
        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;
 }
\ No newline at end of file
index 5dfa5f0..5e6e26a 100644 (file)
@@ -29,4 +29,44 @@ 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);
+}
+
+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);
+       EXPECT_EQ(vision_source_close_device(ms_handle), VISION_SOURCE_ERROR_NONE);
 }
\ No newline at end of file