diff options
author | Dheeraj CVR <cvr.dheeraj@gmail.com> | 2013-11-27 12:59:19 +0530 |
---|---|---|
committer | Dheeraj CVR <cvr.dheeraj@gmail.com> | 2013-11-29 07:55:30 +0530 |
commit | 82dc7a439e1bc80cbc0ac72220e83a3b05416ebe (patch) | |
tree | e39dab816fb073d7429d8138af38afc3ddc2d92d | |
parent | 94d9ab084e69dca7dfc642c5ae045e3e037a6cf3 (diff) | |
download | device_samsung_smdk4412-common-82dc7a439e1bc80cbc0ac72220e83a3b05416ebe.zip device_samsung_smdk4412-common-82dc7a439e1bc80cbc0ac72220e83a3b05416ebe.tar.gz device_samsung_smdk4412-common-82dc7a439e1bc80cbc0ac72220e83a3b05416ebe.tar.bz2 |
smdk4412-common: camera: several fixes for autofocus
Setting the AutoFocus off using V4L2_CID_CAMERA_SET_AUTO_FOCUS will
reset the AF position of the sensor and this was done whenever
autofocus was completed. This totally defeated the purpose of touch
to focus since the sensor AF position was being reset after focus
and had to be refocussed while taking the snapshot. This also led to
several issues with third party applications since this kind of focus
behaviour was not intended.
S5C73M3 Back camera Interleaves YUV and JPEG along with metadata. This
metadata contains the AutoFocus result. Hence we could parse the
autofocus result instead of using V4L2 IOCTL, which is more efficient.
Also, the sensor exhibits issues when AutoExposure and AutoWhite Balance
locks are used with Flash ON. Improper locking could lead to freezing of
the sensor while taking a snapshot. Hence, only lock AEAWB when flash is
OFF and unlock them after AutoFocus finishes.
Change-Id: Ief28005dcacd0f8f04990ef8eafebff4a2f109d5
-rw-r--r-- | camera/exynos_camera.c | 193 | ||||
-rw-r--r-- | camera/exynos_camera.h | 12 |
2 files changed, 69 insertions, 136 deletions
diff --git a/camera/exynos_camera.c b/camera/exynos_camera.c index a414529..716e906 100644 --- a/camera/exynos_camera.c +++ b/camera/exynos_camera.c @@ -913,8 +913,6 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) if (rc < 0) ALOGE("%s: Unable to set object y position", __func__); } - - focus_mode = FOCUS_MODE_TOUCH; } } @@ -954,15 +952,6 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) else awb_lock = 0; - if (ae_lock != exynos_camera->ae_lock || awb_lock != exynos_camera->awb_lock || force) { - exynos_camera->ae_lock = ae_lock; - exynos_camera->awb_lock = awb_lock; - aeawb = (ae_lock ? 0x1 : 0x0) | (awb_lock ? 0x2 : 0x0); - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK, aeawb); - if (rc < 0) - ALOGE("%s: Unable to set AEAWB lock", __func__); - } - // Scene mode scene_mode_string = exynos_param_string_get(exynos_camera, "scene-mode"); @@ -1046,6 +1035,17 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) } } + // Lock Auto Exposure and White Balance only when Flash is OFF + if ((ae_lock != exynos_camera->ae_lock || awb_lock != exynos_camera->awb_lock || force) && + exynos_camera->flash_mode == FLASH_MODE_OFF) { + exynos_camera->ae_lock = ae_lock; + exynos_camera->awb_lock = awb_lock; + aeawb = (ae_lock ? 0x1 : 0x0) | (awb_lock ? 0x2 : 0x0); + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK, aeawb); + if (rc < 0) + ALOGE("%s: Unable to set AEAWB lock", __func__); + } + focus_mode_string = exynos_param_string_get(exynos_camera, "focus-mode"); if (focus_mode_string != NULL) { if (focus_mode == 0) { @@ -1276,25 +1276,7 @@ int s5c73m3_interleaved_decode(void *data, int size, data_p += size - 0x1000; // End of the first plane (interleaved buffer) data_p += 50; // Experimental offset for auto-focus result - s5c73m3_auto_focus_result = *data_p; - - switch (s5c73m3_auto_focus_result) { - case S5C73M3_CAF_STATUS_FOCUSING: - case S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR: - case S5C73M3_AF_STATUS_INVALID: - *auto_focus_result = CAMERA_AF_STATUS_IN_PROGRESS; - break; - case S5C73M3_AF_STATUS_FOCUSED: - case S5C73M3_CAF_STATUS_FOCUSED: - *auto_focus_result = CAMERA_AF_STATUS_SUCCESS; - break; - - case S5C73M3_CAF_STATUS_UNFOCUSED: - case S5C73M3_AF_STATUS_UNFOCUSED: - default: - *auto_focus_result = CAMERA_AF_STATUS_FAIL; - break; - } + *auto_focus_result = (int) *data_p; data_p = (unsigned char *) data; data_p += size - 0x1000; // End of the first plane (interleaved buffer) @@ -1423,6 +1405,7 @@ int exynos_camera_capture(struct exynos_camera *exynos_camera) int buffers_count; int buffer_length; int auto_focus_result; + int current_af; int decoded; int busy; void *pointer; @@ -1489,11 +1472,30 @@ int exynos_camera_capture(struct exynos_camera *exynos_camera) goto error; } - if (auto_focus_result != exynos_camera->capture_auto_focus_result) { - exynos_camera->capture_auto_focus_result = auto_focus_result; + // AutoFocus + switch (auto_focus_result) { + case S5C73M3_CAF_STATUS_FOCUSING: + case S5C73M3_CAF_STATUS_FIND_SEARCHING_DIR: + case S5C73M3_AF_STATUS_FOCUSING: + current_af = CAMERA_AF_STATUS_IN_PROGRESS; + break; + case S5C73M3_CAF_STATUS_FOCUSED: + case S5C73M3_AF_STATUS_FOCUSED: + current_af = CAMERA_AF_STATUS_SUCCESS; + break; + case S5C73M3_CAF_STATUS_UNFOCUSED: + case S5C73M3_AF_STATUS_UNFOCUSED: + current_af = CAMERA_AF_STATUS_FAIL; + break; + case S5C73M3_AF_STATUS_INVALID: + default: + current_af = CAMERA_AF_STATUS_RESTART; + } - if (!exynos_camera->auto_focus_thread_enabled) { - rc = exynos_camera_auto_focus(exynos_camera, auto_focus_result); + if (current_af != exynos_camera->auto_focus_result) { + exynos_camera->auto_focus_result = current_af; + if (exynos_camera->auto_focus_enabled) { + rc = exynos_camera_auto_focus(exynos_camera, current_af); if (rc < 0) { ALOGE("%s: Unable to auto focus", __func__); goto error; @@ -2706,12 +2708,10 @@ int exynos_camera_picture_callback(struct exynos_camera *exynos_camera, pthread_mutex_lock(&exynos_camera->picture_mutex); if (!exynos_camera->picture_enabled && !exynos_camera->camera_fimc_is) { -#if 0 - if (exynos_camera->focus_mode == FOCUS_MODE_CONTINOUS_PICTURE && exynos_camera->capture_auto_focus_result == CAMERA_AF_STATUS_IN_PROGRESS) { + if (exynos_camera->auto_focus_result == CAMERA_AF_STATUS_IN_PROGRESS) { pthread_mutex_unlock(&exynos_camera->picture_mutex); return 0; } -#endif rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_CAPTURE, 0); if (rc < 0) { @@ -3769,69 +3769,20 @@ int exynos_camera_auto_focus(struct exynos_camera *exynos_camera, int auto_focus case CAMERA_AF_STATUS_SUCCESS: if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify) && !exynos_camera->callback_lock) exynos_camera->callbacks.notify(CAMERA_MSG_FOCUS, 1, 0, exynos_camera->callbacks.user); + exynos_camera_auto_focus_finish(exynos_camera); break; case CAMERA_AF_STATUS_FAIL: - default: if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify) && !exynos_camera->callback_lock) exynos_camera->callbacks.notify(CAMERA_MSG_FOCUS, 0, 0, exynos_camera->callbacks.user); + exynos_camera_auto_focus_finish(exynos_camera); break; } return 0; } -void *exynos_camera_auto_focus_thread(void *data) +int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera) { - struct exynos_camera *exynos_camera; - int auto_focus_status = CAMERA_AF_STATUS_FAIL; - int auto_focus_completed = 0; - int rc; - - if (data == NULL) - return NULL; - - exynos_camera = (struct exynos_camera *) data; - - ALOGE("%s: Starting thread", __func__); - exynos_camera->auto_focus_thread_running = 1; - - while (exynos_camera->auto_focus_thread_enabled) { - pthread_mutex_lock(&exynos_camera->auto_focus_mutex); - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT, &auto_focus_status); - if (rc < 0) { - ALOGE("%s: Unable to get auto-focus result", __func__); - auto_focus_status = CAMERA_AF_STATUS_FAIL; - } - - rc = exynos_camera_auto_focus(exynos_camera, auto_focus_status); - if (rc < 0) { - ALOGE("%s: Unable to auto-focus", __func__); - auto_focus_status = CAMERA_AF_STATUS_FAIL; - } - - if (auto_focus_status == CAMERA_AF_STATUS_IN_PROGRESS) - usleep(10000); - else - auto_focus_completed = 1; - - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - - if (auto_focus_completed) { - exynos_camera->auto_focus_thread_running = 0; - exynos_camera_auto_focus_thread_stop(exynos_camera); - } - } - - exynos_camera->auto_focus_thread_running = 0; - ALOGE("%s: Exiting thread", __func__); - - return NULL; -} - -int exynos_camera_auto_focus_thread_start(struct exynos_camera *exynos_camera) -{ - pthread_attr_t thread_attr; int auto_focus; int rc; @@ -3840,13 +3791,6 @@ int exynos_camera_auto_focus_thread_start(struct exynos_camera *exynos_camera) ALOGD("%s()", __func__); - if (exynos_camera->auto_focus_thread_enabled) { - ALOGE("Auto-focus thread was already started!"); - return 0; - } - - pthread_mutex_init(&exynos_camera->auto_focus_mutex, NULL); - auto_focus = AUTO_FOCUS_ON | (exynos_camera->preview_width & 0xfff) << 20 | (exynos_camera->preview_height & 0xfff) << 8; rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, auto_focus); @@ -3855,22 +3799,12 @@ int exynos_camera_auto_focus_thread_start(struct exynos_camera *exynos_camera) goto error; } - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - - exynos_camera->auto_focus_thread_enabled = 1; - - rc = pthread_create(&exynos_camera->auto_focus_thread, &thread_attr, exynos_camera_auto_focus_thread, (void *) exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to create thread", __func__); - goto error; - } + exynos_camera->auto_focus_enabled = 1; rc = 0; goto complete; error: - pthread_mutex_destroy(&exynos_camera->auto_focus_mutex); rc = -1; @@ -3878,38 +3812,40 @@ complete: return rc; } -void exynos_camera_auto_focus_thread_stop(struct exynos_camera *exynos_camera) +void exynos_camera_auto_focus_finish(struct exynos_camera *exynos_camera) { int rc; - int i; - - if (exynos_camera == NULL) - return; ALOGD("%s()", __func__); - if (!exynos_camera->auto_focus_thread_enabled) { - ALOGE("Auto-focus thread was already stopped!"); + if (!exynos_camera->auto_focus_enabled) { return; } - exynos_camera->auto_focus_thread_enabled = 0; + exynos_camera->auto_focus_enabled = 0; - // Wait for the thread to end - i = 0; - while (exynos_camera->auto_focus_thread_running) { - if (i++ > 10000) { - ALOGE("Auto-focus thread is taking too long to end, something is going wrong"); - break; - } - usleep(100); - } + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK, AE_UNLOCK_AWB_UNLOCK); + if (rc < 0) + ALOGE("%s: Unable to set AEAWB lock", __func__); +} + +void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera) +{ + int rc; + int i; + + if (exynos_camera == NULL) + return; + + ALOGD("%s()", __func__); rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF); if (rc < 0) ALOGE("%s: Unable to set auto-focus off", __func__); - pthread_mutex_destroy(&exynos_camera->auto_focus_mutex); + if (exynos_camera->auto_focus_enabled) + exynos_camera_auto_focus_finish(exynos_camera); + } /* @@ -4206,7 +4142,7 @@ int exynos_camera_start_auto_focus(struct camera_device *dev) exynos_camera = (struct exynos_camera *) dev->priv; - return exynos_camera_auto_focus_thread_start(exynos_camera); + return exynos_camera_auto_focus_start(exynos_camera); } int exynos_camera_cancel_auto_focus(struct camera_device *dev) @@ -4220,7 +4156,7 @@ int exynos_camera_cancel_auto_focus(struct camera_device *dev) exynos_camera = (struct exynos_camera *) dev->priv; - exynos_camera_auto_focus_thread_stop(exynos_camera); + exynos_camera_auto_focus_stop(exynos_camera); return 0; } @@ -4237,8 +4173,7 @@ int exynos_camera_take_picture(struct camera_device *dev) exynos_camera = (struct exynos_camera *) dev->priv; - if (exynos_camera->picture_thread_running - || exynos_camera->auto_focus_thread_enabled) + if (exynos_camera->picture_thread_running) { return 0; } diff --git a/camera/exynos_camera.h b/camera/exynos_camera.h index 21bbe28..87a0fe9 100644 --- a/camera/exynos_camera.h +++ b/camera/exynos_camera.h @@ -318,7 +318,7 @@ struct exynos_camera { int capture_memory_index; void *capture_yuv_buffer; void *capture_jpeg_buffer; - int capture_auto_focus_result; + int auto_focus_result; int capture_hybrid; int capture_width; int capture_height; @@ -377,10 +377,7 @@ struct exynos_camera { // Auto-focus - pthread_t auto_focus_thread; - pthread_mutex_t auto_focus_mutex; - int auto_focus_thread_enabled; - int auto_focus_thread_running; + int auto_focus_enabled; // Camera params @@ -509,8 +506,9 @@ void exynos_camera_recording_thread_stop(struct exynos_camera *exynos_camera); // Auto-focus int exynos_camera_auto_focus(struct exynos_camera *exynos_camera, int auto_focus_status); -int exynos_camera_auto_focus_thread_start(struct exynos_camera *exynos_camera); -void exynos_camera_auto_focus_thread_stop(struct exynos_camera *exynos_camera); +int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera); +void exynos_camera_auto_focus_finish(struct exynos_camera *exynos_camera); +void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera); /* * EXIF |