diff options
-rw-r--r-- | camera/exynos_camera.c | 599 | ||||
-rw-r--r-- | camera/exynos_camera.h | 23 | ||||
-rw-r--r-- | camera/exynos_exif.c | 109 | ||||
-rw-r--r-- | camera/exynos_v4l2.c | 63 |
4 files changed, 494 insertions, 300 deletions
diff --git a/camera/exynos_camera.c b/camera/exynos_camera.c index 44a0039..7cea71a 100644 --- a/camera/exynos_camera.c +++ b/camera/exynos_camera.c @@ -90,7 +90,7 @@ struct exynos_camera_preset exynos_camera_presets_smdk4x12[] = { .picture_format = "jpeg", .jpeg_thumbnail_size_values = "160x120,160x90,144x96", .jpeg_thumbnail_width = 160, - .jpeg_thumbnail_height = 160, + .jpeg_thumbnail_height = 120, .jpeg_thumbnail_quality = 100, .jpeg_quality = 90, @@ -107,6 +107,8 @@ struct exynos_camera_preset exynos_camera_presets_smdk4x12[] = { .focus_areas = "(0,0,0,0,0)", .max_num_focus_areas = 1, + .max_detected_faces = 15, + .zoom_supported = 1, .smooth_zoom_supported = 0, .zoom_ratios = "100,102,104,109,111,113,119,121,124,131,134,138,146,150,155,159,165,170,182,189,200,213,222,232,243,255,283,300,319,364,400", @@ -172,7 +174,7 @@ struct exynos_camera_preset exynos_camera_presets_smdk4x12[] = { .preview_fps_range_values = "(8000,8000),(15000,15000),(15000,30000),(30000,30000)", .preview_fps_range = "15000,30000", - .picture_size_values = "1344x756,1280x720,1392x1044,1280x960,960x720,640x480,1392x1392", + .picture_size_values = "1280x960,1392x1392,640x480,1280x720,720x480,320x240", .picture_size = "1280x960", .picture_format_values = "jpeg", .picture_format = "jpeg", @@ -206,6 +208,8 @@ struct exynos_camera_preset exynos_camera_presets_smdk4x12[] = { .flash_mode = NULL, .flash_mode_values = NULL, + .max_detected_faces = 5, + .exposure_compensation = 0, .exposure_compensation_step = 0.5, .min_exposure_compensation = -4, @@ -472,6 +476,11 @@ int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id) exynos_camera->config->presets[id].params.max_num_focus_areas); } + // Face Detection + exynos_camera->max_detected_faces = exynos_camera->config->presets[id].params.max_detected_faces; + exynos_param_int_set(exynos_camera, "max-num-detected-faces-hw", + exynos_camera->max_detected_faces); + // Zoom if (exynos_camera->config->presets[id].params.zoom_supported == 1) { @@ -663,7 +672,7 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) int aeawb = 0; char *flash_mode_string; - int flash_mode; + int flash_mode = 0; int exposure_compensation; int min_exposure_compensation; @@ -913,45 +922,9 @@ 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; } } - focus_mode_string = exynos_param_string_get(exynos_camera, "focus-mode"); - if (focus_mode_string != NULL) { - if (focus_mode == 0) { - if (strcmp(focus_mode_string, "auto") == 0) - focus_mode = FOCUS_MODE_AUTO; - else if (strcmp(focus_mode_string, "infinity") == 0) - focus_mode = FOCUS_MODE_INFINITY; - else if (strcmp(focus_mode_string, "macro") == 0) - focus_mode = FOCUS_MODE_MACRO; - else if (strcmp(focus_mode_string, "fixed") == 0) - focus_mode = FOCUS_MODE_FIXED; - else if (strcmp(focus_mode_string, "facedetect") == 0) - focus_mode = FOCUS_MODE_FACEDETECT; - else if (strcmp(focus_mode_string, "continuous-video") == 0) - focus_mode = FOCUS_MODE_CONTINOUS_VIDEO; - else if (strcmp(focus_mode_string, "continuous-picture") == 0) - focus_mode = FOCUS_MODE_CONTINOUS_PICTURE; - else { - exynos_param_string_set(exynos_camera, "focus-mode", - exynos_camera->raw_focus_mode); - return -EINVAL; - } - } - - if (focus_mode != exynos_camera->focus_mode || force) { - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode); - if (rc < 0) - ALOGE("%s: Unable to set focus mode", __func__); - } - - exynos_camera->focus_mode = focus_mode; - sprintf(exynos_camera->raw_focus_mode, "%s", focus_mode_string); - } - // Zoom zoom_supported_string = exynos_param_string_get(exynos_camera, "zoom-supported"); @@ -988,31 +961,78 @@ 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"); + if (scene_mode_string != NULL) { + if (strcmp(scene_mode_string, "auto") == 0) + scene_mode = SCENE_MODE_NONE; + else if (strcmp(scene_mode_string, "portrait") == 0) { + scene_mode = SCENE_MODE_PORTRAIT; + flash_mode = FLASH_MODE_AUTO; + } else if (strcmp(scene_mode_string, "landscape") == 0) + scene_mode = SCENE_MODE_LANDSCAPE; + else if (strcmp(scene_mode_string, "night") == 0) + scene_mode = SCENE_MODE_NIGHTSHOT; + else if (strcmp(scene_mode_string, "beach") == 0) + scene_mode = SCENE_MODE_BEACH_SNOW; + else if (strcmp(scene_mode_string, "snow") == 0) + scene_mode = SCENE_MODE_BEACH_SNOW; + else if (strcmp(scene_mode_string, "sunset") == 0) + scene_mode = SCENE_MODE_SUNSET; + else if (strcmp(scene_mode_string, "fireworks") == 0) + scene_mode = SCENE_MODE_FIREWORKS; + else if (strcmp(scene_mode_string, "action") == 0) + scene_mode = SCENE_MODE_SPORTS; + else if (strcmp(scene_mode_string, "party") == 0) { + scene_mode = SCENE_MODE_PARTY_INDOOR; + flash_mode = FLASH_MODE_AUTO; + } else if (strcmp(scene_mode_string, "candlelight") == 0) + scene_mode = SCENE_MODE_CANDLE_LIGHT; + else if (strcmp(scene_mode_string, "dusk-dawn") == 0) + scene_mode = SCENE_MODE_DUSK_DAWN; + else if (strcmp(scene_mode_string, "fall-color") == 0) + scene_mode = SCENE_MODE_FALL_COLOR; + else if (strcmp(scene_mode_string, "back-light") == 0) + scene_mode = SCENE_MODE_BACK_LIGHT; + else if (strcmp(scene_mode_string, "text") == 0) + scene_mode = SCENE_MODE_TEXT; + else if (strcmp(scene_mode_string, "high-sensitivity") == 0) + scene_mode = SCENE_MODE_LOW_LIGHT; + else + scene_mode = SCENE_MODE_NONE; + + if (scene_mode != exynos_camera->scene_mode || force) { + exynos_camera->scene_mode = scene_mode; + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SCENE_MODE, scene_mode); + if (rc < 0) + ALOGE("%s: Unable to set scene mode", __func__); + } + + if (scene_mode != SCENE_MODE_NONE && !flash_mode && !focus_mode) { + flash_mode = FLASH_MODE_OFF; + focus_mode = FOCUS_MODE_AUTO; + } } // Flash flash_mode_string = exynos_param_string_get(exynos_camera, "flash-mode"); if (flash_mode_string != NULL) { - if (strcmp(flash_mode_string, "off") == 0) - flash_mode = FLASH_MODE_OFF; - else if (strcmp(flash_mode_string, "auto") == 0) - flash_mode = FLASH_MODE_AUTO; - else if (strcmp(flash_mode_string, "on") == 0) - flash_mode = FLASH_MODE_ON; - else if (strcmp(flash_mode_string, "torch") == 0) - flash_mode = FLASH_MODE_TORCH; - else { - exynos_param_string_set(exynos_camera, "flash-mode", - exynos_camera->raw_flash_mode); - return -EINVAL; + if (flash_mode == 0) { + if (strcmp(flash_mode_string, "off") == 0) + flash_mode = FLASH_MODE_OFF; + else if (strcmp(flash_mode_string, "auto") == 0) + flash_mode = FLASH_MODE_AUTO; + else if (strcmp(flash_mode_string, "on") == 0) + flash_mode = FLASH_MODE_ON; + else if (strcmp(flash_mode_string, "torch") == 0) + flash_mode = FLASH_MODE_TORCH; + else { + exynos_param_string_set(exynos_camera, "flash-mode", + exynos_camera->raw_flash_mode); + return -EINVAL; + } } if (flash_mode != exynos_camera->flash_mode || force) { @@ -1024,6 +1044,51 @@ 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) { + if (strcmp(focus_mode_string, "auto") == 0) + focus_mode = FOCUS_MODE_AUTO; + else if (strcmp(focus_mode_string, "infinity") == 0) + focus_mode = FOCUS_MODE_INFINITY; + else if (strcmp(focus_mode_string, "macro") == 0) + focus_mode = FOCUS_MODE_MACRO; + else if (strcmp(focus_mode_string, "fixed") == 0) + focus_mode = FOCUS_MODE_FIXED; + else if (strcmp(focus_mode_string, "facedetect") == 0) + focus_mode = FOCUS_MODE_FACEDETECT; + else if (strcmp(focus_mode_string, "continuous-video") == 0) + focus_mode = FOCUS_MODE_CONTINOUS_VIDEO; + else if (strcmp(focus_mode_string, "continuous-picture") == 0) + focus_mode = FOCUS_MODE_CONTINOUS_PICTURE; + else { + exynos_param_string_set(exynos_camera, "focus-mode", + exynos_camera->raw_focus_mode); + return -EINVAL; + } + } + + if (focus_mode != exynos_camera->focus_mode || force) { + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode); + if (rc < 0) + ALOGE("%s: Unable to set focus mode", __func__); + } + + exynos_camera->focus_mode = focus_mode; + sprintf(exynos_camera->raw_focus_mode, "%s", focus_mode_string); + } + // Exposure exposure_compensation = exynos_param_int_get(exynos_camera, "exposure-compensation"); @@ -1086,53 +1151,6 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) } } - // Scene mode - - scene_mode_string = exynos_param_string_get(exynos_camera, "scene-mode"); - if (scene_mode_string != NULL) { - if (strcmp(scene_mode_string, "auto") == 0) - scene_mode = SCENE_MODE_NONE; - else if (strcmp(scene_mode_string, "portrait") == 0) - scene_mode = SCENE_MODE_PORTRAIT; - else if (strcmp(scene_mode_string, "landscape") == 0) - scene_mode = SCENE_MODE_LANDSCAPE; - else if (strcmp(scene_mode_string, "night") == 0) - scene_mode = SCENE_MODE_NIGHTSHOT; - else if (strcmp(scene_mode_string, "beach") == 0) - scene_mode = SCENE_MODE_BEACH_SNOW; - else if (strcmp(scene_mode_string, "snow") == 0) - scene_mode = SCENE_MODE_BEACH_SNOW; - else if (strcmp(scene_mode_string, "sunset") == 0) - scene_mode = SCENE_MODE_SUNSET; - else if (strcmp(scene_mode_string, "fireworks") == 0) - scene_mode = SCENE_MODE_FIREWORKS; - else if (strcmp(scene_mode_string, "action") == 0) - scene_mode = SCENE_MODE_SPORTS; - else if (strcmp(scene_mode_string, "party") == 0) - scene_mode = SCENE_MODE_PARTY_INDOOR; - else if (strcmp(scene_mode_string, "candlelight") == 0) - scene_mode = SCENE_MODE_CANDLE_LIGHT; - else if (strcmp(scene_mode_string, "dusk-dawn") == 0) - scene_mode = SCENE_MODE_DUSK_DAWN; - else if (strcmp(scene_mode_string, "fall-color") == 0) - scene_mode = SCENE_MODE_FALL_COLOR; - else if (strcmp(scene_mode_string, "back-light") == 0) - scene_mode = SCENE_MODE_BACK_LIGHT; - else if (strcmp(scene_mode_string, "text") == 0) - scene_mode = SCENE_MODE_TEXT; - else if (strcmp(scene_mode_string, "high-sensitivity") == 0) - scene_mode = SCENE_MODE_LOW_LIGHT; - else - scene_mode = SCENE_MODE_NONE; - - if (scene_mode != exynos_camera->scene_mode || force) { - exynos_camera->scene_mode = scene_mode; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SCENE_MODE, scene_mode); - if (rc < 0) - ALOGE("%s: Unable to set scene mode", __func__); - } - } - // Effect effect_string = exynos_param_string_get(exynos_camera, "effect"); @@ -1228,12 +1246,17 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera, int force) // Capture -int s5c73m3_interleaved_decode(void *data, int size, +int s5c73m3_interleaved_decode(struct exynos_camera *exynos_camera, void *data, int size, void *yuv_data, int *yuv_size, int yuv_width, int yuv_height, - void *jpeg_data, int *jpeg_size, int *decoded, int *auto_focus_result) + void *jpeg_data, int *jpeg_size, int *decoded, int *auto_focus_result, + struct exynos_exif *exif) { + exif_attribute_t *attributes; + camera_face_t caface[exynos_camera->max_detected_faces]; int yuv_length; int jpeg_length; + int num_detected_faces; + int face; unsigned char *yuv_p; unsigned char *jpeg_p; unsigned char *data_p; @@ -1265,25 +1288,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) @@ -1299,9 +1304,63 @@ int s5c73m3_interleaved_decode(void *data, int size, offset_p = (unsigned int *) data_p; pointers_array_size = BIG2LITTLE_ENDIAN(*offset_p); + // FaceDetection Information + data_p = (unsigned char *) data; + data_p += size - 0x1000; // End of the first plane (interleaved buffer) + data_p += 108; //Number of Faces Detected + + num_detected_faces = (int) *data_p; + data_p += 2; //Start of Face Detection Info + + exynos_camera->mFaceData.faces = caface; + if (num_detected_faces > 0 && num_detected_faces < exynos_camera->max_detected_faces) + { + for (face = 0; face < num_detected_faces; face++) { + exynos_camera->mFaceData.faces[face].rect[0] = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + exynos_camera->mFaceData.faces[face].rect[1] = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + exynos_camera->mFaceData.faces[face].rect[2] = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + exynos_camera->mFaceData.faces[face].rect[3] = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + exynos_camera->mFaceData.faces[face].score = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + exynos_camera->mFaceData.faces[face].id = (short)(data_p[1] << 8) + data_p[0]; + data_p += 2; + } + } + exynos_camera->mFaceData.number_of_faces = num_detected_faces; + if (!*decoded) return 0; + attributes = &exif->attributes; + + //Extract the EXIF from the Metadata + //Flash + data_p = (unsigned char *) data; + data_p += size - 0x1000; // End of the first plane (interleaved buffer) + data_p += 4; // EXIF Flash Offset + attributes->flash = (int) data_p[0]; + + //ISO + data_p += 4; // EXIF ISO Offset + attributes->iso_speed_rating = (data_p[1] << 8) + data_p[0]; + + //Exposure + data_p += 4; // EXIF Exposure Offset + attributes->brightness.num = (int) data_p[0]; + + //Exposure Bias + data_p += 4; // EXIF Exposure Bias Offset + attributes->exposure_bias.num = (data_p[1] << 8) + data_p[0]; + + //Exposure Time + data_p += 8; // EXIF Exposure Time Offset + attributes->exposure_time.den = (data_p[1] << 8) + data_p[0]; + + ALOGD("%s: Interleaved pointers array is at offset 0x%x, 0x%x bytes long\n", __func__, pointers_array_offset, pointers_array_size); if ((int) pointers_array_offset > size || (int) pointers_array_size > size || (int) pointers_array_size < yuv_height * (int) sizeof(unsigned int)) { @@ -1386,6 +1445,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; @@ -1446,17 +1506,36 @@ int exynos_camera_capture(struct exynos_camera *exynos_camera) yuv_length = jpeg_length = 0; auto_focus_result = decoded = 0; - rc = s5c73m3_interleaved_decode(pointer, buffer_length, exynos_camera->capture_yuv_buffer, &yuv_length, width, height, exynos_camera->capture_jpeg_buffer, &jpeg_length, &decoded, &auto_focus_result); + rc = s5c73m3_interleaved_decode(exynos_camera, pointer, buffer_length, exynos_camera->capture_yuv_buffer, &yuv_length, width, height, exynos_camera->capture_jpeg_buffer, &jpeg_length, &decoded, &auto_focus_result, &exynos_camera->exif); if (rc < 0) { ALOGE("%s: Unable to decode S5C73M3 interleaved", __func__); 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; @@ -1505,6 +1584,8 @@ int exynos_camera_capture(struct exynos_camera *exynos_camera) buffer->format = V4L2_PIX_FMT_JPEG; exynos_camera->capture_hybrid = 0; + + exynos_exif_create(exynos_camera, &exynos_camera->exif); } break; case V4L2_PIX_FMT_JPEG: @@ -1555,6 +1636,7 @@ int exynos_camera_capture(struct exynos_camera *exynos_camera) buffer->width = exynos_camera->jpeg_thumbnail_width; buffer->height = exynos_camera->jpeg_thumbnail_height; buffer->format = V4L2_PIX_FMT_JPEG; + break; default: buffers_count = 1; @@ -1932,6 +2014,10 @@ int exynos_camera_capture_start(struct exynos_camera *exynos_camera) } exynos_camera->capture_memory = memory; + + memory = exynos_camera->callbacks.request_memory(-1, 1, 1, exynos_camera->callbacks.user); + + exynos_camera->face_data = memory; } else { ALOGE("%s: No memory request function!", __func__); goto error; @@ -1942,6 +2028,10 @@ int exynos_camera_capture_start(struct exynos_camera *exynos_camera) exynos_camera->capture_jpeg_buffer = malloc(buffer_length); } + // Start EXIF + memset(&exynos_camera->exif, 0, sizeof(exynos_camera->exif)); + exynos_exif_start(exynos_camera, &exynos_camera->exif); + for (i = 0; i < buffers_count; i++) { rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, i); if (rc < 0) { @@ -1980,6 +2070,21 @@ int exynos_camera_capture_start(struct exynos_camera *exynos_camera) goto error; } + // Few Scene Modes require to be set after stream on + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SCENE_MODE, exynos_camera->scene_mode); + if (rc < 0) { + ALOGE("%s: Unable to set scene mode", __func__); + goto error; + } + + if (exynos_camera->camera_fimc_is) { + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_IS_CMD_FD, IS_FD_COMMAND_START); + if (rc < 0) { + ALOGE("%s: Unable to start face detection", __func__); + goto error; + } + } + exynos_camera->capture_enabled = 1; pthread_mutex_unlock(&exynos_camera->capture_lock_mutex); @@ -2020,6 +2125,12 @@ void exynos_camera_capture_stop(struct exynos_camera *exynos_camera) ALOGE("%s: Unable to set hybrid", __func__); } + if (exynos_camera->camera_fimc_is) { + rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_IS_CMD_FD, IS_FD_COMMAND_STOP); + if (rc < 0) + ALOGE("%s: Unable to stop face detection", __func__); + } + rc = exynos_v4l2_streamoff_cap(exynos_camera, 0); if (rc < 0) { ALOGE("%s: Unable to stop stream", __func__); @@ -2040,6 +2151,11 @@ void exynos_camera_capture_stop(struct exynos_camera *exynos_camera) exynos_camera->capture_jpeg_buffer = NULL; } + if (&exynos_camera->exif != NULL) { + exynos_exif_stop(exynos_camera, &exynos_camera->exif); + free(&exynos_camera->exif); + } + exynos_camera->capture_enabled = 0; } @@ -2155,10 +2271,12 @@ struct exynos_camera_capture_listener *exynos_camera_capture_listener_register( if (exynos_camera->capture_listeners == NULL) exynos_camera->capture_listeners = listener; - rc = exynos_camera_capture_setup(exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to setup capture", __func__); - goto error; + if (!(exynos_camera->camera_fimc_is && exynos_camera->picture_thread_enabled)) { + rc = exynos_camera_capture_setup(exynos_camera); + if (rc < 0) { + ALOGE("%s: Unable to setup capture", __func__); + goto error; + } } rc = 0; @@ -2397,6 +2515,7 @@ int exynos_camera_preview(struct exynos_camera *exynos_camera) void *window_data; int window_stride; camera_memory_t *memory; + camera_face_t caface[exynos_camera->max_detected_faces]; void *memory_pointer; int memory_index; int memory_size; @@ -2447,10 +2566,19 @@ int exynos_camera_preview(struct exynos_camera *exynos_camera) exynos_camera->preview_window->enqueue_buffer(exynos_camera->preview_window, window_buffer); } + if (exynos_camera->camera_fimc_is) { + exynos_camera->mFaceData.faces = caface; + exynos_v4l2_s_ext_ctrl_face_detection(exynos_camera, 0, &exynos_camera->mFaceData); + } + if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_PREVIEW_FRAME) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) && !exynos_camera->callback_lock) { exynos_camera->callbacks.data(CAMERA_MSG_PREVIEW_FRAME, memory, memory_index, NULL, exynos_camera->callbacks.user); } + if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_PREVIEW_METADATA) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) && !exynos_camera->callback_lock) { + exynos_camera->callbacks.data(CAMERA_MSG_PREVIEW_METADATA, exynos_camera->face_data, 0, &exynos_camera->mFaceData, exynos_camera->callbacks.user); + } + if (exynos_camera->preview_output_enabled) { rc = exynos_v4l2_output_release(exynos_camera, output); if (rc < 0) { @@ -2650,12 +2778,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) { @@ -2692,7 +2818,7 @@ int exynos_camera_picture_callback(struct exynos_camera *exynos_camera, else if (buffers->width == thumbnail_width && buffers->height == thumbnail_height) jpeg_thumbnail_buffer = buffers; } else { - if (buffers->width >= width && buffers->height >= height) + if ((buffers->width >= width && buffers->height >= height) || exynos_camera->camera_fimc_is) yuv_buffer = buffers; if (buffers->width >= thumbnail_width && buffers->height >= thumbnail_height) yuv_thumbnail_buffer = buffers; @@ -2762,7 +2888,6 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera) struct exynos_camera_buffer *yuv_thumbnail_buffer; struct exynos_v4l2_output output; struct exynos_jpeg jpeg; - struct exynos_exif exif; int output_enabled = 0; int width, height, format; int buffer_width, buffer_height, buffer_format, buffer_address; @@ -2832,7 +2957,7 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera) buffer_format = yuv_buffer->format; buffer_address = yuv_buffer->address; - if (width != buffer_width && height != buffer_height) { + if ((width != buffer_width && height != buffer_height) || exynos_camera->camera_fimc_is) { format = EXYNOS_CAMERA_PICTURE_OUTPUT_FORMAT; memset(&output, 0, sizeof(output)); @@ -2862,6 +2987,9 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera) yuv_data = output.memory->data; yuv_address = output.memory_address; yuv_size = output.buffer_length; + + if (exynos_camera->camera_fimc_is) + exynos_exif_create(exynos_camera, &exynos_camera->exif); } memset(&jpeg, 0, sizeof(jpeg)); @@ -3022,24 +3150,16 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera) } // EXIF + exynos_camera->exif.jpeg_thumbnail_data = jpeg_thumbnail_data; + exynos_camera->exif.jpeg_thumbnail_size = jpeg_thumbnail_size; - memset(&exif, 0, sizeof(exif)); - exif.jpeg_thumbnail_data = jpeg_thumbnail_data; - exif.jpeg_thumbnail_size = jpeg_thumbnail_size; - - rc = exynos_exif_start(exynos_camera, &exif); - if (rc < 0) { - ALOGE("%s: Unable to start exif", __func__); - goto error; - } - - rc = exynos_exif(exynos_camera, &exif); + rc = exynos_exif(exynos_camera, &exynos_camera->exif); if (rc < 0) { ALOGE("%s: Unable to exif", __func__); goto error; } - memory_size = exif.memory_size + jpeg_size; + memory_size = exynos_camera->exif.memory_size + jpeg_size; if (EXYNOS_CAMERA_CALLBACK_DEFINED(request_memory)) { memory = exynos_camera->callbacks.request_memory(-1, memory_size, 1, exynos_camera->callbacks.user); @@ -3059,14 +3179,12 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera) p += 2; // Copy the EXIF data - memcpy(p, exif.memory->data, exif.memory_size); - p += exif.memory_size; + memcpy(p, exynos_camera->exif.memory->data, exynos_camera->exif.memory_size); + p += exynos_camera->exif.memory_size; // Copy the JPEG picture memcpy(p, (void *) ((unsigned char *) jpeg_data + 2), jpeg_size - 2); - exynos_exif_stop(exynos_camera, &exif); - exynos_camera->picture_memory = memory; rc = 0; @@ -3724,69 +3842,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) -{ - 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) +int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera) { - pthread_attr_t thread_attr; int auto_focus; int rc; @@ -3795,13 +3864,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); @@ -3810,22 +3872,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; @@ -3833,38 +3885,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); + } /* @@ -4161,7 +4215,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) @@ -4175,7 +4229,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; } @@ -4192,8 +4246,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; } @@ -4290,13 +4343,59 @@ void exynos_camera_put_parameters(struct camera_device *dev, char *params) free(params); } +int setFaceDetect(struct exynos_camera *exynos_camera, int face_detect) +{ + ALOGD("%s(face_detect(%d))", __func__, face_detect); + if (exynos_camera->camera_fimc_is) { + if (face_detect < IS_FD_COMMAND_STOP || IS_FD_COMMAND_MAX <= face_detect) { + ALOGE("ERR(%s):Invalid face_detect value (%d)", __func__, face_detect); + return -1; + } + } else { + if (face_detect < FACE_DETECTION_OFF || FACE_DETECTION_MAX <= face_detect) { + ALOGE("ERR(%s):Invalid face_detect value (%d)", __func__, face_detect); + return -1; + } + } + + if (exynos_camera->camera_fimc_is) { + if (exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_IS_CMD_FD, face_detect) < 0) { + ALOGE("ERR(%s):Fail on V4L2_CID_IS_CMD_FD", __func__); + return -1; + } + } else { + if (exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FACE_DETECTION, face_detect) < 0) { + ALOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FACE_DETECTION", __func__); + return -1; + } + } + + return 0; +} + int exynos_camera_send_command(struct camera_device *dev, int32_t cmd, int32_t arg1, int32_t arg2) { + struct exynos_camera *exynos_camera; + exynos_camera = (struct exynos_camera *) dev->priv; + ALOGD("%s(%p, %d, %d, %d)", __func__, dev, cmd, arg1, arg2); switch (cmd) { case CAMERA_CMD_START_FACE_DETECTION: - return -EINVAL; + if (setFaceDetect(exynos_camera, FACE_DETECTION_ON) < 0) { + ALOGE("ERR: Fail on setFaceDetect(ON)"); + return -EINVAL; + } else { + return 0; + } + break; + case CAMERA_CMD_STOP_FACE_DETECTION: + if (setFaceDetect(exynos_camera, FACE_DETECTION_OFF) < 0) { + ALOGE("ERR: Fail on setFaceDetect(OFF)"); + return -EINVAL; + } else { + return 0; + } break; default: break; diff --git a/camera/exynos_camera.h b/camera/exynos_camera.h index 9895ef5..6579305 100644 --- a/camera/exynos_camera.h +++ b/camera/exynos_camera.h @@ -144,6 +144,8 @@ struct exynos_camera_params { char *focus_areas; int max_num_focus_areas; + int max_detected_faces; + int zoom_supported; int smooth_zoom_supported; char *zoom_ratios; @@ -312,12 +314,13 @@ struct exynos_camera { int capture_enabled; struct exynos_camera_capture_listener *capture_listeners; + struct exynos_exif exif; camera_memory_t *capture_memory; int capture_memory_address; 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; @@ -356,6 +359,11 @@ struct exynos_camera { struct exynos_camera_buffer picture_yuv_buffer; struct exynos_camera_buffer picture_yuv_thumbnail_buffer; + // Face Detection + camera_frame_metadata_t mFaceData; + camera_memory_t *face_data; + int max_detected_faces; + // Recording pthread_t recording_thread; @@ -376,10 +384,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 @@ -508,14 +513,16 @@ 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 */ int exynos_exif_start(struct exynos_camera *exynos_camera, struct exynos_exif *exif); +int exynos_exif_create(struct exynos_camera *exynos_camera, struct exynos_exif *exif); void exynos_exif_stop(struct exynos_camera *exynos_camera, struct exynos_exif *exif); int exynos_exif(struct exynos_camera *exynos_camera, struct exynos_exif *exif); @@ -590,6 +597,8 @@ int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int exynos_v4l2_id, int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id); int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id, int type, int memory, int index, unsigned long userptr); +int exynos_v4l2_s_ext_ctrl_face_detection(struct exynos_camera *exynos_camera, + int id, void *value); int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id, int index); int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id, diff --git a/camera/exynos_exif.c b/camera/exynos_exif.c index b0d1656..486b256 100644 --- a/camera/exynos_exif.c +++ b/camera/exynos_exif.c @@ -262,63 +262,68 @@ int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera, attributes->focal_length.num = exynos_camera->camera_focal_length; attributes->focal_length.den = EXIF_DEF_FOCAL_LEN_DEN; - shutter_speed = 100; - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_TV, - &shutter_speed); - if (rc < 0) - ALOGE("%s: Unable to get shutter speed", __func__); + // Only Query the Front Camera Sensor for EXIF Attributes. + if (exynos_camera->camera_fimc_is) { + rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EXPTIME, + &exposure_time); + if (rc < 0) + ALOGE("%s: Unable to get exposure time", __func__); - attributes->shutter_speed.num = shutter_speed; - attributes->shutter_speed.den = 100; - - attributes->exposure_time.num = 1; - attributes->exposure_time.den = APEX_SHUTTER_TO_EXPOSURE(shutter_speed); + attributes->exposure_time.den = exposure_time; - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO, - &iso_speed); - if (rc < 0) - ALOGE("%s: Unable to get iso", __func__); + rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO, + &iso_speed); + if (rc < 0) + ALOGE("%s: Unable to get iso", __func__); - attributes->iso_speed_rating = iso_speed; + attributes->iso_speed_rating = iso_speed; - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_FLASH, - &flash_results); - if (rc < 0) - ALOGE("%s: Unable to get flash", __func__); + rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_FLASH, + &flash_results); + if (rc < 0) + ALOGE("%s: Unable to get flash", __func__); - attributes->flash = flash_results; + attributes->flash = flash_results; - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_BV, + rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_BV, (int *) &bv); - if (rc < 0) { - ALOGE("%s: Unable to get bv", __func__); - goto bv_static; - } + if (rc < 0) { + ALOGE("%s: Unable to get bv", __func__); + goto bv_static; + } - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EBV, - (int *) &ev); - if (rc < 0) { - ALOGE("%s: Unable to get ebv", __func__); - goto bv_static; - } + rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EBV, + (int *) &ev); + if (rc < 0) { + ALOGE("%s: Unable to get ebv", __func__); + goto bv_static; + } - goto bv_ioctl; + goto bv_ioctl; bv_static: - exposure = exynos_param_int_get(exynos_camera, "exposure-compensation"); - if (exposure < 0) - exposure = EV_DEFAULT; + exposure = exynos_param_int_get(exynos_camera, "exposure-compensation"); + if (exposure < 0) + exposure = EV_DEFAULT; + + av = APEX_FNUM_TO_APERTURE((double) attributes->fnumber.num / + attributes->fnumber.den); + tv = APEX_EXPOSURE_TO_SHUTTER((double) attributes->exposure_time.num / + attributes->exposure_time.den); + sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed); + bv = av + tv - sv; + ev = exposure - EV_DEFAULT; - av = APEX_FNUM_TO_APERTURE((double) attributes->fnumber.num / - attributes->fnumber.den); - tv = APEX_EXPOSURE_TO_SHUTTER((double) attributes->exposure_time.num / - attributes->exposure_time.den); - sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed); - bv = av + tv - sv; - ev = exposure - EV_DEFAULT; bv_ioctl: - attributes->brightness.num = bv; + attributes->brightness.num = bv; + } + + attributes->shutter_speed.num = APEX_EXPOSURE_TO_SHUTTER(attributes->exposure_time.den); + attributes->shutter_speed.den = 100; + + attributes->exposure_time.num = 1; + attributes->brightness.den = EXIF_DEF_APEX_DEN; if (exynos_camera->scene_mode == SCENE_MODE_BEACH_SNOW) { @@ -450,6 +455,24 @@ complete: return rc; } +int exynos_exif_create(struct exynos_camera *exynos_camera, struct exynos_exif *exif) +{ + int rc; + + rc = exynos_exif_attributes_create_params(exynos_camera, exif); + if (rc < 0) { + ALOGE("%s: Unable to create exif parameters", __func__); + goto error; + } + + goto complete; +error: + rc = -1; + +complete: + return rc; +} + void exynos_exif_stop(struct exynos_camera *exynos_camera, struct exynos_exif *exif) { diff --git a/camera/exynos_v4l2.c b/camera/exynos_v4l2.c index 2e7fdaf..2768676 100644 --- a/camera/exynos_v4l2.c +++ b/camera/exynos_v4l2.c @@ -232,6 +232,69 @@ int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id, return buffer.index; } +int exynos_v4l2_s_ext_ctrl_face_detection(struct exynos_camera *exynos_camera, + int id, void *value) +{ + struct v4l2_ext_control ext_ctrl_fd[111]; + struct v4l2_ext_controls ext_ctrls_fd; + struct v4l2_ext_controls *ctrls; + camera_frame_metadata_t *facedata = (camera_frame_metadata_t *)value; + int i, ret; + + ext_ctrl_fd[0].id = V4L2_CID_IS_FD_GET_FACE_COUNT; + for (i = 0; i < exynos_camera->max_detected_faces; i++) { + ext_ctrl_fd[22*i+1].id = V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER; + ext_ctrl_fd[22*i+2].id = V4L2_CID_IS_FD_GET_FACE_CONFIDENCE; + ext_ctrl_fd[22*i+3].id = V4L2_CID_IS_FD_GET_FACE_SMILE_LEVEL; + ext_ctrl_fd[22*i+4].id = V4L2_CID_IS_FD_GET_FACE_BLINK_LEVEL; + ext_ctrl_fd[22*i+5].id = V4L2_CID_IS_FD_GET_FACE_TOPLEFT_X; + ext_ctrl_fd[22*i+6].id = V4L2_CID_IS_FD_GET_FACE_TOPLEFT_Y; + ext_ctrl_fd[22*i+7].id = V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_X; + ext_ctrl_fd[22*i+8].id = V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_Y; + ext_ctrl_fd[22*i+9].id = V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_X; + ext_ctrl_fd[22*i+10].id = V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_Y; + ext_ctrl_fd[22*i+11].id = V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_X; + ext_ctrl_fd[22*i+12].id = V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_Y; + ext_ctrl_fd[22*i+13].id = V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_X; + ext_ctrl_fd[22*i+14].id = V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_Y; + ext_ctrl_fd[22*i+15].id = V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_X; + ext_ctrl_fd[22*i+16].id = V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_Y; + ext_ctrl_fd[22*i+17].id = V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_X; + ext_ctrl_fd[22*i+18].id = V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_Y; + ext_ctrl_fd[22*i+19].id = V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_X; + ext_ctrl_fd[22*i+20].id = V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_Y; + ext_ctrl_fd[22*i+21].id = V4L2_CID_IS_FD_GET_ANGLE; + ext_ctrl_fd[22*i+22].id = V4L2_CID_IS_FD_GET_NEXT; + } + + ext_ctrls_fd.ctrl_class = V4L2_CTRL_CLASS_CAMERA; + ext_ctrls_fd.count = 111; + ext_ctrls_fd.controls = ext_ctrl_fd; + ctrls = &ext_ctrls_fd; + + ret = exynos_v4l2_ioctl(exynos_camera, id, VIDIOC_G_EXT_CTRLS, &ext_ctrls_fd); + + facedata->number_of_faces = ext_ctrls_fd.controls[0].value; + + for(i = 0; i < facedata->number_of_faces; i++) { + facedata->faces[i].rect[0] = ext_ctrl_fd[22*i+5].value; + facedata->faces[i].rect[1] = ext_ctrl_fd[22*i+6].value; + facedata->faces[i].rect[2] = ext_ctrl_fd[22*i+7].value; + facedata->faces[i].rect[3] = ext_ctrl_fd[22*i+8].value; + facedata->faces[i].score = ext_ctrl_fd[22*i+2].value; + /* TODO : id is unique value for each face. We need to suppot this. */ + facedata->faces[i].id = 0; + facedata->faces[i].left_eye[0] = (ext_ctrl_fd[22*i+9].value + ext_ctrl_fd[22*i+11].value) / 2; + facedata->faces[i].left_eye[1] = (ext_ctrl_fd[22*i+10].value + ext_ctrl_fd[22*i+12].value) / 2; + facedata->faces[i].right_eye[0] = (ext_ctrl_fd[22*i+13].value + ext_ctrl_fd[22*i+15].value) / 2; + facedata->faces[i].right_eye[1] = (ext_ctrl_fd[22*i+14].value + ext_ctrl_fd[22*i+16].value) / 2; + facedata->faces[i].mouth[0] = (ext_ctrl_fd[22*i+17].value + ext_ctrl_fd[22*i+19].value) / 2; + facedata->faces[i].mouth[1] = (ext_ctrl_fd[22*i+18].value + ext_ctrl_fd[22*i+20].value) / 2; + } + + return ret; +} + int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id) { |