From: Jeongmo Yang Date: Thu, 23 Jul 2020 10:56:57 +0000 (+0900) Subject: Support capture function X-Git-Tag: accepted/tizen/6.0/unified/20201030.123220^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F89%2F239289%2F5;p=platform%2Fadaptation%2Fcamera-hal-v4l2.git Support capture function - Additional changes : Remove or rename some member variables in camera_hal_handle : Move S_FMT/S_PARM code to __camera_start_stream() : Remove debug log [Version] 0.0.12 [Profile] Common [Issue Type] Update Change-Id: If3737f434b0248b8e3df2b261844a48139b248a1 Signed-off-by: Jeongmo Yang --- diff --git a/packaging/camera-hal-v4l2.spec b/packaging/camera-hal-v4l2.spec index 58bdca4..353c6a3 100644 --- a/packaging/camera-hal-v4l2.spec +++ b/packaging/camera-hal-v4l2.spec @@ -1,6 +1,6 @@ Name: camera-hal-v4l2 Summary: Tizen Camera Hal for V4L2 -Version: 0.0.11 +Version: 0.0.12 Release: 0 Group: Multimedia/Libraries License: Apache-2.0 diff --git a/src/tizen_camera_v4l2.c b/src/tizen_camera_v4l2.c index 2b4b06d..0ade153 100644 --- a/src/tizen_camera_v4l2.c +++ b/src/tizen_camera_v4l2.c @@ -322,7 +322,7 @@ static int __camera_get_format(guint32 fourcc, int *pixel_format) return CAMERA_ERROR_NONE; } -static int __camera_get_fourcc_plane_num(int pixel_format, guint32 *fourcc, uint8_t *plane_num) +static int __camera_get_fourcc_plane_num(int pixel_format, guint32 *fourcc, guint32 *plane_num) { if (!fourcc || !plane_num) { LOGE("NULL parameter %p %p", fourcc, plane_num); @@ -522,7 +522,7 @@ static int __camera_get_device_info_list(void) ret = CAMERA_ERROR_INTERNAL; goto _GET_DEVICE_INFO_LIST_DONE; default: - LOGE("unknown eror : %d", ret); + LOGE("unknown error : %d", ret); ret = CAMERA_ERROR_INTERNAL; goto _GET_DEVICE_INFO_LIST_DONE; } @@ -598,7 +598,7 @@ static int __camera_stop_stream(camera_hal_handle *handle, uint32_t buffer_count LOGD("buffer count[%d]", buffer_count); /* stream off */ - ret = __camera_v4l2_stream(handle->device_fd, handle->v4l2_type, FALSE); + ret = __camera_v4l2_stream(handle->device_fd, handle->buffer_type, FALSE); LOGD("stream off : 0x%x", ret); @@ -618,7 +618,7 @@ static int __camera_stop_stream(camera_hal_handle *handle, uint32_t buffer_count /* reqbufs 0 */ ret = __camera_v4l2_reqbufs(handle->device_fd, - handle->v4l2_type, V4L2_MEMORY_MMAP, 0, &buffer_count); + handle->buffer_type, V4L2_MEMORY_MMAP, 0, &buffer_count); LOGD("reqbufs 0 : 0x%x", ret); @@ -626,60 +626,116 @@ static int __camera_stop_stream(camera_hal_handle *handle, uint32_t buffer_count } -static int __camera_start_stream(camera_hal_handle *handle, camera_format_t *format, - uint32_t request_buffer_count, uint32_t *result_buffer_count) +static int __camera_start_stream(camera_hal_handle *handle, camera_pixel_format_t pixel_format, + camera_resolution_t *resolution, uint32_t fps, uint32_t request_buffer_count) { int i = 0; int ret = CAMERA_ERROR_NONE; camera_buffer_t *buffer = NULL; + struct v4l2_format v4l2_fmt; + struct v4l2_streamparm v4l2_parm; struct v4l2_buffer v4l2_buf; - struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX]; + struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];; + guint32 fourcc = 0; + guint32 plane_num = 0; + + if (!handle || !resolution) { + LOGE("NULL param %p %p", handle, resolution); + return CAMERA_ERROR_INTERNAL; + } + + /* S_FMT */ + ret = __camera_get_fourcc_plane_num(pixel_format, &fourcc, &plane_num); + if (ret != CAMERA_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 (ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) { + LOGE("S_FMT failed. errno %d", errno); + return CAMERA_ERROR_INTERNAL; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) { + for (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)); - if (!handle || !format || !result_buffer_count) { - LOGE("NULL param %p %p", handle, result_buffer_count); + v4l2_parm.type = handle->buffer_type; + + if (ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) { + LOGE("G_PARM failed. errno %d", errno); + return CAMERA_ERROR_INTERNAL; + } + + /* S_PARM to set fps */ + v4l2_parm.parm.capture.timeperframe.numerator = 1; + v4l2_parm.parm.capture.timeperframe.denominator = fps; + + if (ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) { + LOGE("S_PARM failed. errno %d", errno); return CAMERA_ERROR_INTERNAL; } /* request buffer */ ret = __camera_v4l2_reqbufs(handle->device_fd, - handle->v4l2_type, V4L2_MEMORY_MMAP, request_buffer_count, result_buffer_count); + handle->buffer_type, V4L2_MEMORY_MMAP, request_buffer_count, &handle->buffer_count); if (ret != CAMERA_ERROR_NONE) { - g_mutex_unlock(&handle->lock); return ret; } LOGD("buffer count : request %d -> result %d", - request_buffer_count, *result_buffer_count); + request_buffer_count, handle->buffer_count); /* query buffer, mmap and qbuf */ - for (i = 0 ; i < *result_buffer_count ; i++) { + for (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->v4l2_type; + 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 = handle->plane_num; - - LOGD("%d", i); + v4l2_buf.length = plane_num; if (ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) { LOGE("[%d] query buf failed. errno %d", i, errno); goto _START_STREAM_FAILED; } - LOGD("%d", i); - buffer = &handle->camera_buffers[i]; - LOGD("%d", i); - buffer->index = i; - buffer->format = format->stream_format; - buffer->resolution = format->stream_resolution; + buffer->format = pixel_format; + buffer->resolution.width = resolution->width; + buffer->resolution.height = resolution->height; buffer->total_size = v4l2_buf.length; - buffer->num_planes = handle->plane_num; + buffer->num_planes = plane_num; buffer->planes[0].size = v4l2_buf.length; buffer->planes[0].data = mmap(0, v4l2_buf.length, @@ -688,25 +744,19 @@ static int __camera_start_stream(camera_hal_handle *handle, camera_format_t *for handle->device_fd, v4l2_buf.m.offset); - LOGD("%d", i); - if (buffer->planes[0].data == MAP_FAILED) { LOGE("[%d] mmap failed (errno %d)", i, errno); goto _START_STREAM_FAILED; } - LOGD("%d", i); - - if (__camera_v4l2_qbuf(handle->device_fd, handle->v4l2_type, V4L2_MEMORY_MMAP, i) != CAMERA_ERROR_NONE) { + if (__camera_v4l2_qbuf(handle->device_fd, handle->buffer_type, V4L2_MEMORY_MMAP, i) != CAMERA_ERROR_NONE) { LOGE("[%d] qbuf failed (errno %d)", i, errno); goto _START_STREAM_FAILED; } - - LOGD("%d", i); } /* stream on */ - ret = __camera_v4l2_stream(handle->device_fd, handle->v4l2_type, TRUE); + ret = __camera_v4l2_stream(handle->device_fd, handle->buffer_type, TRUE); if (ret != CAMERA_ERROR_NONE) { LOGE("stream on failed"); goto _START_STREAM_FAILED; @@ -715,11 +765,110 @@ static int __camera_start_stream(camera_hal_handle *handle, camera_format_t *for return CAMERA_ERROR_NONE; _START_STREAM_FAILED: - __camera_stop_stream(handle, *result_buffer_count); + __camera_stop_stream(handle, handle->buffer_count); return ret; } +static void __camera_do_capture(camera_hal_handle *handle) +{ + int ret = CAMERA_ERROR_NONE; + int buffer_index = 0; + + if (!handle) { + LOGE("NULL handle"); + return; + } + + LOGD("start"); + + /* restart stream for capture */ + if (handle->capture_restart_stream) { + ret = __camera_stop_stream(handle, handle->buffer_count); + if (ret != CAMERA_ERROR_NONE) { + LOGE("stop stream failed for capture[0x%x]", ret); + goto _CAPTURE_DONE; + } + + ret = __camera_start_stream(handle, + handle->preview_format.capture_format, + &handle->preview_format.capture_resolution, + handle->preview_format.stream_fps, + BUFFER_MAX); + if (ret != CAMERA_ERROR_NONE) { + LOGE("start stream failed for capture[0x%x]", ret); + goto _CAPTURE_DONE; + } + } + + /* get capture buffer */ + ret = __camera_v4l2_wait_frame(handle->device_fd, 5); + if (ret != CAMERA_ERROR_NONE) { + LOGE("frame wait failed for capture[0x%x]", ret); + goto _CAPTURE_DONE; + } + + ret = __camera_v4l2_dqbuf(handle->device_fd, + handle->buffer_type, V4L2_MEMORY_MMAP, &buffer_index); + if (ret != CAMERA_ERROR_NONE) { + LOGE("dqbuf failed for capture[0x%x]", ret); + goto _CAPTURE_DONE; + } + + g_mutex_lock(&handle->buffer_lock); + + handle->captured_count++; + + g_mutex_unlock(&handle->buffer_lock); + + LOGD("capture cb[%p], buffer index[%d],count[%d]", + handle->capture_cb, buffer_index, handle->captured_count); + + if (handle->capture_cb) { + ((camera_capture_cb)handle->capture_cb)(&handle->camera_buffers[buffer_index], + NULL, NULL, handle->capture_cb_data); + } else { + LOGW("capture callback is NULL"); + /* Need to post error? */ + } + + ret = __camera_v4l2_qbuf(handle->device_fd, + handle->buffer_type, V4L2_MEMORY_MMAP, buffer_index); + if (ret != CAMERA_ERROR_NONE) + LOGE("qbuf failed for capture[0x%x]", ret); + + g_mutex_lock(&handle->buffer_lock); + + if (handle->state == CAMERA_STATE_CAPTURING) { + LOGD("wait for capture stop signal"); + g_cond_wait(&handle->buffer_cond, &handle->buffer_lock); + LOGD("signal received"); + } else { + LOGD("The state is already changed."); + } + + g_mutex_unlock(&handle->buffer_lock); + +_CAPTURE_DONE: + /* restart stream for preview */ + if (handle->capture_restart_stream) { + ret = __camera_stop_stream(handle, handle->buffer_count); + if (ret != CAMERA_ERROR_NONE) + LOGE("stop stream failed for preview[0x%x]", ret); + + ret = __camera_start_stream(handle, + handle->preview_format.stream_format, + &handle->preview_format.stream_resolution, + handle->preview_format.stream_fps, + BUFFER_MAX); + if (ret != CAMERA_ERROR_NONE) + LOGE("start stream failed for preview[0x%x]", ret); + } + + LOGD("done"); +} + + static void *__camera_buffer_handler_func(gpointer data) { int index = 0; @@ -733,34 +882,34 @@ static void *__camera_buffer_handler_func(gpointer data) LOGD("enter - preview handler thread"); /* run buffer thread */ - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); while (handle->buffer_thread_run) { - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); if (__camera_v4l2_wait_frame(handle->device_fd, 5) != CAMERA_ERROR_NONE) { LOGE("frame wait failed"); - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); break; } - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); if (handle->buffer_thread_run == FALSE) { LOGW("stop preview handler thread"); break; } - if (__camera_v4l2_dqbuf(handle->device_fd, handle->v4l2_type, V4L2_MEMORY_MMAP, &index) != CAMERA_ERROR_NONE) { + if (__camera_v4l2_dqbuf(handle->device_fd, handle->buffer_type, V4L2_MEMORY_MMAP, &index) != CAMERA_ERROR_NONE) { LOGE("dqbuf failed"); break; } - handle->live_buffer_num++; + handle->buffer_dequeued_count++; - /*LOGD("live buffer num %d", handle->live_buffer_num);*/ + /*LOGD("dequeued buffer count %d", handle->buffer_dequeued_count);*/ - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); if (handle->preview_cb) { ((camera_preview_frame_cb)handle->preview_cb)(&handle->camera_buffers[index], NULL, handle->preview_cb_data); @@ -769,12 +918,18 @@ static void *__camera_buffer_handler_func(gpointer data) camera_release_preview_buffer((void *)handle, index); } + /* check capture request flag */ + if (handle->capture_request) { + __camera_do_capture(handle); + handle->capture_request = FALSE; + } + sched_yield(); - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); } - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); LOGD("leave - preview handler thread"); @@ -812,42 +967,42 @@ static void *_camera_message_handler_func(gpointer data) LOGD("enter - message thread"); - g_mutex_lock(&handle->message_cb_lock); + g_mutex_lock(&handle->msg_cb_lock); - while (handle->message_cb_run) { - if (g_queue_is_empty(handle->message_list)) { + while (handle->msg_cb_run) { + if (g_queue_is_empty(handle->msg_list)) { LOGD("wait for message"); - g_cond_wait(&handle->message_cb_cond, &handle->message_cb_lock); + g_cond_wait(&handle->msg_cb_cond, &handle->msg_cb_lock); LOGD("message signal received"); } - if (!handle->message_cb_run) { + if (!handle->msg_cb_run) { LOGW("break message thread"); break; } - message = g_queue_pop_head(handle->message_list); + message = g_queue_pop_head(handle->msg_list); if (!message) { LOGW("NULL message"); continue; } - g_mutex_unlock(&handle->message_cb_lock); + g_mutex_unlock(&handle->msg_cb_lock); for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) { - if (handle->message_cb[i]) { + if (handle->msg_cb[i]) { LOGD("call message callback type %d", message->type); - ((camera_message_cb)handle->message_cb[i])(message, handle->message_cb_data[i]); + ((camera_message_cb)handle->msg_cb[i])(message, handle->msg_cb_data[i]); } } g_free(message); message = NULL; - g_mutex_lock(&handle->message_cb_lock); + g_mutex_lock(&handle->msg_cb_lock); } - g_mutex_unlock(&handle->message_cb_lock); + g_mutex_unlock(&handle->msg_cb_lock); LOGD("leave - message thread"); @@ -862,21 +1017,21 @@ static void __camera_release_handle(camera_hal_handle *handle) return; } - if (handle->message_thread) { - g_mutex_lock(&handle->message_cb_lock); - handle->message_cb_run = FALSE; - g_cond_signal(&handle->message_cb_cond); - g_mutex_unlock(&handle->message_cb_lock); - g_thread_join(handle->message_thread); - g_queue_free_full(handle->message_list, (GDestroyNotify)__camera_message_release_func); - handle->message_list = NULL; + if (handle->msg_thread) { + g_mutex_lock(&handle->msg_cb_lock); + handle->msg_cb_run = FALSE; + g_cond_signal(&handle->msg_cb_cond); + g_mutex_unlock(&handle->msg_cb_lock); + g_thread_join(handle->msg_thread); + g_queue_free_full(handle->msg_list, (GDestroyNotify)__camera_message_release_func); + handle->msg_list = NULL; } g_mutex_clear(&handle->lock); - g_mutex_clear(&handle->preview_cb_lock); - g_mutex_clear(&handle->message_cb_lock); - g_cond_clear(&handle->preview_cb_cond); - g_cond_clear(&handle->message_cb_cond); + g_mutex_clear(&handle->buffer_lock); + g_mutex_clear(&handle->msg_cb_lock); + g_cond_clear(&handle->buffer_cond); + g_cond_clear(&handle->msg_cb_cond); if (handle->bufmgr) { tbm_bufmgr_deinit(handle->bufmgr); @@ -920,17 +1075,17 @@ int camera_init(void **camera_handle) new_handle->bufmgr = bufmgr; g_mutex_init(&new_handle->lock); - g_mutex_init(&new_handle->preview_cb_lock); - g_mutex_init(&new_handle->message_cb_lock); - g_cond_init(&new_handle->preview_cb_cond); - g_cond_init(&new_handle->message_cb_cond); + g_mutex_init(&new_handle->buffer_lock); + g_mutex_init(&new_handle->msg_cb_lock); + g_cond_init(&new_handle->buffer_cond); + g_cond_init(&new_handle->msg_cb_cond); /* message thread */ - new_handle->message_list = g_queue_new(); - new_handle->message_cb_run = TRUE; - new_handle->message_thread = g_thread_try_new("camera_hal_message_thread", + new_handle->msg_list = g_queue_new(); + new_handle->msg_cb_run = TRUE; + new_handle->msg_thread = g_thread_try_new("camera_hal_msg_thread", _camera_message_handler_func, (gpointer)new_handle, NULL); - if (!new_handle->message_thread) { + if (!new_handle->msg_thread) { LOGE("failed to create message thread"); ret = CAMERA_ERROR_INTERNAL; goto _INIT_ERROR; @@ -1061,16 +1216,16 @@ int camera_open_device(void *camera_handle, int device_index) } if (g_device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) - handle->v4l2_type = V4L2_CAP_VIDEO_CAPTURE_MPLANE; + handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE_MPLANE; else - handle->v4l2_type = V4L2_CAP_VIDEO_CAPTURE; + handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE; handle->state = CAMERA_STATE_OPENED; handle->device_index = device_index; handle->device_fd = device_fd; LOGD("[%d] device[%s] opened [fd %d, type %d]", - device_index, node_path, device_fd, handle->v4l2_type); + device_index, node_path, device_fd, handle->buffer_type); _OPEN_DEVICE_DONE: g_mutex_unlock(&handle->lock); @@ -1137,9 +1292,9 @@ int camera_add_message_callback(void *camera_handle, camera_message_cb callback, } for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) { - if (handle->message_cb[i] == NULL) { - handle->message_cb[i] = callback; - handle->message_cb_data[i] = user_data; + if (handle->msg_cb[i] == NULL) { + handle->msg_cb[i] = callback; + handle->msg_cb_data[i] = user_data; *cb_id = i; LOGD("message cb [%p] added, user data %p - id %u", callback, user_data, i); g_mutex_unlock(&handle->lock); @@ -1176,12 +1331,12 @@ int camera_remove_message_callback(void *camera_handle, uint32_t cb_id) return CAMERA_ERROR_INVALID_STATE; } - if (handle->message_cb[cb_id]) { + if (handle->msg_cb[cb_id]) { LOGD("remove message callback %p, user data %p - cb_id %u", - handle->message_cb[cb_id], handle->message_cb_data[cb_id], cb_id); + handle->msg_cb[cb_id], handle->msg_cb_data[cb_id], cb_id); - handle->message_cb[cb_id] = NULL; - handle->message_cb_data[cb_id] = NULL; + handle->msg_cb[cb_id] = NULL; + handle->msg_cb_data[cb_id] = NULL; } else { LOGE("already removed message cb"); g_mutex_unlock(&handle->lock); @@ -1199,11 +1354,8 @@ int camera_set_preview_stream_format(void *camera_handle, camera_format_t *forma int j = 0; int ret = CAMERA_ERROR_NONE; gboolean capability_check = FALSE; - guint32 fourcc = 0; camera_hal_handle *handle = (camera_hal_handle *)camera_handle; camera_device_info_t *device_info = NULL; - struct v4l2_format v4l2_fmt; - struct v4l2_streamparm v4l2_parm; if (!handle || !format) { LOGE("NULL param %p %p", handle, format); @@ -1217,7 +1369,8 @@ int camera_set_preview_stream_format(void *camera_handle, camera_format_t *forma g_mutex_lock(&handle->lock); - if (handle->state != CAMERA_STATE_OPENED) { + if (handle->state != CAMERA_STATE_OPENED && + handle->state != CAMERA_STATE_PREVIEWING) { LOGE("invalid state %d", handle->state); g_mutex_unlock(&handle->lock); return CAMERA_ERROR_INVALID_STATE; @@ -1256,80 +1409,60 @@ int camera_set_preview_stream_format(void *camera_handle, camera_format_t *forma return CAMERA_ERROR_INVALID_PARAMETER; } - /* S_FMT */ - ret = __camera_get_fourcc_plane_num(format->stream_format, &fourcc, &handle->plane_num); - if (ret != CAMERA_ERROR_NONE) { - LOGE("get fourcc failed [format %d]", format->stream_format); - g_mutex_unlock(&handle->lock); - return ret; - } - - memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format)); - - v4l2_fmt.type = handle->v4l2_type; - if (V4L2_TYPE_IS_MULTIPLANAR(handle->v4l2_type)) { - v4l2_fmt.fmt.pix_mp.width = format->stream_resolution.width; - v4l2_fmt.fmt.pix_mp.height = format->stream_resolution.height; - v4l2_fmt.fmt.pix_mp.pixelformat = fourcc; - v4l2_fmt.fmt.pix_mp.num_planes = handle->plane_num; - } else { - v4l2_fmt.fmt.pix.width = format->stream_resolution.width; - v4l2_fmt.fmt.pix.height = format->stream_resolution.height; - v4l2_fmt.fmt.pix.pixelformat = fourcc; - v4l2_fmt.fmt.pix.bytesperline = format->stream_resolution.width; - } - - if (ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) { - LOGE("S_FMT failed. errno %d", errno); - g_mutex_unlock(&handle->lock); - return CAMERA_ERROR_INTERNAL; - } - - if (V4L2_TYPE_IS_MULTIPLANAR(handle->v4l2_type)) { - for (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); + /* compare with current settings */ + if (handle->state == CAMERA_STATE_PREVIEWING) { + if (handle->preview_format.stream_format == format->stream_format && + handle->preview_format.stream_resolution.width == format->stream_resolution.width && + handle->preview_format.stream_resolution.height == format->stream_resolution.height && + handle->preview_format.stream_fps == format->stream_fps && + handle->preview_format.stream_rotation == format->stream_rotation) { + LOGD("no need to restart preview stream"); + goto _SET_PREVIEW_STREAM_FORMAT_DONE; } - } 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)); + LOGD("Preview setting is changed. Restart preview now."); - v4l2_parm.type = handle->v4l2_type; + /* stop preview stream to change it */ + ret = __camera_stop_stream(handle, handle->buffer_count); + if (ret != CAMERA_ERROR_NONE) { + LOGE("failed to stop stream"); + g_mutex_unlock(&handle->lock); + return ret; + } - if (ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) { - LOGE("G_PARM failed. errno %d", errno); - g_mutex_unlock(&handle->lock); - return CAMERA_ERROR_INTERNAL; + /* restart preview stream to change it */ + ret = __camera_start_stream(handle, + format->stream_format, + &format->stream_resolution, + format->stream_fps, + BUFFER_MAX); + if (ret != CAMERA_ERROR_NONE) { + LOGE("failed to start stream"); + g_mutex_unlock(&handle->lock); + return ret; + } } - /* S_PARM to set fps */ - v4l2_parm.parm.capture.timeperframe.numerator = 1; - v4l2_parm.parm.capture.timeperframe.denominator = format->stream_fps; - - if (ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) { - LOGE("S_PARM failed. errno %d", errno); - g_mutex_unlock(&handle->lock); - return CAMERA_ERROR_INTERNAL; - } +_SET_PREVIEW_STREAM_FORMAT_DONE: + /* set capture restart flag */ + if (format->stream_format == format->capture_format && + format->stream_resolution.width == format->capture_resolution.width && + format->stream_resolution.height == format->capture_resolution.height) + handle->capture_restart_stream = FALSE; + else + handle->capture_restart_stream = TRUE; memcpy(&handle->preview_format, format, sizeof(camera_format_t)); - LOGD("set preview stream [%d: %dx%d, fps %d]", + LOGD("set format PREVIEW[%d:%dx%d,fps:%d], CAPTURE[%d:%dx%d,restart:%d]", format->stream_format, format->stream_resolution.width, format->stream_resolution.height, - format->stream_fps); - - LOGW("CAPTURE STREAM [%d: %dx%d] IS NOT SUPPORTED", + format->stream_fps, format->capture_format, format->capture_resolution.width, - format->capture_resolution.height); + format->capture_resolution.height, + handle->capture_restart_stream); g_mutex_unlock(&handle->lock); @@ -1376,14 +1509,18 @@ int camera_start_preview(void *camera_handle, camera_preview_frame_cb callback, return CAMERA_ERROR_INVALID_STATE; } - ret = __camera_start_stream(handle, &handle->preview_format, BUFFER_MAX, &handle->buffer_count); + ret = __camera_start_stream(handle, + handle->preview_format.stream_format, + &handle->preview_format.stream_resolution, + handle->preview_format.stream_fps, + BUFFER_MAX); if (ret != CAMERA_ERROR_NONE) { LOGE("__camera_start_stream failed[0x%x]", ret); g_mutex_unlock(&handle->lock); return ret; } - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); handle->buffer_thread_run = TRUE; @@ -1391,7 +1528,7 @@ int camera_start_preview(void *camera_handle, camera_preview_frame_cb callback, __camera_buffer_handler_func, (gpointer)handle, NULL); if (!handle->buffer_thread) { LOGE("failed to create buffer handler thread"); - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); __camera_stop_stream(handle, handle->buffer_count); @@ -1403,7 +1540,7 @@ int camera_start_preview(void *camera_handle, camera_preview_frame_cb callback, handle->preview_cb = callback; handle->preview_cb_data = user_data; - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); handle->state = CAMERA_STATE_PREVIEWING; @@ -1430,21 +1567,25 @@ int camera_release_preview_buffer(void *camera_handle, int buffer_index) } ret = __camera_v4l2_qbuf(handle->device_fd, - handle->v4l2_type, V4L2_MEMORY_MMAP, buffer_index); + handle->buffer_type, V4L2_MEMORY_MMAP, buffer_index); - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); if (ret == CAMERA_ERROR_NONE) { - handle->live_buffer_num--; - LOGD("qbud done : index %d, live buffer num %d", - buffer_index, handle->live_buffer_num); + if (handle->buffer_dequeued_count > 0) + handle->buffer_dequeued_count--; + else + LOGW("invalid dequeued buffer count[%u]", handle->buffer_dequeued_count); + + /*LOGD("qbud done : index %d, dequeued buffer count %d", + buffer_index, handle->buffer_dequeued_count);*/ } else { LOGE("qbuf failed [index %d]", buffer_index); } - g_cond_signal(&handle->preview_cb_cond); + g_cond_signal(&handle->buffer_cond); - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); return ret; } @@ -1471,14 +1612,14 @@ int camera_stop_preview(void *camera_handle) return CAMERA_ERROR_INVALID_STATE; } - g_mutex_lock(&handle->preview_cb_lock); + g_mutex_lock(&handle->buffer_lock); handle->buffer_thread_run = FALSE; - while (handle->live_buffer_num > 0) { - LOGD("wait for live buffer [num %d]", handle->live_buffer_num); + while (handle->buffer_dequeued_count > 0) { + LOGD("wait for dequeued buffer [%d]", handle->buffer_dequeued_count); end_time = g_get_monotonic_time() + 3 * G_TIME_SPAN_SECOND; - if (!g_cond_wait_until(&handle->preview_cb_cond, &handle->preview_cb_lock, end_time)) { + if (!g_cond_wait_until(&handle->buffer_cond, &handle->buffer_lock, end_time)) { LOGE("buffer wait failed"); break; } else { @@ -1486,7 +1627,7 @@ int camera_stop_preview(void *camera_handle) } } - g_mutex_unlock(&handle->preview_cb_lock); + g_mutex_unlock(&handle->buffer_lock); ret = __camera_stop_stream(handle, handle->buffer_count); @@ -1532,28 +1673,76 @@ int camera_stop_auto_focus(void *camera_handle) int camera_start_capture(void *camera_handle, camera_capture_cb callback, void *user_data) { - if (!camera_handle || !callback) { + camera_hal_handle *handle = (camera_hal_handle *)camera_handle; + + if (!handle || !callback) { LOGE("NULL param %p %p", camera_handle, callback); return CAMERA_ERROR_INVALID_PARAMETER; } - LOGE("NOT SUPPORTED"); + g_mutex_lock(&handle->lock); - /* capture function is not supported */ - return CAMERA_ERROR_DEVICE_NOT_SUPPORTED; + if (handle->state != CAMERA_STATE_PREVIEWING) { + LOGE("invalid state %d", handle->state); + g_mutex_unlock(&handle->lock); + return CAMERA_ERROR_INVALID_STATE; + } + + /* set callback and user data */ + handle->capture_cb = callback; + handle->capture_cb_data = user_data; + + /* reset captured count */ + handle->captured_count = 0; + + /* set capture request flag */ + handle->capture_request = TRUE; + + handle->state = CAMERA_STATE_CAPTURING; + + LOGD("start capture"); + + g_mutex_unlock(&handle->lock); + + return CAMERA_ERROR_NONE; } int camera_stop_capture(void *camera_handle) { - if (!camera_handle) { + camera_hal_handle *handle = (camera_hal_handle *)camera_handle; + + if (!handle) { LOGE("NULL handle"); return CAMERA_ERROR_INVALID_PARAMETER; } - LOGE("NOT SUPPORTED"); + g_mutex_lock(&handle->lock); - /* capture function is not supported */ - return CAMERA_ERROR_DEVICE_NOT_SUPPORTED; + if (handle->state != CAMERA_STATE_CAPTURING) { + LOGE("invalid state %d", handle->state); + g_mutex_unlock(&handle->lock); + return CAMERA_ERROR_INVALID_STATE; + } + + g_mutex_lock(&handle->buffer_lock); + + if (handle->captured_count == 0) { + LOGE("No captured image yet."); + g_mutex_unlock(&handle->buffer_lock); + g_mutex_unlock(&handle->lock); + return CAMERA_ERROR_INTERNAL; + } + + LOGD("send signal to start preview after capture"); + + g_cond_signal(&handle->buffer_cond); + g_mutex_unlock(&handle->buffer_lock); + + handle->state = CAMERA_STATE_PREVIEWING; + + g_mutex_unlock(&handle->lock); + + return CAMERA_ERROR_NONE; } int camera_set_video_stream_format(void *camera_handle, camera_format_t *format) diff --git a/src/tizen_camera_v4l2_private.h b/src/tizen_camera_v4l2_private.h index 2e4996f..c6abc44 100644 --- a/src/tizen_camera_v4l2_private.h +++ b/src/tizen_camera_v4l2_private.h @@ -32,44 +32,48 @@ #define V4L2_PLANES_MAX 4 typedef struct _camera_hal_handle { + /* tbm */ tbm_bufmgr bufmgr; - int device_index; - int device_fd; - camera_state_t state; - camera_format_t preview_format; - camera_format_t video_format; + /* device */ + gint32 device_index; + gint32 device_fd; - /* V4L2 */ - enum v4l2_buf_type v4l2_type; - uint8_t plane_num; - int live_buffer_num; - - /* thread */ + /* buffer */ + guint32 buffer_dequeued_count; GThread *buffer_thread; - GThread *message_thread; gboolean buffer_thread_run; + guint32 buffer_count; + camera_buffer_t camera_buffers[BUFFER_MAX]; + enum v4l2_buf_type buffer_type; + GMutex buffer_lock; + GCond buffer_cond; - /* buffer handler */ + /* preview */ + camera_format_t preview_format; camera_preview_frame_cb preview_cb; + gpointer preview_cb_data; + + /* capture */ camera_capture_cb capture_cb; - void *preview_cb_data; - void *capture_cb_data; - uint32_t buffer_count; - camera_buffer_t camera_buffers[BUFFER_MAX]; + gpointer capture_cb_data; + guint32 capture_count; + guint32 captured_count; + gboolean capture_request; + gboolean capture_restart_stream; - /* message callback */ - camera_message_cb message_cb[MESSAGE_CALLBACK_MAX]; - void *message_cb_data[MESSAGE_CALLBACK_MAX]; - gboolean message_cb_run; - GQueue *message_list; + /* message */ + GThread *msg_thread; + camera_message_cb msg_cb[MESSAGE_CALLBACK_MAX]; + gpointer msg_cb_data[MESSAGE_CALLBACK_MAX]; + gboolean msg_cb_run; + GQueue *msg_list; + GMutex msg_cb_lock; + GCond msg_cb_cond; - /* thread safe */ + /* etc */ GMutex lock; - GMutex preview_cb_lock; - GMutex message_cb_lock; - GCond preview_cb_cond; - GCond message_cb_cond; + camera_state_t state; } camera_hal_handle; #endif /* __TIZEN_CAMERA_PRIVATE_H__ */