From 0e78a03f89268e0100723c308e2db0dfc03c371d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 3 Jan 2014 13:20:26 +0100 Subject: SMDK4210 Camera Signed-off-by: Paul Kocialkowski --- camera/Android.mk | 10 +- camera/exynos_camera.c | 2865 ---------------------------------------------- camera/exynos_exif.c | 791 ------------- camera/exynos_param.c | 520 --------- camera/smdk4210_camera.c | 2865 ++++++++++++++++++++++++++++++++++++++++++++++ camera/smdk4210_camera.h | 433 +++++++ camera/smdk4210_exif.c | 791 +++++++++++++ camera/smdk4210_param.c | 520 +++++++++ camera/smdk4210_v4l2.c | 796 +++++++++++++ 9 files changed, 5410 insertions(+), 4181 deletions(-) delete mode 100644 camera/exynos_camera.c delete mode 100644 camera/exynos_exif.c delete mode 100644 camera/exynos_param.c create mode 100644 camera/smdk4210_camera.c create mode 100644 camera/smdk4210_camera.h create mode 100644 camera/smdk4210_exif.c create mode 100644 camera/smdk4210_param.c create mode 100644 camera/smdk4210_v4l2.c diff --git a/camera/Android.mk b/camera/Android.mk index 671edae..95c9701 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -18,10 +18,10 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - exynos_camera.c \ - exynos_exif.c \ - exynos_param.c \ - exynos_v4l2.c + smdk4210_camera.c \ + smdk4210_exif.c \ + smdk4210_param.c \ + smdk4210_v4l2.c LOCAL_C_INCLUDES := \ hardware/samsung/exynos4/hal/include @@ -29,7 +29,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libcamera_client libhardware libs5pjpeg LOCAL_PRELINK_MODULE := false -LOCAL_MODULE := camera.$(TARGET_BOOTLOADER_BOARD_NAME) +LOCAL_MODULE := camera.smdk4210 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional diff --git a/camera/exynos_camera.c b/camera/exynos_camera.c deleted file mode 100644 index 98ff74c..0000000 --- a/camera/exynos_camera.c +++ /dev/null @@ -1,2865 +0,0 @@ -/* - * Copyright (C) 2013 Paul Kocialkowski - * - * Based on crespo libcamera and exynos4 hal libcamera: - * Copyright 2008, The Android Open Source Project, Apache License 2.0 - * Copyright 2010, Samsung Electronics Co. LTD, Apache License 2.0 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define LOG_TAG "exynos_camera" -#include -#include - -#include "exynos_camera.h" - -/* - * Devices configurations - */ - -struct exynos_camera_preset exynos_camera_presets_galaxys2[] = { - { - .name = "M5MO", - .facing = CAMERA_FACING_BACK, - .orientation = 90, - .rotation = 0, - .hflip = 0, - .vflip = 0, - .picture_format = V4L2_PIX_FMT_JPEG, - .focal_length = 4.03f, - .horizontal_view_angle = 60.5f, - .vertical_view_angle = 47.1f, - .metering = METERING_CENTER, - .params = { - .preview_size_values = "1280x720,640x480,720x480,800x480,800x450,352x288,320x240,176x144", - .preview_size = "640x480", - .preview_format_values = "yuv420sp,yuv420p,rgb565", - .preview_format = "rgb565", - .preview_frame_rate_values = "30,25,20,15,10,7", - .preview_frame_rate = 30, - .preview_fps_range_values = "(7000,30000)", - .preview_fps_range = "7000,30000", - - .picture_size_values = "3264x2448,3264x1968,2048x1536,2048x1232,1280x960,800x480,640x480", - .picture_size = "3264x2448", - .picture_format_values = "jpeg", - .picture_format = "jpeg", - .jpeg_thumbnail_size_values = "320x240,400x240,0x0", - .jpeg_thumbnail_width = 320, - .jpeg_thumbnail_height = 240, - .jpeg_thumbnail_quality = 100, - .jpeg_quality = 90, - - .recording_size = "720x480", - .recording_size_values = "1920x1080,1280x720,720x480,640x480", - .recording_format = "yuv420sp", - - .focus_mode = "auto", - .focus_mode_values = "auto,infinity,macro,fixed,facedetect,continuous-video", - .focus_distances = "0.15,1.20,Infinity", - .focus_areas = "(0,0,0,0,0)", - .max_num_focus_areas = 1, - - .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", - .zoom = 0, - .max_zoom = 30, - - .flash_mode = "off", - .flash_mode_values = "off,auto,on,torch", - - .exposure_compensation = 0, - .exposure_compensation_step = 0.5, - .min_exposure_compensation = -4, - .max_exposure_compensation = 4, - - .whitebalance = "auto", - .whitebalance_values = "auto,incandescent,fluorescent,daylight,cloudy-daylight", - - .scene_mode = "auto", - .scene_mode_values = "auto,portrait,landscape,night,beach,snow,sunset,fireworks,sports,party,candlelight,dusk-dawn,fall-color,back-light,text", - - .effect = "none", - .effect_values = "none,mono,negative,sepia,aqua", - - .iso = "auto", - .iso_values = "auto,ISO50,ISO100,ISO200,ISO400,ISO800", - }, - }, - { - .name = "S5K5BAFX", - .facing = CAMERA_FACING_FRONT, - .orientation = 270, - .rotation = 0, - .hflip = 0, - .vflip = 0, - .picture_format = V4L2_PIX_FMT_YUYV, - .focal_length = 2.73f, - .horizontal_view_angle = 51.2f, - .vertical_view_angle = 39.4f, - .metering = METERING_CENTER, - .params = { - .preview_size_values = "640x480,352x288,320x240,176x144", - .preview_size = "640x480", - .preview_format_values = "yuv420sp,yuv420p,rgb565", - .preview_format = "rgb565", - .preview_frame_rate_values = "30,25,20,15,10,7", - .preview_frame_rate = 30, - .preview_fps_range_values = "(7000,30000)", - .preview_fps_range = "7000,30000", - - .picture_size_values = "1600x1200,640x480", - .picture_size = "1600x1200", - .picture_format_values = "jpeg", - .picture_format = "jpeg", - .jpeg_thumbnail_size_values = "160x120,0x0", - .jpeg_thumbnail_width = 160, - .jpeg_thumbnail_height = 120, - .jpeg_thumbnail_quality = 100, - .jpeg_quality = 90, - - .recording_size = "640x480", - .recording_size_values = "640x480", - .recording_format = "yuv420sp", - - .focus_mode = "fixed", - .focus_mode_values = "fixed", - .focus_distances = "0.20,0.25,Infinity", - .focus_areas = NULL, - .max_num_focus_areas = 0, - - .zoom_supported = 0, - - .flash_mode = NULL, - .flash_mode_values = NULL, - - .exposure_compensation = 0, - .exposure_compensation_step = 0.5, - .min_exposure_compensation = -4, - .max_exposure_compensation = 4, - - .whitebalance = NULL, - .whitebalance_values = NULL, - - .scene_mode = NULL, - .scene_mode_values = NULL, - - .effect = NULL, - .effect_values = NULL, - - .iso = "auto", - .iso_values = "auto", - }, - }, -}; - -struct exynos_v4l2_node exynos_v4l2_nodes_galaxys2[] = { - { - .id = 0, - .node = "/dev/video0", - }, - { - .id = 1, - .node = "/dev/video1", - }, - { - .id = 2, - .node = "/dev/video2", - }, -}; - -struct exynox_camera_config exynos_camera_config_galaxys2 = { - .presets = (struct exynos_camera_preset *) &exynos_camera_presets_galaxys2, - .presets_count = 2, - .v4l2_nodes = (struct exynos_v4l2_node *) &exynos_v4l2_nodes_galaxys2, - .v4l2_nodes_count = 3, -}; - -/* - * Exynos Camera - */ - -struct exynox_camera_config *exynos_camera_config = - &exynos_camera_config_galaxys2; - -int exynos_camera_init(struct exynos_camera *exynos_camera, int id) -{ - char firmware_version[7] = { 0 }; - struct exynos_v4l2_ext_control control; - int rc; - - if (exynos_camera == NULL || id >= exynos_camera->config->presets_count) - return -EINVAL; - - // Init FIMC1 - rc = exynos_v4l2_open(exynos_camera, 0); - if (rc < 0) { - ALOGE("Unable to open v4l2 device"); - return -1; - } - - rc = exynos_v4l2_querycap_cap(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: querycap failed", __func__); - return -1; - } - - rc = exynos_v4l2_enum_input(exynos_camera, 0, id); - if (rc < 0) { - ALOGE("%s: enum input failed", __func__); - return -1; - } - - rc = exynos_v4l2_s_input(exynos_camera, 0, id); - if (rc < 0) { - ALOGE("%s: s input failed", __func__); - return -1; - } - - // Init FIMC2 - rc = exynos_v4l2_open(exynos_camera, 2); - if (rc < 0) { - ALOGE("Unable to open v4l2 device"); - return -1; - } - - rc = exynos_v4l2_querycap_cap(exynos_camera, 2); - if (rc < 0) { - ALOGE("%s: querycap failed", __func__); - return -1; - } - - rc = exynos_v4l2_enum_input(exynos_camera, 2, id); - if (rc < 0) { - ALOGE("%s: enum input failed", __func__); - return -1; - } - - rc = exynos_v4l2_s_input(exynos_camera, 2, id); - if (rc < 0) { - ALOGE("%s: s input failed", __func__); - return -1; - } - - // Get firmware information - memset(&control, 0, sizeof(control)); - control.id = V4L2_CID_CAM_SENSOR_FW_VER; - control.data.string = firmware_version; - - rc = exynos_v4l2_g_ext_ctrls(exynos_camera, 0, (struct v4l2_ext_control *) &control, 1); - if (rc < 0) { - ALOGE("%s: g ext ctrls failed", __func__); - } else { - ALOGD("Firmware version: %s", firmware_version); - } - - // Params - rc = exynos_camera_params_init(exynos_camera, id); - if (rc < 0) - ALOGE("%s: Unable to init params", __func__); - - // Gralloc - rc = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const struct hw_module_t **) &exynos_camera->gralloc); - if (rc) - ALOGE("%s: Unable to get gralloc module", __func__); - - return 0; -} - -void exynos_camera_deinit(struct exynos_camera *exynos_camera) -{ - int i; - int id; - - if (exynos_camera == NULL || exynos_camera->config == NULL) - return; - - exynos_v4l2_close(exynos_camera, 0); - exynos_v4l2_close(exynos_camera, 2); -} - -// Params - -int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id) -{ - int rc; - - if (exynos_camera == NULL || id >= exynos_camera->config->presets_count) - return -EINVAL; - - // Camera params - exynos_camera->camera_rotation = exynos_camera->config->presets[id].rotation; - exynos_camera->camera_hflip = exynos_camera->config->presets[id].hflip; - exynos_camera->camera_vflip = exynos_camera->config->presets[id].vflip; - exynos_camera->camera_picture_format = exynos_camera->config->presets[id].picture_format; - exynos_camera->camera_focal_length = (int) (exynos_camera->config->presets[id].focal_length * 100); - exynos_camera->camera_metering = exynos_camera->config->presets[id].metering; - - // Recording preview - exynos_param_string_set(exynos_camera, "preferred-preview-size-for-video", - exynos_camera->config->presets[id].params.preview_size); - - // Preview - exynos_param_string_set(exynos_camera, "preview-size-values", - exynos_camera->config->presets[id].params.preview_size_values); - exynos_param_string_set(exynos_camera, "preview-size", - exynos_camera->config->presets[id].params.preview_size); - exynos_param_string_set(exynos_camera, "preview-format-values", - exynos_camera->config->presets[id].params.preview_format_values); - exynos_param_string_set(exynos_camera, "preview-format", - exynos_camera->config->presets[id].params.preview_format); - exynos_param_string_set(exynos_camera, "preview-frame-rate-values", - exynos_camera->config->presets[id].params.preview_frame_rate_values); - exynos_param_int_set(exynos_camera, "preview-frame-rate", - exynos_camera->config->presets[id].params.preview_frame_rate); - exynos_param_string_set(exynos_camera, "preview-fps-range-values", - exynos_camera->config->presets[id].params.preview_fps_range_values); - exynos_param_string_set(exynos_camera, "preview-fps-range", - exynos_camera->config->presets[id].params.preview_fps_range); - - // Picture - exynos_param_string_set(exynos_camera, "picture-size-values", - exynos_camera->config->presets[id].params.picture_size_values); - exynos_param_string_set(exynos_camera, "picture-size", - exynos_camera->config->presets[id].params.picture_size); - exynos_param_string_set(exynos_camera, "picture-format-values", - exynos_camera->config->presets[id].params.picture_format_values); - exynos_param_string_set(exynos_camera, "picture-format", - exynos_camera->config->presets[id].params.picture_format); - exynos_param_string_set(exynos_camera, "jpeg-thumbnail-size-values", - exynos_camera->config->presets[id].params.jpeg_thumbnail_size_values); - exynos_param_int_set(exynos_camera, "jpeg-thumbnail-width", - exynos_camera->config->presets[id].params.jpeg_thumbnail_width); - exynos_param_int_set(exynos_camera, "jpeg-thumbnail-height", - exynos_camera->config->presets[id].params.jpeg_thumbnail_height); - exynos_param_int_set(exynos_camera, "jpeg-thumbnail-quality", - exynos_camera->config->presets[id].params.jpeg_thumbnail_quality); - exynos_param_int_set(exynos_camera, "jpeg-quality", - exynos_camera->config->presets[id].params.jpeg_quality); - - // Recording - exynos_param_string_set(exynos_camera, "video-size", - exynos_camera->config->presets[id].params.recording_size); - exynos_param_string_set(exynos_camera, "video-size-values", - exynos_camera->config->presets[id].params.recording_size_values); - exynos_param_string_set(exynos_camera, "video-frame-format", - exynos_camera->config->presets[id].params.recording_format); - - // Focus - exynos_param_string_set(exynos_camera, "focus-mode", - exynos_camera->config->presets[id].params.focus_mode); - exynos_param_string_set(exynos_camera, "focus-mode-values", - exynos_camera->config->presets[id].params.focus_mode_values); - exynos_param_string_set(exynos_camera, "focus-distances", - exynos_camera->config->presets[id].params.focus_distances); - if (exynos_camera->config->presets[id].params.max_num_focus_areas > 0) { - exynos_param_string_set(exynos_camera, "focus-areas", - exynos_camera->config->presets[id].params.focus_areas); - exynos_param_int_set(exynos_camera, "max-num-focus-areas", - exynos_camera->config->presets[id].params.max_num_focus_areas); - } - - // Zoom - if (exynos_camera->config->presets[id].params.zoom_supported == 1) { - exynos_param_string_set(exynos_camera, "zoom-supported", "true"); - - if (exynos_camera->config->presets[id].params.smooth_zoom_supported == 1) - exynos_param_string_set(exynos_camera, "smooth-zoom-supported", "true"); - - if (exynos_camera->config->presets[id].params.zoom_ratios != NULL) - exynos_param_string_set(exynos_camera, "zoom-ratios", exynos_camera->config->presets[id].params.zoom_ratios); - - exynos_param_int_set(exynos_camera, "zoom", exynos_camera->config->presets[id].params.zoom); - exynos_param_int_set(exynos_camera, "max-zoom", exynos_camera->config->presets[id].params.max_zoom); - - } else { - exynos_param_string_set(exynos_camera, "zoom-supported", "false"); - } - - // Flash - exynos_param_string_set(exynos_camera, "flash-mode", - exynos_camera->config->presets[id].params.flash_mode); - exynos_param_string_set(exynos_camera, "flash-mode-values", - exynos_camera->config->presets[id].params.flash_mode_values); - - // Exposure - exynos_param_int_set(exynos_camera, "exposure-compensation", - exynos_camera->config->presets[id].params.exposure_compensation); - exynos_param_float_set(exynos_camera, "exposure-compensation-step", - exynos_camera->config->presets[id].params.exposure_compensation_step); - exynos_param_int_set(exynos_camera, "min-exposure-compensation", - exynos_camera->config->presets[id].params.min_exposure_compensation); - exynos_param_int_set(exynos_camera, "max-exposure-compensation", - exynos_camera->config->presets[id].params.max_exposure_compensation); - - // WB - exynos_param_string_set(exynos_camera, "whitebalance", - exynos_camera->config->presets[id].params.whitebalance); - exynos_param_string_set(exynos_camera, "whitebalance-values", - exynos_camera->config->presets[id].params.whitebalance_values); - - // Scene mode - exynos_param_string_set(exynos_camera, "scene-mode", - exynos_camera->config->presets[id].params.scene_mode); - exynos_param_string_set(exynos_camera, "scene-mode-values", - exynos_camera->config->presets[id].params.scene_mode_values); - - // Effect - exynos_param_string_set(exynos_camera, "effect", - exynos_camera->config->presets[id].params.effect); - exynos_param_string_set(exynos_camera, "effect-values", - exynos_camera->config->presets[id].params.effect_values); - - // ISO - exynos_param_string_set(exynos_camera, "iso", - exynos_camera->config->presets[id].params.iso); - exynos_param_string_set(exynos_camera, "iso-values", - exynos_camera->config->presets[id].params.iso_values); - - // Camera - exynos_param_float_set(exynos_camera, "focal-length", - exynos_camera->config->presets[id].focal_length); - exynos_param_float_set(exynos_camera, "horizontal-view-angle", - exynos_camera->config->presets[id].horizontal_view_angle); - exynos_param_float_set(exynos_camera, "vertical-view-angle", - exynos_camera->config->presets[id].vertical_view_angle); - - rc = exynos_camera_params_apply(exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to apply params", __func__); - return -1; - } - - return 0; -} - -int exynos_camera_params_apply(struct exynos_camera *exynos_camera) -{ - char *recording_hint_string; - char *recording_preview_size_string; - - char *preview_size_string; - int preview_width = 0; - int preview_height = 0; - char *preview_format_string; - int preview_format; - float preview_format_bpp; - int preview_fps; - - char *picture_size_string; - int picture_width = 0; - int picture_height = 0; - char *picture_format_string; - int picture_format; - - int jpeg_thumbnail_width; - int jpeg_thumbnail_height; - int jpeg_thumbnail_quality; - int jpeg_quality; - - char *video_size_string; - int recording_width = 0; - int recording_height = 0; - char *video_frame_format_string; - int recording_format; - int camera_sensor_mode; - int camera_sensor_output_size; - - char *focus_mode_string; - int focus_mode = 0; - char *focus_areas_string; - int focus_left, focus_top, focus_right, focus_bottom, focus_weigth; - int focus_x; - int focus_y; - - char *zoom_supported_string; - int zoom, max_zoom; - - char *flash_mode_string; - int flash_mode; - - int exposure_compensation; - int min_exposure_compensation; - int max_exposure_compensation; - - char *whitebalance_string; - int whitebalance; - - char *scene_mode_string; - int scene_mode; - - char *effect_string; - int effect; - - char *iso_string; - int iso; - - int force = 0; - - int w, h; - char *k; - int rc; - - if (exynos_camera == NULL) - return -EINVAL; - - if (!exynos_camera->preview_params_set) { - ALOGE("%s: Setting preview params", __func__); - exynos_camera->preview_params_set = 1; - force = 1; - } - - // Preview - preview_size_string = exynos_param_string_get(exynos_camera, "preview-size"); - if (preview_size_string != NULL) { - sscanf(preview_size_string, "%dx%d", &preview_width, &preview_height); - - if (preview_width != 0 && preview_width != exynos_camera->preview_width) - exynos_camera->preview_width = preview_width; - if (preview_height != 0 && preview_height != exynos_camera->preview_height) - exynos_camera->preview_height = preview_height; - } - - preview_format_string = exynos_param_string_get(exynos_camera, "preview-format"); - if (preview_format_string != NULL) { - if (strcmp(preview_format_string, "yuv420sp") == 0) { - preview_format = V4L2_PIX_FMT_NV21; - preview_format_bpp = 1.5f; - } else if (strcmp(preview_format_string, "yuv420p") == 0) { - preview_format = V4L2_PIX_FMT_YUV420; - preview_format_bpp = 1.5f; - } else if (strcmp(preview_format_string, "rgb565") == 0) { - preview_format = V4L2_PIX_FMT_RGB565; - preview_format_bpp = 2.0f; - } else if (strcmp(preview_format_string, "rgb8888") == 0) { - preview_format = V4L2_PIX_FMT_RGB32; - preview_format_bpp = 4.0f; - } else { - ALOGE("%s: Unsupported preview format: %s", __func__, preview_format_string); - preview_format = V4L2_PIX_FMT_NV21; - preview_format_bpp = 1.5f; - } - - if (preview_format != exynos_camera->preview_format) { - exynos_camera->preview_format = preview_format; - exynos_camera->preview_format_bpp = preview_format_bpp; - } - } - - preview_fps = exynos_param_int_get(exynos_camera, "preview-frame-rate"); - if (preview_fps > 0) - exynos_camera->preview_fps = preview_fps; - else - exynos_camera->preview_fps = 0; - - // Picture - picture_size_string = exynos_param_string_get(exynos_camera, "picture-size"); - if (picture_size_string != NULL) { - sscanf(picture_size_string, "%dx%d", &picture_width, &picture_height); - - if (picture_width != 0 && picture_width != exynos_camera->picture_width) - exynos_camera->picture_width = picture_width; - if (picture_height != 0 && picture_height != exynos_camera->picture_height) - exynos_camera->picture_height = picture_height; - } - - picture_format_string = exynos_param_string_get(exynos_camera, "picture-format"); - if (picture_format_string != NULL) { - if (strcmp(picture_format_string, "jpeg") == 0) { - picture_format = V4L2_PIX_FMT_JPEG; - } else { - ALOGE("%s: Unsupported picture format: %s", __func__, picture_format_string); - picture_format = V4L2_PIX_FMT_JPEG; - } - - if (picture_format != exynos_camera->picture_format) - exynos_camera->picture_format = picture_format; - } - - jpeg_thumbnail_width = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-width"); - if (jpeg_thumbnail_width > 0) - exynos_camera->jpeg_thumbnail_width = jpeg_thumbnail_width; - - jpeg_thumbnail_height = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-height"); - if (jpeg_thumbnail_height > 0) - exynos_camera->jpeg_thumbnail_height = jpeg_thumbnail_height; - - jpeg_thumbnail_quality = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-quality"); - if (jpeg_thumbnail_quality > 0) - exynos_camera->jpeg_thumbnail_quality = jpeg_thumbnail_quality; - - jpeg_quality = exynos_param_int_get(exynos_camera, "jpeg-quality"); - if (jpeg_quality <= 100 && jpeg_quality >= 0 && (jpeg_quality != exynos_camera->jpeg_quality || force)) { - exynos_camera->jpeg_quality = jpeg_quality; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_QUALITY, jpeg_quality); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - // Recording - video_size_string = exynos_param_string_get(exynos_camera, "video-size"); - if (video_size_string == NULL) - video_size_string = exynos_param_string_get(exynos_camera, "preview-size"); - - if (video_size_string != NULL) { - sscanf(video_size_string, "%dx%d", &recording_width, &recording_height); - - if (recording_width != 0 && recording_width != exynos_camera->recording_width) - exynos_camera->recording_width = recording_width; - if (recording_height != 0 && recording_height != exynos_camera->recording_height) - exynos_camera->recording_height = recording_height; - } - - video_frame_format_string = exynos_param_string_get(exynos_camera, "video-frame-format"); - if (video_frame_format_string != NULL) { - if (strcmp(video_frame_format_string, "yuv420sp") == 0) { - recording_format = V4L2_PIX_FMT_NV12; - } else if (strcmp(video_frame_format_string, "yuv420p") == 0) { - recording_format = V4L2_PIX_FMT_YUV420; - } else if (strcmp(video_frame_format_string, "rgb565") == 0) { - recording_format = V4L2_PIX_FMT_RGB565; - } else if (strcmp(video_frame_format_string, "rgb8888") == 0) { - recording_format = V4L2_PIX_FMT_RGB32; - } else { - ALOGE("%s: Unsupported recording format: %s", __func__, video_frame_format_string); - recording_format = V4L2_PIX_FMT_NV12; - } - - if (recording_format != exynos_camera->recording_format) - exynos_camera->recording_format = recording_format; - } - - recording_hint_string = exynos_param_string_get(exynos_camera, "recording-hint"); - if (recording_hint_string != NULL && strcmp(recording_hint_string, "true") == 0) { - camera_sensor_mode = SENSOR_MOVIE; - - k = exynos_param_string_get(exynos_camera, "preview-size-values"); - while (recording_width != 0 && recording_height != 0) { - if (k == NULL) - break; - - sscanf(k, "%dx%d", &w, &h); - - // Look for same aspect ratio - if ((recording_width * h) / recording_height == w) { - preview_width = w; - preview_height = h; - break; - } - - k = strchr(k, ','); - if (k == NULL) - break; - - k++; - } - - if (preview_width != 0 && preview_width != exynos_camera->preview_width) - exynos_camera->preview_width = preview_width; - if (preview_height != 0 && preview_height != exynos_camera->preview_height) - exynos_camera->preview_height = preview_height; - - camera_sensor_output_size = ((recording_width & 0xffff) << 16) | (recording_height & 0xffff); - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SENSOR_OUTPUT_SIZE, - camera_sensor_output_size); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } else { - camera_sensor_mode = SENSOR_CAMERA; - } - - // Switching modes - if (camera_sensor_mode != exynos_camera->camera_sensor_mode) { - exynos_camera->camera_sensor_mode = camera_sensor_mode; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SENSOR_MODE, camera_sensor_mode); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - // Focus - focus_areas_string = exynos_param_string_get(exynos_camera, "focus-areas"); - if (focus_areas_string != NULL) { - focus_left = focus_top = focus_right = focus_bottom = focus_weigth = 0; - - rc = sscanf(focus_areas_string, "(%d,%d,%d,%d,%d)", - &focus_left, &focus_top, &focus_right, &focus_bottom, &focus_weigth); - if (rc != 5) { - ALOGE("%s: sscanf failed!", __func__); - } else if (focus_left != 0 && focus_top != 0 && focus_right != 0 && focus_bottom != 0) { - focus_x = (((focus_left + focus_right) / 2) + 1000) * preview_width / 2000; - focus_y = (((focus_top + focus_bottom) / 2) + 1000) * preview_height / 2000; - - if (focus_x != exynos_camera->focus_x || force) { - exynos_camera->focus_x = focus_x; - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_X, focus_x); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - if (focus_y != exynos_camera->focus_y || force) { - exynos_camera->focus_y = focus_y; - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_Y, focus_y); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __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; - else if (strcmp(focus_mode_string, "continuous-picture") == 0) - focus_mode = FOCUS_MODE_CONTINOUS; - else - focus_mode = FOCUS_MODE_AUTO; - } - - 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: s ctrl failed!", __func__); - } - - if (focus_mode == FOCUS_MODE_TOUCH) { - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, 1); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } else if (exynos_camera->focus_mode == FOCUS_MODE_TOUCH) { - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, 0); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - exynos_camera->focus_mode = focus_mode; - } - - // Zoom - zoom_supported_string = exynos_param_string_get(exynos_camera, "zoom-supported"); - if (zoom_supported_string != NULL && strcmp(zoom_supported_string, "true") == 0) { - zoom = exynos_param_int_get(exynos_camera, "zoom"); - max_zoom = exynos_param_int_get(exynos_camera, "max-zoom"); - if (zoom <= max_zoom && zoom >= 0 && (zoom != exynos_camera->zoom || force)) { - exynos_camera->zoom = zoom; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_ZOOM, zoom); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - } - - // 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 - flash_mode = FLASH_MODE_AUTO; - - if (flash_mode != exynos_camera->flash_mode || force) { - exynos_camera->flash_mode = flash_mode; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FLASH_MODE, flash_mode); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - } - - // Exposure - exposure_compensation = exynos_param_int_get(exynos_camera, "exposure-compensation"); - min_exposure_compensation = exynos_param_int_get(exynos_camera, "min-exposure-compensation"); - max_exposure_compensation = exynos_param_int_get(exynos_camera, "max-exposure-compensation"); - - if (exposure_compensation <= max_exposure_compensation && exposure_compensation >= min_exposure_compensation && - (exposure_compensation != exynos_camera->exposure_compensation || force)) { - exynos_camera->exposure_compensation = exposure_compensation; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_BRIGHTNESS, exposure_compensation); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - - // WB - whitebalance_string = exynos_param_string_get(exynos_camera, "whitebalance"); - if (whitebalance_string != NULL) { - if (strcmp(whitebalance_string, "auto") == 0) - whitebalance = WHITE_BALANCE_AUTO; - else if (strcmp(whitebalance_string, "incandescent") == 0) - whitebalance = WHITE_BALANCE_TUNGSTEN; - else if (strcmp(whitebalance_string, "fluorescent") == 0) - whitebalance = WHITE_BALANCE_FLUORESCENT; - else if (strcmp(whitebalance_string, "daylight") == 0) - whitebalance = WHITE_BALANCE_SUNNY; - else if (strcmp(whitebalance_string, "cloudy-daylight") == 0) - whitebalance = WHITE_BALANCE_CLOUDY; - else - whitebalance = WHITE_BALANCE_AUTO; - - if (whitebalance != exynos_camera->whitebalance || force) { - exynos_camera->whitebalance = whitebalance; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_WHITE_BALANCE, whitebalance); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __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; - 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, "sports") == 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 - 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: s ctrl failed!", __func__); - } - } - - // Effect - effect_string = exynos_param_string_get(exynos_camera, "effect"); - if (effect_string != NULL) { - if (strcmp(effect_string, "auto") == 0) - effect = IMAGE_EFFECT_NONE; - else if (strcmp(effect_string, "mono") == 0) - effect = IMAGE_EFFECT_BNW; - else if (strcmp(effect_string, "negative") == 0) - effect = IMAGE_EFFECT_NEGATIVE; - else if (strcmp(effect_string, "sepia") == 0) - effect = IMAGE_EFFECT_SEPIA; - else if (strcmp(effect_string, "aqua") == 0) - effect = IMAGE_EFFECT_AQUA; - else - effect = IMAGE_EFFECT_NONE; - - if (effect != exynos_camera->effect || force) { - exynos_camera->effect = effect; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EFFECT, effect); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - } - - // ISO - iso_string = exynos_param_string_get(exynos_camera, "iso"); - if (iso_string != NULL) { - if (strcmp(iso_string, "auto") == 0) - iso = ISO_AUTO; - else if (strcmp(iso_string, "ISO50") == 0) - iso = ISO_50; - else if (strcmp(iso_string, "ISO100") == 0) - iso = ISO_100; - else if (strcmp(iso_string, "ISO200") == 0) - iso = ISO_200; - else if (strcmp(iso_string, "ISO400") == 0) - iso = ISO_400; - else if (strcmp(iso_string, "ISO800") == 0) - iso = ISO_800; - else - iso = ISO_AUTO; - - if (iso != exynos_camera->iso || force) { - exynos_camera->iso = iso; - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_ISO, iso); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - } - } - - ALOGD("%s: Preview size: %dx%d, picture size: %dx%d, recording size: %dx%d", - __func__, preview_width, preview_height, picture_width, picture_height, - recording_width, recording_height); - - return 0; -} - -// Picture - -int exynos_camera_picture(struct exynos_camera *exynos_camera) -{ - camera_memory_t *data_memory = NULL; - camera_memory_t *exif_data_memory = NULL; - camera_memory_t *picture_data_memory = NULL; - camera_memory_t *jpeg_thumbnail_data_memory = NULL; - - int camera_picture_format; - int picture_width; - int picture_height; - int picture_format; - - int jpeg_thumbnail_width; - int jpeg_thumbnail_height; - int jpeg_thumbnail_quality; - int jpeg_quality; - - int data_size; - - int offset = 0; - void *picture_addr = NULL; - int picture_size = 0; - void *jpeg_thumbnail_addr = NULL; - int jpeg_thumbnail_size = 0; - - int jpeg_fd; - struct jpeg_enc_param jpeg_enc_params; - enum jpeg_frame_format jpeg_in_format; - enum jpeg_stream_format jpeg_out_format; - enum jpeg_ret_type jpeg_result; - void *jpeg_in_buffer; - int jpeg_in_size; - void *jpeg_out_buffer; - int jpeg_out_size; - - exif_attribute_t exif_attributes; - int exif_size = 0; - - int index; - int rc; - - if (exynos_camera == NULL) - return -EINVAL; - - picture_width = exynos_camera->picture_width; - picture_height = exynos_camera->picture_height; - picture_format = exynos_camera->picture_format; - camera_picture_format = exynos_camera->camera_picture_format; - jpeg_thumbnail_width = exynos_camera->jpeg_thumbnail_width; - jpeg_thumbnail_height = exynos_camera->jpeg_thumbnail_height; - jpeg_thumbnail_quality = exynos_camera->jpeg_thumbnail_quality; - jpeg_quality = exynos_camera->jpeg_quality; - - if (camera_picture_format == 0) - camera_picture_format = picture_format; - - // V4L2 - - rc = exynos_v4l2_poll(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: poll failed!", __func__); - return -1; - } else if (rc == 0) { - ALOGE("%s: poll timeout!", __func__); - return -1; - } - - rc = exynos_v4l2_streamoff_cap(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: streamoff failed!", __func__); - return -1; - } - - index = exynos_v4l2_dqbuf_cap(exynos_camera, 0); - if (index < 0) { - ALOGE("%s: dqbuf failed!", __func__); - return -1; - } - - // This assumes that the output format is JPEG - - if (camera_picture_format == V4L2_PIX_FMT_JPEG) { - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_SIZE, - &picture_size); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - return -1; - } - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_OFFSET, - &offset); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - return -1; - } - - picture_addr = (void *) ((int) exynos_camera->picture_memory->data + offset); - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_SIZE, - &jpeg_thumbnail_size); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - return -1; - } - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_OFFSET, - &offset); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - return -1; - } - - jpeg_thumbnail_addr = (void *) ((int) exynos_camera->picture_memory->data + offset); - } - - // Thumbnail - - if (camera_picture_format == V4L2_PIX_FMT_JPEG && jpeg_thumbnail_addr != NULL && jpeg_thumbnail_size >= 0) { - if (exynos_camera->callbacks.request_memory != NULL) { - jpeg_thumbnail_data_memory = - exynos_camera->callbacks.request_memory(-1, - jpeg_thumbnail_size, 1, 0); - if (jpeg_thumbnail_data_memory == NULL) { - ALOGE("%s: thumb memory request failed!", __func__); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - goto error; - } - - memcpy(jpeg_thumbnail_data_memory->data, jpeg_thumbnail_addr, jpeg_thumbnail_size); - } else { - jpeg_fd = api_jpeg_encode_init(); - if (jpeg_fd < 0) { - ALOGE("%s: Failed to init JPEG", __func__); - goto error; - } - - switch (camera_picture_format) { - case V4L2_PIX_FMT_RGB565: - jpeg_in_format = RGB_565; - jpeg_out_format = JPEG_420; - jpeg_in_size = (picture_width * picture_height * 2); - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV12T: - case V4L2_PIX_FMT_YUV420: - jpeg_in_format = YUV_420; - jpeg_out_format = JPEG_420; - jpeg_in_size = (picture_width * picture_height * 1.5); - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUV422P: - default: - jpeg_in_format = YUV_422; - jpeg_out_format = JPEG_422; - jpeg_in_size = (picture_width * picture_height * 2); - break; - } - - memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params)); - - jpeg_enc_params.width = jpeg_thumbnail_width; - jpeg_enc_params.height = jpeg_thumbnail_height; - jpeg_enc_params.in_fmt = jpeg_in_format; - jpeg_enc_params.out_fmt = jpeg_out_format; - - if (jpeg_thumbnail_quality >= 90) - jpeg_enc_params.quality = QUALITY_LEVEL_1; - else if (jpeg_thumbnail_quality >= 80) - jpeg_enc_params.quality = QUALITY_LEVEL_2; - else if (jpeg_thumbnail_quality >= 70) - jpeg_enc_params.quality = QUALITY_LEVEL_3; - else - jpeg_enc_params.quality = QUALITY_LEVEL_4; - - api_jpeg_set_encode_param(&jpeg_enc_params); - - jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size); - if (jpeg_in_buffer == NULL) { - ALOGE("%s: Failed to get JPEG in buffer", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd); - if (jpeg_out_buffer == NULL) { - ALOGE("%s: Failed to get JPEG out buffer", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size); - - jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params); - if (jpeg_result != JPEG_ENCODE_OK) { - ALOGE("%s: Failed to encode JPEG", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - jpeg_out_size = jpeg_enc_params.size; - if (jpeg_out_size <= 0) { - ALOGE("%s: Failed to get JPEG out size", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - if (exynos_camera->callbacks.request_memory != NULL) { - jpeg_thumbnail_data_memory = - exynos_camera->callbacks.request_memory(-1, - jpeg_out_size, 1, 0); - if (jpeg_thumbnail_data_memory == NULL) { - ALOGE("%s: thumbnail memory request failed!", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - memcpy(jpeg_thumbnail_data_memory->data, jpeg_out_buffer, jpeg_out_size); - jpeg_thumbnail_size = jpeg_out_size; - - api_jpeg_encode_deinit(jpeg_fd); - } - - // Picture - - if (camera_picture_format == V4L2_PIX_FMT_JPEG && picture_addr != NULL && picture_size >= 0) { - if (exynos_camera->callbacks.request_memory != NULL) { - picture_data_memory = - exynos_camera->callbacks.request_memory(-1, - picture_size, 1, 0); - if (picture_data_memory == NULL) { - ALOGE("%s: picture memory request failed!", __func__); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - goto error; - } - - memcpy(picture_data_memory->data, picture_addr, picture_size); - } else { - jpeg_fd = api_jpeg_encode_init(); - if (jpeg_fd < 0) { - ALOGE("%s: Failed to init JPEG", __func__); - goto error; - } - - switch (camera_picture_format) { - case V4L2_PIX_FMT_RGB565: - jpeg_in_format = RGB_565; - jpeg_out_format = JPEG_420; - jpeg_in_size = (picture_width * picture_height * 2); - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV12T: - case V4L2_PIX_FMT_YUV420: - jpeg_in_format = YUV_420; - jpeg_out_format = JPEG_420; - jpeg_in_size = (picture_width * picture_height * 1.5); - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUV422P: - default: - jpeg_in_format = YUV_422; - jpeg_out_format = JPEG_422; - jpeg_in_size = (picture_width * picture_height * 2); - break; - } - - memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params)); - - jpeg_enc_params.width = picture_width; - jpeg_enc_params.height = picture_height; - jpeg_enc_params.in_fmt = jpeg_in_format; - jpeg_enc_params.out_fmt = jpeg_out_format; - - if (jpeg_quality >= 90) - jpeg_enc_params.quality = QUALITY_LEVEL_1; - else if (jpeg_quality >= 80) - jpeg_enc_params.quality = QUALITY_LEVEL_2; - else if (jpeg_quality >= 70) - jpeg_enc_params.quality = QUALITY_LEVEL_3; - else - jpeg_enc_params.quality = QUALITY_LEVEL_4; - - api_jpeg_set_encode_param(&jpeg_enc_params); - - jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size); - if (jpeg_in_buffer == NULL) { - ALOGE("%s: Failed to get JPEG in buffer", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd); - if (jpeg_out_buffer == NULL) { - ALOGE("%s: Failed to get JPEG out buffer", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size); - - jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params); - if (jpeg_result != JPEG_ENCODE_OK) { - ALOGE("%s: Failed to encode JPEG", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - jpeg_out_size = jpeg_enc_params.size; - if (jpeg_out_size <= 0) { - ALOGE("%s: Failed to get JPEG out size", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - if (exynos_camera->callbacks.request_memory != NULL) { - picture_data_memory = - exynos_camera->callbacks.request_memory(-1, - jpeg_out_size, 1, 0); - if (picture_data_memory == NULL) { - ALOGE("%s: picture memory request failed!", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - api_jpeg_encode_deinit(jpeg_fd); - goto error; - } - - memcpy(picture_data_memory->data, jpeg_out_buffer, jpeg_out_size); - picture_size = jpeg_out_size; - - api_jpeg_encode_deinit(jpeg_fd); - } - - // EXIF - - memset(&exif_attributes, 0, sizeof(exif_attributes)); - exynos_exif_attributes_create_static(exynos_camera, &exif_attributes); - exynos_exif_attributes_create_params(exynos_camera, &exif_attributes); - - rc = exynos_exif_create(exynos_camera, &exif_attributes, - jpeg_thumbnail_data_memory, jpeg_thumbnail_size, - &exif_data_memory, &exif_size); - if (rc < 0 || exif_data_memory == NULL || exif_size <= 0) { - ALOGE("%s: EXIF create failed!", __func__); - goto error; - } - - data_size = exif_size + picture_size; - - if (exynos_camera->callbacks.request_memory != NULL) { - data_memory = - exynos_camera->callbacks.request_memory(-1, - data_size, 1, 0); - if (data_memory == NULL) { - ALOGE("%s: data memory request failed!", __func__); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - goto error; - } - - // Copy the first two bytes of the JPEG picture - memcpy(data_memory->data, picture_data_memory->data, 2); - - // Copy the EXIF data - memcpy((void *) ((int) data_memory->data + 2), exif_data_memory->data, - exif_size); - - // Copy the JPEG picture - memcpy((void *) ((int) data_memory->data + 2 + exif_size), - (void *) ((int) picture_data_memory->data + 2), picture_size - 2); - - // Callbacks - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_SHUTTER) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify)) - exynos_camera->callbacks.notify(CAMERA_MSG_SHUTTER, 0, 0, - exynos_camera->callbacks.user); - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) && - jpeg_thumbnail_data_memory != NULL) - exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE, - jpeg_thumbnail_data_memory, 0, NULL, exynos_camera->callbacks.user); - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) && - data_memory != NULL) - exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE, - data_memory, 0, NULL, exynos_camera->callbacks.user); - - // Release memory - - if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL) - jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory); - - if (picture_data_memory != NULL && picture_data_memory->release != NULL) - picture_data_memory->release(picture_data_memory); - - if (exif_data_memory != NULL && exif_data_memory->release != NULL) - exif_data_memory->release(exif_data_memory); - - if (data_memory != NULL && data_memory->release != NULL) - data_memory->release(data_memory); - - return 0; - -error: - if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL) - jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory); - - if (picture_data_memory != NULL && picture_data_memory->release != NULL) - picture_data_memory->release(picture_data_memory); - - if (exif_data_memory != NULL && exif_data_memory->release != NULL) - exif_data_memory->release(exif_data_memory); - - if (data_memory != NULL && data_memory->release != NULL) - data_memory->release(data_memory); - - return -1; -} - -void *exynos_camera_picture_thread(void *data) -{ - struct exynos_camera *exynos_camera; - int rc; - int i; - - if (data == NULL) - return NULL; - - exynos_camera = (struct exynos_camera *) data; - - ALOGE("%s: Starting thread", __func__); - exynos_camera->picture_thread_running = 1; - - if (exynos_camera->picture_enabled == 1) { - pthread_mutex_lock(&exynos_camera->picture_mutex); - - rc = exynos_camera_picture(exynos_camera); - if (rc < 0) { - ALOGE("%s: picture failed!", __func__); - exynos_camera->picture_enabled = 0; - } - - if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL) { - exynos_camera->picture_memory->release(exynos_camera->picture_memory); - exynos_camera->picture_memory = NULL; - } - - pthread_mutex_unlock(&exynos_camera->picture_mutex); - } - - exynos_camera->picture_thread_running = 0; - exynos_camera->picture_enabled = 0; - - ALOGE("%s: Exiting thread", __func__); - - return NULL; -} - -int exynos_camera_picture_start(struct exynos_camera *exynos_camera) -{ - pthread_attr_t thread_attr; - - int width, height, format, camera_format; - - int fd; - int rc; - - if (exynos_camera == NULL) - return -EINVAL; - - // Stop preview thread - exynos_camera_preview_stop(exynos_camera); - - width = exynos_camera->picture_width; - height = exynos_camera->picture_height; - format = exynos_camera->picture_format; - camera_format = exynos_camera->camera_picture_format; - - // V4L2 - - if (camera_format == 0) - camera_format = format; - - rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, camera_format); - if (rc < 0) { - ALOGE("%s: enum fmt failed!", __func__); - return -1; - } - - rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, camera_format, V4L2_PIX_FMT_MODE_CAPTURE); - if (rc < 0) { - ALOGE("%s: s fmt failed!", __func__); - return -1; - } - - // Only use 1 buffer - rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, 1); - if (rc < 0) { - ALOGE("%s: reqbufs failed!", __func__); - return -1; - } - - rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, 0); - if (rc < 0) { - ALOGE("%s: querybuf failed!", __func__); - return -1; - } - - exynos_camera->picture_buffer_length = rc; - - if (exynos_camera->callbacks.request_memory != NULL) { - fd = exynos_v4l2_find_fd(exynos_camera, 0); - if (fd < 0) { - ALOGE("%s: Unable to find v4l2 fd", __func__); - return -1; - } - - if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL) - exynos_camera->picture_memory->release(exynos_camera->picture_memory); - - exynos_camera->picture_memory = - exynos_camera->callbacks.request_memory(fd, - exynos_camera->picture_buffer_length, 1, 0); - if (exynos_camera->picture_memory == NULL) { - ALOGE("%s: memory request failed!", __func__); - return -1; - } - } else { - ALOGE("%s: No memory request function!", __func__); - return -1; - } - - rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, 0); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - return -1; - } - - rc = exynos_v4l2_streamon_cap(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: streamon failed!", __func__); - return -1; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_CAPTURE, 0); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - return -1; - } - - // Thread - - if (exynos_camera->picture_thread_running) { - ALOGE("Picture thread is already running!"); - return -1; - } - - pthread_mutex_init(&exynos_camera->picture_mutex, NULL); - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - - exynos_camera->picture_enabled = 1; - - rc = pthread_create(&exynos_camera->picture_thread, &thread_attr, - exynos_camera_picture_thread, (void *) exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to create thread", __func__); - return -1; - } - - return 0; -} - -void exynos_camera_picture_stop(struct exynos_camera *exynos_camera) -{ - int rc; - int i; - - if (exynos_camera == NULL) - return; - - if (!exynos_camera->picture_enabled) { - ALOGE("Picture was already stopped!"); - return; - } - - pthread_mutex_lock(&exynos_camera->picture_mutex); - - // Disable picture to make the thread end - exynos_camera->picture_enabled = 0; - - pthread_mutex_unlock(&exynos_camera->picture_mutex); - - // Wait for the thread to end - for (i = 0; i < 10; i++) { - if (!exynos_camera->picture_thread_running) - break; - - usleep(500); - } - - pthread_mutex_destroy(&exynos_camera->picture_mutex); -} - -// Auto-focus - -void *exynos_camera_auto_focus_thread(void *data) -{ - struct exynos_camera *exynos_camera; - int auto_focus_status = -1; - int auto_focus_result = 0; - int rc; - int i; - - if (data == NULL) - return NULL; - - exynos_camera = (struct exynos_camera *) data; - - ALOGE("%s: Starting thread", __func__); - exynos_camera->auto_focus_thread_running = 1; - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_ON); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - auto_focus_result = 0; - goto thread_exit; - } - - while (exynos_camera->auto_focus_enabled == 1) { - 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: g ctrl failed!", __func__); - auto_focus_result = 0; - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - goto thread_exit; - } - - if (auto_focus_status & M5MO_AF_STATUS_IN_PROGRESS) { - usleep(10000); - } else if (auto_focus_status == M5MO_AF_STATUS_SUCCESS || auto_focus_status == M5MO_AF_STATUS_1ST_SUCCESS) { - auto_focus_result = 1; - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - goto thread_exit; - } else { - auto_focus_result = 0; - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - goto thread_exit; - } - - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - } - -thread_exit: - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF); - if (rc < 0) - ALOGE("%s: s ctrl failed!", __func__); - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify)) - exynos_camera->callbacks.notify(CAMERA_MSG_FOCUS, - (int32_t) auto_focus_result, 0, exynos_camera->callbacks.user); - - exynos_camera->auto_focus_thread_running = 0; - exynos_camera->auto_focus_enabled = 0; - - ALOGE("%s: Exiting thread", __func__); - - return NULL; -} - -int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera) -{ - pthread_attr_t thread_attr; - int rc; - - if (exynos_camera == NULL) - return -EINVAL; - - // Thread - - if (exynos_camera->auto_focus_thread_running) { - ALOGE("Auto-focus thread is already running!"); - return -1; - } - - pthread_mutex_init(&exynos_camera->auto_focus_mutex, NULL); - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - - exynos_camera->auto_focus_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__); - return -1; - } - - return 0; -} - -void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera) -{ - int rc; - int i; - - if (exynos_camera == NULL) - return; - - if (!exynos_camera->auto_focus_enabled) { - ALOGE("Auto-focus was already stopped!"); - return; - } - - pthread_mutex_lock(&exynos_camera->auto_focus_mutex); - - // Disable auto-focus to make the thread end - exynos_camera->auto_focus_enabled = 0; - - pthread_mutex_unlock(&exynos_camera->auto_focus_mutex); - - // Wait for the thread to end - for (i = 0; i < 10; i++) { - if (!exynos_camera->auto_focus_thread_running) - break; - - usleep(500); - } - - pthread_mutex_destroy(&exynos_camera->auto_focus_mutex); -} - -// Preview - -int exynos_camera_preview(struct exynos_camera *exynos_camera) -{ - buffer_handle_t *buffer; - int stride; - - int width, height; - float format_bpp; - - char *preview_format_string; - int frame_size, offset; - void *preview_data; - void *window_data; - - unsigned int recording_y_addr; - unsigned int recording_cbcr_addr; - nsecs_t timestamp; - struct exynos_camera_addrs *addrs; - struct timespec ts; - - int index; - int rc; - int i; - - if (exynos_camera == NULL || exynos_camera->preview_memory == NULL || - exynos_camera->preview_window == NULL) - return -EINVAL; - - timestamp = systemTime(1); - - // V4L2 - - rc = exynos_v4l2_poll(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: poll failed!", __func__); - return -1; - } else if (rc == 0) { - ALOGE("%s: poll timeout!", __func__); - return -1; - } - - index = exynos_v4l2_dqbuf_cap(exynos_camera, 0); - if (index < 0 || index >= exynos_camera->preview_buffers_count) { - ALOGE("%s: dqbuf failed!", __func__); - return -1; - } - - rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, index); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - return -1; - } - - // Preview window - - width = exynos_camera->preview_width; - height = exynos_camera->preview_height; - format_bpp = exynos_camera->preview_format_bpp; - - exynos_camera->preview_window->dequeue_buffer(exynos_camera->preview_window, - &buffer, &stride); - exynos_camera->gralloc->lock(exynos_camera->gralloc, *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, - 0, 0, width, height, &window_data); - - if (window_data == NULL) { - ALOGE("%s: gralloc lock failed!", __func__); - return -1; - } - - frame_size = exynos_camera->preview_frame_size; - offset = index * frame_size; - - preview_data = (void *) ((int) exynos_camera->preview_memory->data + offset); - memcpy(window_data, preview_data, frame_size); - - exynos_camera->gralloc->unlock(exynos_camera->gralloc, *buffer); - exynos_camera->preview_window->enqueue_buffer(exynos_camera->preview_window, - buffer); - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_PREVIEW_FRAME) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) { - exynos_camera->callbacks.data(CAMERA_MSG_PREVIEW_FRAME, - exynos_camera->preview_memory, index, NULL, exynos_camera->callbacks.user); - } - - // Recording - - if (exynos_camera->recording_enabled && exynos_camera->recording_memory != NULL) { - pthread_mutex_lock(&exynos_camera->recording_mutex); - - // V4L2 - - rc = exynos_v4l2_poll(exynos_camera, 2); - if (rc < 0) { - ALOGE("%s: poll failed!", __func__); - goto error_recording; - } else if (rc == 0) { - ALOGE("%s: poll timeout!", __func__); - goto error_recording; - } - - index = exynos_v4l2_dqbuf_cap(exynos_camera, 2); - if (index < 0) { - ALOGE("%s: dqbuf failed!", __func__); - goto error_recording; - } - - recording_y_addr = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_PADDR_Y, index); - if (recording_y_addr == 0xffffffff) { - ALOGE("%s: s ctrl failed!", __func__); - goto error_recording; - } - - recording_cbcr_addr = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_PADDR_CBCR, index); - if (recording_cbcr_addr == 0xffffffff) { - ALOGE("%s: s ctrl failed!", __func__); - goto error_recording; - } - - addrs = (struct exynos_camera_addrs *) exynos_camera->recording_memory->data; - - addrs[index].type = 0; // kMetadataBufferTypeCameraSource - addrs[index].y = recording_y_addr; - addrs[index].cbcr = recording_cbcr_addr; - addrs[index].index = index; - addrs[index].reserved = 0; - - pthread_mutex_unlock(&exynos_camera->recording_mutex); - - if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_VIDEO_FRAME) && EXYNOS_CAMERA_CALLBACK_DEFINED(data_timestamp)) { - exynos_camera->callbacks.data_timestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, - exynos_camera->recording_memory, index, exynos_camera->callbacks.user); - } else { - rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, index); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - return -1; - } - } - } - - return 0; - -error_recording: - pthread_mutex_lock(&exynos_camera->recording_mutex); - - return -1; -} - -void *exynos_camera_preview_thread(void *data) -{ - struct exynos_camera *exynos_camera; - int rc; - - if (data == NULL) - return NULL; - - exynos_camera = (struct exynos_camera *) data; - - ALOGE("%s: Starting thread", __func__); - exynos_camera->preview_thread_running = 1; - - if (exynos_camera->preview_window == NULL) { - // Lock preview lock mutex - pthread_mutex_lock(&exynos_camera->preview_lock_mutex); - } - - while (exynos_camera->preview_enabled == 1) { - pthread_mutex_lock(&exynos_camera->preview_mutex); - - rc = exynos_camera_preview(exynos_camera); - if (rc < 0) { - ALOGE("%s: preview failed!", __func__); - exynos_camera->preview_enabled = 0; - } - - pthread_mutex_unlock(&exynos_camera->preview_mutex); - } - - exynos_camera->preview_thread_running = 0; - ALOGE("%s: Exiting thread", __func__); - - return NULL; -} - -int exynos_camera_preview_start(struct exynos_camera *exynos_camera) -{ - struct v4l2_streamparm streamparm; - int width, height, format; - float format_bpp; - int fps, frame_size; - int fd; - - pthread_attr_t thread_attr; - - int rc; - int i; - - if (exynos_camera == NULL) - return -EINVAL; - - if (exynos_camera->preview_enabled) { - ALOGE("Preview was already started!"); - return 0; - } - - // V4L2 - - format = exynos_camera->preview_format; - - rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, format); - if (rc < 0) { - ALOGE("%s: enum fmt failed!", __func__); - return -1; - } - - width = exynos_camera->preview_width; - height = exynos_camera->preview_height; - format_bpp = exynos_camera->preview_format_bpp; - - rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, format, V4L2_PIX_FMT_MODE_PREVIEW); - if (rc < 0) { - ALOGE("%s: s fmt failed!", __func__); - return -1; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CACHEABLE, 1); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - return -1; - } - - for (i = EXYNOS_CAMERA_MAX_BUFFERS_COUNT; i >= EXYNOS_CAMERA_MIN_BUFFERS_COUNT; i--) { - rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, i); - if (rc >= 0) - break; - } - - if (rc < 0) { - ALOGE("%s: reqbufs failed!", __func__); - return -1; - } - - exynos_camera->preview_buffers_count = rc; - ALOGD("Found %d preview buffers available!", exynos_camera->preview_buffers_count); - - fps = exynos_camera->preview_fps; - memset(&streamparm, 0, sizeof(streamparm)); - streamparm.parm.capture.timeperframe.numerator = 1; - streamparm.parm.capture.timeperframe.denominator = fps; - - rc = exynos_v4l2_s_parm_cap(exynos_camera, 0, &streamparm); - if (rc < 0) { - ALOGE("%s: s parm failed!", __func__); - return -1; - } - - frame_size = (int) ((float) width * (float) height * format_bpp); - for (i = 0; i < exynos_camera->preview_buffers_count; i++) { - rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, i); - if (rc < 0) { - ALOGE("%s: querybuf failed!", __func__); - return -1; - } - - if (rc < frame_size) { - ALOGE("%s: problematic frame size: %d/%d", __func__, rc, frame_size); - return -1; - } - } - - frame_size = rc; - exynos_camera->preview_frame_size = frame_size; - - if (exynos_camera->callbacks.request_memory != NULL) { - fd = exynos_v4l2_find_fd(exynos_camera, 0); - if (fd < 0) { - ALOGE("%s: Unable to find v4l2 fd", __func__); - return -1; - } - - if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) - exynos_camera->preview_memory->release(exynos_camera->preview_memory); - - exynos_camera->preview_memory = - exynos_camera->callbacks.request_memory(fd, - frame_size, exynos_camera->preview_buffers_count, 0); - if (exynos_camera->preview_memory == NULL) { - ALOGE("%s: memory request failed!", __func__); - return -1; - } - } else { - ALOGE("%s: No memory request function!", __func__); - return -1; - } - - for (i = 0; i < exynos_camera->preview_buffers_count; i++) { - rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, i); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - return -1; - } - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_ROTATION, - exynos_camera->camera_rotation); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - return -1; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_HFLIP, - exynos_camera->camera_hflip); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - return -1; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_VFLIP, - exynos_camera->camera_vflip); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - return -1; - } - - rc = exynos_v4l2_streamon_cap(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: streamon failed!", __func__); - return -1; - } - - // Thread - - pthread_mutex_init(&exynos_camera->preview_mutex, NULL); - pthread_mutex_init(&exynos_camera->preview_lock_mutex, NULL); - - // Lock preview lock - pthread_mutex_lock(&exynos_camera->preview_lock_mutex); - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - - exynos_camera->preview_enabled = 1; - - rc = pthread_create(&exynos_camera->preview_thread, &thread_attr, - exynos_camera_preview_thread, (void *) exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to create thread", __func__); - return -1; - } - - return 0; -} - -void exynos_camera_preview_stop(struct exynos_camera *exynos_camera) -{ - int rc; - int i; - - if (exynos_camera == NULL) - return; - - if (!exynos_camera->preview_enabled) { - ALOGE("Preview was already stopped!"); - return; - } - - exynos_camera->preview_enabled = 0; - - // Unlock preview lock - pthread_mutex_unlock(&exynos_camera->preview_lock_mutex); - - pthread_mutex_lock(&exynos_camera->preview_mutex); - - // Wait for the thread to end - for (i = 0; i < 10; i++) { - if (!exynos_camera->preview_thread_running) - break; - - usleep(1000); - } - - rc = exynos_v4l2_streamoff_cap(exynos_camera, 0); - if (rc < 0) { - ALOGE("%s: streamoff failed!", __func__); - } - - exynos_camera->preview_params_set = 0; - - if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) { - exynos_camera->preview_memory->release(exynos_camera->preview_memory); - exynos_camera->preview_memory = NULL; - } - - exynos_camera->preview_window = NULL; - - pthread_mutex_unlock(&exynos_camera->preview_mutex); - - pthread_mutex_destroy(&exynos_camera->preview_lock_mutex); - pthread_mutex_destroy(&exynos_camera->preview_mutex); -} - -// Recording - -void exynos_camera_recording_frame_release(struct exynos_camera *exynos_camera, void *data) -{ - struct exynos_camera_addrs *addrs; - int rc; - - if (exynos_camera == NULL || data == NULL) - return; - - addrs = (struct exynos_camera_addrs *) data; - if (addrs->index >= (unsigned int) exynos_camera->recording_buffers_count) - return; - - pthread_mutex_lock(&exynos_camera->recording_mutex); - - rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, addrs->index); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - goto error; - } - -error: - pthread_mutex_unlock(&exynos_camera->recording_mutex); -} - -int exynos_camera_recording_start(struct exynos_camera *exynos_camera) -{ - int width, height, format; - int fd; - - int rc; - int i; - - if (exynos_camera == NULL) - return -EINVAL; - - if (exynos_camera->recording_enabled) { - ALOGE("Recording was already started!"); - return 0; - } - - pthread_mutex_lock(&exynos_camera->preview_mutex); - - // V4L2 - - format = exynos_camera->recording_format; - - rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 2, format); - if (rc < 0) { - ALOGE("%s: enum fmt failed!", __func__); - goto error; - } - - width = exynos_camera->recording_width; - height = exynos_camera->recording_height; - - rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 2, width, height, format, V4L2_PIX_FMT_MODE_CAPTURE); - if (rc < 0) { - ALOGE("%s: s fmt failed!", __func__); - goto error; - } - - for (i = EXYNOS_CAMERA_MAX_BUFFERS_COUNT; i >= EXYNOS_CAMERA_MIN_BUFFERS_COUNT; i--) { - rc = exynos_v4l2_reqbufs_cap(exynos_camera, 2, i); - if (rc >= 0) - break; - } - - if (rc < 0) { - ALOGE("%s: reqbufs failed!", __func__); - goto error; - } - - exynos_camera->recording_buffers_count = rc; - ALOGD("Found %d recording buffers available!", exynos_camera->recording_buffers_count); - - for (i = 0; i < exynos_camera->recording_buffers_count; i++) { - rc = exynos_v4l2_querybuf_cap(exynos_camera, 2, i); - if (rc < 0) { - ALOGE("%s: querybuf failed!", __func__); - goto error; - } - } - - if (exynos_camera->callbacks.request_memory != NULL) { - if (exynos_camera->recording_memory != NULL && exynos_camera->recording_memory->release != NULL) - exynos_camera->recording_memory->release(exynos_camera->recording_memory); - - exynos_camera->recording_memory = - exynos_camera->callbacks.request_memory(-1, sizeof(struct exynos_camera_addrs), - exynos_camera->recording_buffers_count, 0); - if (exynos_camera->recording_memory == NULL) { - ALOGE("%s: memory request failed!", __func__); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - goto error; - } - - for (i = 0; i < exynos_camera->recording_buffers_count; i++) { - rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, i); - if (rc < 0) { - ALOGE("%s: qbuf failed!", __func__); - goto error; - } - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_ROTATION, - exynos_camera->camera_rotation); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - goto error; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_HFLIP, - exynos_camera->camera_hflip); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - goto error; - } - - rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_VFLIP, - exynos_camera->camera_vflip); - if (rc < 0) { - ALOGE("%s: s ctrl failed!", __func__); - goto error; - } - - rc = exynos_v4l2_streamon_cap(exynos_camera, 2); - if (rc < 0) { - ALOGE("%s: streamon failed!", __func__); - goto error; - } - - pthread_mutex_init(&exynos_camera->recording_mutex, NULL); - - exynos_camera->recording_enabled = 1; - - pthread_mutex_unlock(&exynos_camera->preview_mutex); - - return 0; -error: - pthread_mutex_unlock(&exynos_camera->preview_mutex); - - return -1; -} - -void exynos_camera_recording_stop(struct exynos_camera *exynos_camera) -{ - int rc; - - if (exynos_camera == NULL) - return; - - if (!exynos_camera->recording_enabled) { - ALOGE("Recording was already stopped!"); - return; - } - - exynos_camera->recording_enabled = 0; - - pthread_mutex_lock(&exynos_camera->preview_mutex); - - rc = exynos_v4l2_streamoff_cap(exynos_camera, 2); - if (rc < 0) { - ALOGE("%s: streamoff failed!", __func__); - } - - if (exynos_camera->recording_memory != NULL && exynos_camera->recording_memory->release != NULL) { - exynos_camera->recording_memory->release(exynos_camera->recording_memory); - exynos_camera->recording_memory = NULL; - } - - pthread_mutex_unlock(&exynos_camera->preview_mutex); - - pthread_mutex_destroy(&exynos_camera->recording_mutex); -} - -/* - * Exynos Camera OPS - */ - -int exynos_camera_set_preview_window(struct camera_device *dev, - struct preview_stream_ops *w) -{ - struct exynos_camera *exynos_camera; - - int width, height, format, hal_format; - - buffer_handle_t *buffer; - int stride; - void *addr = NULL; - - int rc; - - ALOGD("%s(%p, %p)", __func__, dev, w); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - if (w == NULL) - return 0; - - exynos_camera->preview_window = w; - - if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL) - return -EINVAL; - - if (exynos_camera->preview_buffers_count <= 0) { - ALOGE("%s: Invalid preview buffers count", __func__); - exynos_camera->preview_buffers_count = EXYNOS_CAMERA_MAX_BUFFERS_COUNT; - } - - rc = w->set_buffer_count(w, exynos_camera->preview_buffers_count); - if (rc) { - ALOGE("%s: Unable to set buffer count (%d)", __func__, - exynos_camera->preview_buffers_count); - return -1; - } - - rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN); - if (rc) { - ALOGE("%s: Unable to set usage", __func__); - return -1; - } - - width = exynos_camera->preview_width; - height = exynos_camera->preview_height; - format = exynos_camera->preview_format; - - switch (format) { - case V4L2_PIX_FMT_NV21: - hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; - break; - case V4L2_PIX_FMT_YUV420: - hal_format = HAL_PIXEL_FORMAT_YV12; - break; - case V4L2_PIX_FMT_RGB565: - hal_format = HAL_PIXEL_FORMAT_RGB_565; - break; - case V4L2_PIX_FMT_RGB32: - hal_format = HAL_PIXEL_FORMAT_RGBX_8888; - break; - default: - hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; - break; - } - - rc = w->set_buffers_geometry(w, width, height, hal_format); - if (rc) { - ALOGE("%s: Unable to set buffers geometry", __func__); - return -1; - } - - // Unlock preview lock - pthread_mutex_unlock(&exynos_camera->preview_lock_mutex); - - return 0; -} - -void exynos_camera_set_callbacks(struct camera_device *dev, - camera_notify_callback notify_cb, - camera_data_callback data_cb, - camera_data_timestamp_callback data_cb_timestamp, - camera_request_memory get_memory, - void *user) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p, %p)", __func__, dev, user); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera->callbacks.notify = notify_cb; - exynos_camera->callbacks.data = data_cb; - exynos_camera->callbacks.data_timestamp = data_cb_timestamp; - exynos_camera->callbacks.request_memory = get_memory; - exynos_camera->callbacks.user = user; -} - -void exynos_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p, %d)", __func__, dev, msg_type); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera->messages_enabled |= msg_type; -} - -void exynos_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p, %d)", __func__, dev, msg_type); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera->messages_enabled &= ~msg_type; -} - -int exynos_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p, %d)", __func__, dev, msg_type); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera->messages_enabled & msg_type; -} - -int exynos_camera_start_preview(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera_preview_start(exynos_camera); -} - -void exynos_camera_stop_preview(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera_preview_stop(exynos_camera); -} - -int exynos_camera_preview_enabled(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera->preview_enabled; -} - -int exynos_camera_store_meta_data_in_buffers(struct camera_device *dev, - int enable) -{ - ALOGD("%s(%p, %d)", __func__, dev, enable); - - if (!enable) { - ALOGE("%s: Cannot disable meta-data in buffers!", __func__); - return -1; - } - - return 0; -} - -int exynos_camera_start_recording(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera_recording_start(exynos_camera); -} - -void exynos_camera_stop_recording(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera_recording_stop(exynos_camera); -} - -int exynos_camera_recording_enabled(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera->recording_enabled; -} - -void exynos_camera_release_recording_frame(struct camera_device *dev, - const void *opaque) -{ - struct exynos_camera *exynos_camera; - - ALOGV("%s(%p, %p)", __func__, dev, opaque); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera_recording_frame_release(exynos_camera, (void *) opaque); -} - -int exynos_camera_auto_focus(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera_auto_focus_start(exynos_camera); -} - -int exynos_camera_cancel_auto_focus(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera_auto_focus_stop(exynos_camera); - - return 0; -} - -int exynos_camera_take_picture(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - return exynos_camera_picture_start(exynos_camera); -} - -int exynos_camera_cancel_picture(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - exynos_camera_picture_stop(exynos_camera); - - return 0; -} - -int exynos_camera_set_parameters(struct camera_device *dev, - const char *params) -{ - struct exynos_camera *exynos_camera; - int rc; - - ALOGD("%s(%p, %s)", __func__, dev, params); - - if (dev == NULL || dev->priv == NULL || params == NULL) - return -EINVAL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - rc = exynos_params_string_set(exynos_camera, (char *) params); - if (rc < 0) { - ALOGE("%s: Unable to set params string", __func__); - return -1; - } - - rc = exynos_camera_params_apply(exynos_camera); - if (rc < 0) { - ALOGE("%s: Unable to apply params", __func__); - return -1; - } - - return 0; -} - -char *exynos_camera_get_parameters(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - char *params; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return NULL; - - exynos_camera = (struct exynos_camera *) dev->priv; - - params = exynos_params_string_get(exynos_camera); - if (params == NULL) { - ALOGE("%s: Couldn't find any param", __func__); - return strdup(""); - } - - return params; -} - -void exynos_camera_put_parameters(struct camera_device *dev, char *params) -{ - ALOGD("%s(%p)", __func__, dev); - - if (params != NULL) - free(params); -} - -int exynos_camera_send_command(struct camera_device *dev, - int32_t cmd, int32_t arg1, int32_t arg2) -{ - ALOGD("%s(%p, %d, %d, %d)", __func__, dev, cmd, arg1, arg2); - - return 0; -} - -void exynos_camera_release(struct camera_device *dev) -{ - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, dev); - - if (dev == NULL || dev->priv == NULL) - return; - - exynos_camera = (struct exynos_camera *) dev->priv; - - if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) { - exynos_camera->preview_memory->release(exynos_camera->preview_memory); - exynos_camera->preview_memory = NULL; - } - - if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL) { - exynos_camera->picture_memory->release(exynos_camera->picture_memory); - exynos_camera->picture_memory = NULL; - } - - exynos_camera_deinit(exynos_camera); -} - -int exynos_camera_dump(struct camera_device *dev, int fd) -{ - ALOGD("%s(%p, %d)", __func__, dev, fd); - - return 0; -} - -/* - * Interface - */ - -struct camera_device_ops exynos_camera_ops = { - .set_preview_window = exynos_camera_set_preview_window, - .set_callbacks = exynos_camera_set_callbacks, - .enable_msg_type = exynos_camera_enable_msg_type, - .disable_msg_type = exynos_camera_disable_msg_type, - .msg_type_enabled = exynos_camera_msg_type_enabled, - .start_preview = exynos_camera_start_preview, - .stop_preview = exynos_camera_stop_preview, - .preview_enabled = exynos_camera_preview_enabled, - .store_meta_data_in_buffers = exynos_camera_store_meta_data_in_buffers, - .start_recording = exynos_camera_start_recording, - .stop_recording = exynos_camera_stop_recording, - .recording_enabled = exynos_camera_recording_enabled, - .release_recording_frame = exynos_camera_release_recording_frame, - .auto_focus = exynos_camera_auto_focus, - .cancel_auto_focus = exynos_camera_cancel_auto_focus, - .take_picture = exynos_camera_take_picture, - .cancel_picture = exynos_camera_cancel_picture, - .set_parameters = exynos_camera_set_parameters, - .get_parameters = exynos_camera_get_parameters, - .put_parameters = exynos_camera_put_parameters, - .send_command = exynos_camera_send_command, - .release = exynos_camera_release, - .dump = exynos_camera_dump, -}; - -int exynos_camera_close(hw_device_t *device) -{ - struct camera_device *camera_device; - struct exynos_camera *exynos_camera; - - ALOGD("%s(%p)", __func__, device); - - if (device == NULL) - return -EINVAL; - - camera_device = (struct camera_device *) device; - - if (camera_device->priv != NULL) { - free(camera_device->priv); - } - - free(camera_device); - - return 0; -} - -int exynos_camera_open(const struct hw_module_t* module, const char *camera_id, - struct hw_device_t** device) -{ - struct camera_device *camera_device = NULL; - struct exynos_camera *exynos_camera = NULL; - int id; - int rc; - - ALOGD("%s(%p, %s, %p)", __func__, module, camera_id, device); - - if (module == NULL || camera_id == NULL || device == NULL) - return -EINVAL; - - id = atoi(camera_id); - if (id < 0) - return -EINVAL; - - exynos_camera = calloc(1, sizeof(struct exynos_camera)); - exynos_camera->config = exynos_camera_config; - - if (exynos_camera->config->presets_count > EXYNOS_CAMERA_MAX_PRESETS_COUNT || - exynos_camera->config->v4l2_nodes_count > EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT) - goto error_preset; - - if (id >= exynos_camera->config->presets_count) - goto error_preset; - - rc = exynos_camera_init(exynos_camera, id); - if (rc < 0) { - ALOGE("%s: Unable to init camera", __func__); - goto error; - } - - camera_device = calloc(1, sizeof(struct camera_device)); - camera_device->common.tag = HARDWARE_DEVICE_TAG; - camera_device->common.version = 0; - camera_device->common.module = (struct hw_module_t *) module; - camera_device->common.close = exynos_camera_close; - - camera_device->ops = &exynos_camera_ops; - camera_device->priv = exynos_camera; - - *device = (struct hw_device_t *) &(camera_device->common); - - return 0; - -error: - exynos_camera_deinit(exynos_camera); - -error_device: - if (camera_device != NULL) - free(camera_device); - -error_preset: - if (exynos_camera != NULL) - free(exynos_camera); - - return -1; -} - -int exynos_camera_get_number_of_cameras(void) -{ - ALOGD("%s()", __func__); - - if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) { - ALOGE("%s: Unable to find proper camera config", __func__); - return -1; - } - - return exynos_camera_config->presets_count; -} - -int exynos_camera_get_camera_info(int id, struct camera_info *info) -{ - ALOGD("%s(%d, %p)", __func__, id, info); - - if (id < 0 || info == NULL) - return -EINVAL; - - if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) { - ALOGE("%s: Unable to find proper camera config", __func__); - return -1; - } - - if (id >= exynos_camera_config->presets_count) - return -EINVAL; - - ALOGD("Selected camera: %s", exynos_camera_config->presets[id].name); - - info->facing = exynos_camera_config->presets[id].facing; - info->orientation = exynos_camera_config->presets[id].orientation; - - return 0; -} - -struct hw_module_methods_t exynos_camera_module_methods = { - .open = exynos_camera_open, -}; - -struct camera_module HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .hal_api_version = HARDWARE_HAL_API_VERSION, - .module_api_version = CAMERA_MODULE_API_VERSION_1_0, - .id = CAMERA_HARDWARE_MODULE_ID, - .name = "Exynos Camera", - .author = "Paul Kocialkowski", - .methods = &exynos_camera_module_methods, - }, - .get_number_of_cameras = exynos_camera_get_number_of_cameras, - .get_camera_info = exynos_camera_get_camera_info, -}; diff --git a/camera/exynos_exif.c b/camera/exynos_exif.c deleted file mode 100644 index 80f3c8f..0000000 --- a/camera/exynos_exif.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright (C) 2013 Paul Kocialkowski - * - * Based on crespo libcamera and exynos4 hal libcamera: - * Copyright 2008, The Android Open Source Project, Apache License 2.0 - * Copyright 2010, Samsung Electronics Co. LTD, Apache License 2.0 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define LOG_TAG "exynos_camera" -#include -#include - -#include "exynos_camera.h" - -int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera, - exif_attribute_t *exif_attributes) -{ - unsigned char gps_version[] = { 0x02, 0x02, 0x00, 0x00 }; - char property[PROPERTY_VALUE_MAX]; - uint32_t av; - - if (exynos_camera == NULL || exif_attributes == NULL) - return -EINVAL; - - // Device - property_get("ro.product.brand", property, EXIF_DEF_MAKER); - strncpy((char *) exif_attributes->maker, property, - sizeof(exif_attributes->maker) - 1); - exif_attributes->maker[sizeof(exif_attributes->maker) - 1] = '\0'; - - property_get("ro.product.model", property, EXIF_DEF_MODEL); - strncpy((char *) exif_attributes->model, property, - sizeof(exif_attributes->model) - 1); - exif_attributes->model[sizeof(exif_attributes->model) - 1] = '\0'; - - property_get("ro.build.id", property, EXIF_DEF_SOFTWARE); - strncpy((char *) exif_attributes->software, property, - sizeof(exif_attributes->software) - 1); - exif_attributes->software[sizeof(exif_attributes->software) - 1] = '\0'; - - exif_attributes->ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING; - - exif_attributes->fnumber.num = EXIF_DEF_FNUMBER_NUM; - exif_attributes->fnumber.den = EXIF_DEF_FNUMBER_DEN; - - exif_attributes->exposure_program = EXIF_DEF_EXPOSURE_PROGRAM; - - memcpy(exif_attributes->exif_version, EXIF_DEF_EXIF_VERSION, - sizeof(exif_attributes->exif_version)); - - av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num / - exif_attributes->fnumber.den); - exif_attributes->aperture.num = av; - exif_attributes->aperture.den = EXIF_DEF_APEX_DEN; - exif_attributes->max_aperture.num = av; - exif_attributes->max_aperture.den = EXIF_DEF_APEX_DEN; - - strcpy((char *) exif_attributes->user_comment, EXIF_DEF_USERCOMMENTS); - exif_attributes->color_space = EXIF_DEF_COLOR_SPACE; - exif_attributes->exposure_mode = EXIF_DEF_EXPOSURE_MODE; - - // GPS version - memcpy(exif_attributes->gps_version_id, gps_version, sizeof(gps_version)); - - exif_attributes->compression_scheme = EXIF_DEF_COMPRESSION; - exif_attributes->x_resolution.num = EXIF_DEF_RESOLUTION_NUM; - exif_attributes->x_resolution.den = EXIF_DEF_RESOLUTION_DEN; - exif_attributes->y_resolution.num = EXIF_DEF_RESOLUTION_NUM; - exif_attributes->y_resolution.den = EXIF_DEF_RESOLUTION_DEN; - exif_attributes->resolution_unit = EXIF_DEF_RESOLUTION_UNIT; - - return 0; -} - -int exynos_exif_attributes_create_gps(struct exynos_camera *exynos_camera, - exif_attribute_t *exif_attributes) -{ - float gps_latitude_float, gps_longitude_float, gps_altitude_float; - int gps_timestamp_int; - char *gps_processing_method_string; - long gps_latitude, gps_longitude; - long gps_altitude, gps_timestamp; - double gps_latitude_abs, gps_longitude_abs, gps_altitude_abs; - - struct tm time_info; - - if (exynos_camera == NULL || exif_attributes == NULL) - return -EINVAL; - - gps_latitude_float = exynos_param_float_get(exynos_camera, "gps-latitude"); - gps_longitude_float = exynos_param_float_get(exynos_camera, "gps-longitude"); - gps_altitude_float = exynos_param_float_get(exynos_camera, "gps-altitude"); - if (gps_altitude_float == -1) - gps_altitude_float = (float) exynos_param_int_get(exynos_camera, "gps-altitude"); - gps_timestamp_int = exynos_param_int_get(exynos_camera, "gps-timestamp"); - gps_processing_method_string = exynos_param_string_get(exynos_camera, "gps-processing-method"); - - if (gps_latitude_float == -1 || gps_longitude_float == -1 || - gps_altitude_float == -1 || gps_timestamp_int <= 0 || - gps_processing_method_string == NULL) { - exif_attributes->enableGps = false; - return 0; - } - - gps_latitude = (long) (gps_latitude_float * 10000000) / 1; - gps_longitude = (long) (gps_longitude_float * 10000000) / 1; - gps_altitude = (long) (gps_altitude_float * 100) / 1; - gps_timestamp = (long) gps_timestamp_int; - - if (gps_latitude == 0 || gps_longitude == 0) { - exif_attributes->enableGps = false; - return 0; - } - - if (gps_latitude > 0) - strcpy((char *) exif_attributes->gps_latitude_ref, "N"); - else - strcpy((char *) exif_attributes->gps_latitude_ref, "S"); - - if (gps_longitude > 0) - strcpy((char *) exif_attributes->gps_longitude_ref, "E"); - else - strcpy((char *) exif_attributes->gps_longitude_ref, "W"); - - if (gps_altitude > 0) - exif_attributes->gps_altitude_ref = 0; - else - exif_attributes->gps_altitude_ref = 1; - - - gps_latitude_abs = fabs(gps_latitude); - gps_longitude_abs = fabs(gps_longitude); - gps_altitude_abs = fabs(gps_altitude); - - exif_attributes->gps_latitude[0].num = (uint32_t) gps_latitude_abs; - exif_attributes->gps_latitude[0].den = 10000000; - exif_attributes->gps_latitude[1].num = 0; - exif_attributes->gps_latitude[1].den = 1; - exif_attributes->gps_latitude[2].num = 0; - exif_attributes->gps_latitude[2].den = 1; - - exif_attributes->gps_longitude[0].num = (uint32_t) gps_longitude_abs; - exif_attributes->gps_longitude[0].den = 10000000; - exif_attributes->gps_longitude[1].num = 0; - exif_attributes->gps_longitude[1].den = 1; - exif_attributes->gps_longitude[2].num = 0; - exif_attributes->gps_longitude[2].den = 1; - - exif_attributes->gps_altitude.num = (uint32_t) gps_altitude_abs; - exif_attributes->gps_altitude.den = 100; - - gmtime_r(&gps_timestamp, &time_info); - - exif_attributes->gps_timestamp[0].num = time_info.tm_hour; - exif_attributes->gps_timestamp[0].den = 1; - exif_attributes->gps_timestamp[1].num = time_info.tm_min; - exif_attributes->gps_timestamp[1].den = 1; - exif_attributes->gps_timestamp[2].num = time_info.tm_sec; - exif_attributes->gps_timestamp[2].den = 1; - snprintf((char *) exif_attributes->gps_datestamp, sizeof(exif_attributes->gps_datestamp), - "%04d:%02d:%02d", time_info.tm_year + 1900, time_info.tm_mon + 1, time_info.tm_mday); - - exif_attributes->enableGps = true; - - return 0; -} - -int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera, - exif_attribute_t *exif_attributes) -{ - uint32_t av, tv, bv, sv, ev; - time_t time_data; - struct tm *time_info; - int rotation; - int shutter_speed; - int exposure_time; - int iso_speed; - int exposure; - int flash_results; - - int rc; - - if (exynos_camera == NULL || exif_attributes == NULL) - return -EINVAL; - - // Picture size - exif_attributes->width = exynos_camera->picture_width; - exif_attributes->height = exynos_camera->picture_height; - - // Thumbnail - exif_attributes->widthThumb = exynos_camera->jpeg_thumbnail_width; - exif_attributes->heightThumb = exynos_camera->jpeg_thumbnail_height; - exif_attributes->enableThumb = true; - - // Orientation - rotation = exynos_param_int_get(exynos_camera, "rotation"); - switch (rotation) { - case 90: - exif_attributes->orientation = EXIF_ORIENTATION_90; - break; - case 180: - exif_attributes->orientation = EXIF_ORIENTATION_180; - break; - case 270: - exif_attributes->orientation = EXIF_ORIENTATION_270; - break; - case 0: - default: - exif_attributes->orientation = EXIF_ORIENTATION_UP; - break; - } - - // Time - time(&time_data); - time_info = localtime(&time_data); - strftime((char *) exif_attributes->date_time, sizeof(exif_attributes->date_time), - "%Y:%m:%d %H:%M:%S", time_info); - - exif_attributes->focal_length.num = exynos_camera->camera_focal_length; - exif_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: g ctrl failed!", __func__); - - exif_attributes->shutter_speed.num = shutter_speed; - exif_attributes->shutter_speed.den = 100; - - exif_attributes->exposure_time.num = 1; - exif_attributes->exposure_time.den = APEX_SHUTTER_TO_EXPOSURE(shutter_speed); - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO, - &iso_speed); - if (rc < 0) - ALOGE("%s: g ctrl failed!", __func__); - - exif_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: g ctrl failed!", __func__); - - exif_attributes->flash = flash_results; - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_BV, - (int *) &bv); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - goto bv_static; - } - - rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EBV, - (int *) &ev); - if (rc < 0) { - ALOGE("%s: g ctrl failed!", __func__); - goto bv_static; - } - - goto bv_ioctl; - -bv_static: - exposure = exynos_param_int_get(exynos_camera, "exposure-compensation"); - if (exposure < 0) - exposure = EV_DEFAULT; - - av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num / - exif_attributes->fnumber.den); - tv = APEX_EXPOSURE_TO_SHUTTER((double) exif_attributes->exposure_time.num / - exif_attributes->exposure_time.den); - sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed); - bv = av + tv - sv; - ev = exposure - EV_DEFAULT; - -bv_ioctl: - exif_attributes->brightness.num = bv; - exif_attributes->brightness.den = EXIF_DEF_APEX_DEN; - - if (exynos_camera->scene_mode == SCENE_MODE_BEACH_SNOW) { - exif_attributes->exposure_bias.num = EXIF_DEF_APEX_DEN; - exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN; - } else { - exif_attributes->exposure_bias.num = ev * EXIF_DEF_APEX_DEN; - exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN; - } - - switch (exynos_camera->camera_metering) { - case METERING_CENTER: - exif_attributes->metering_mode = EXIF_METERING_CENTER; - break; - case METERING_MATRIX: - exif_attributes->metering_mode = EXIF_METERING_AVERAGE; - break; - case METERING_SPOT: - exif_attributes->metering_mode = EXIF_METERING_SPOT; - break; - default: - exif_attributes->metering_mode = EXIF_METERING_AVERAGE; - break; - } - - if (exynos_camera->whitebalance == WHITE_BALANCE_AUTO || - exynos_camera->whitebalance == WHITE_BALANCE_BASE) - exif_attributes->white_balance = EXIF_WB_AUTO; - else - exif_attributes->white_balance = EXIF_WB_MANUAL; - - switch (exynos_camera->scene_mode) { - case SCENE_MODE_PORTRAIT: - exif_attributes->scene_capture_type = EXIF_SCENE_PORTRAIT; - break; - case SCENE_MODE_LANDSCAPE: - exif_attributes->scene_capture_type = EXIF_SCENE_LANDSCAPE; - break; - case SCENE_MODE_NIGHTSHOT: - exif_attributes->scene_capture_type = EXIF_SCENE_NIGHT; - break; - default: - exif_attributes->scene_capture_type = EXIF_SCENE_STANDARD; - break; - } - - rc = exynos_exif_attributes_create_gps(exynos_camera, exif_attributes); - if (rc < 0) { - ALOGE("%s: Failed to create GPS attributes", __func__); - return -1; - } - - return 0; -} - -int exynos_exif_write_data(void *exif_data, unsigned short tag, - unsigned short type, unsigned int count, int *offset, void *start, - void *data, int length) -{ - unsigned char *pointer; - int size; - - if (exif_data == NULL || data == NULL || length <= 0) - return -EINVAL; - - pointer = (unsigned char *) exif_data; - - memcpy(pointer, &tag, sizeof(tag)); - pointer += sizeof(tag); - - memcpy(pointer, &type, sizeof(type)); - pointer += sizeof(type); - - memcpy(pointer, &count, sizeof(count)); - pointer += sizeof(count); - - if (offset != NULL && start != NULL) { - memcpy(pointer, offset, sizeof(*offset)); - pointer += sizeof(*offset); - - memcpy((void *) ((int) start + *offset), data, count * length); - *offset += count * length; - } else { - memcpy(pointer, data, count * length); - pointer += 4; - } - - size = (int) pointer - (int) exif_data; - return size; -} - -int exynos_exif_create(struct exynos_camera *exynos_camera, - exif_attribute_t *exif_attributes, - camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size, - camera_memory_t **exif_data_memory_p, int *exif_size_p) -{ - // Markers - unsigned char exif_app1_marker[] = { 0xff, 0xe1 }; - unsigned char exif_app1_size[] = { 0x00, 0x00 }; - unsigned char exif_marker[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; - unsigned char tiff_marker[] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; - - unsigned char user_comment_code[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; - unsigned char exif_ascii_prefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; - - camera_memory_t *exif_data_memory; - void *exif_data; - int exif_data_size; - int exif_size; - - void *exif_ifd_data_start, *exif_ifd_start, *exif_ifd_gps, *exif_ifd_thumb; - - void *exif_thumb_data; - unsigned int exif_thumb_size; - - unsigned char *pointer; - unsigned int offset; - void *data; - int count; - - unsigned int value; - - if (exynos_camera == NULL || exif_attributes == NULL || - jpeg_thumbnail_data_memory == NULL || jpeg_thumbnail_size <= 0 || - exif_data_memory_p == NULL || exif_size_p == NULL) - return -EINVAL; - - exif_data_size = EXIF_FILE_SIZE + jpeg_thumbnail_size; - - if (exynos_camera->callbacks.request_memory != NULL) { - exif_data_memory = exynos_camera->callbacks.request_memory(-1, - exif_data_size, 1, 0); - if (exif_data_memory == NULL) { - ALOGE("%s: exif memory request failed!", __func__); - goto error; - } - } else { - ALOGE("%s: No memory request function!", __func__); - goto error; - } - - exif_data = exif_data_memory->data; - memset(exif_data, 0, exif_data_size); - - pointer = (unsigned char *) exif_data; - exif_ifd_data_start = (void *) pointer; - - // Skip 4 bytes for APP1 marker - pointer += 4; - - // Copy EXIF marker - memcpy(pointer, exif_marker, sizeof(exif_marker)); - pointer += sizeof(exif_marker); - - // Copy TIFF marker - memcpy(pointer, tiff_marker, sizeof(tiff_marker)); - exif_ifd_start = (void *) pointer; - pointer += sizeof(tiff_marker); - - if (exif_attributes->enableGps) - value = NUM_0TH_IFD_TIFF; - else - value = NUM_0TH_IFD_TIFF - 1; - - memcpy(pointer, &value, NUM_SIZE); - pointer += NUM_SIZE; - - offset = 8 + NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE; - - // Write EXIF data - count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_MAKE, - EXIF_TYPE_ASCII, strlen((char *) exif_attributes->maker) + 1, - &offset, exif_ifd_start, &exif_attributes->maker, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_MODEL, - EXIF_TYPE_ASCII, strlen((char *) exif_attributes->model) + 1, - &offset, exif_ifd_start, &exif_attributes->model, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_SOFTWARE, - EXIF_TYPE_ASCII, strlen((char *) exif_attributes->software) + 1, - &offset, exif_ifd_start, &exif_attributes->software, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME, - EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_YCBCR_POSITIONING, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->ycbcr_positioning, sizeof(exif_attributes->ycbcr_positioning)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_IFD_POINTER, - EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); - pointer += count; - - if (exif_attributes->enableGps) { - exif_ifd_gps = (void *) pointer; - pointer += IFD_SIZE; - } - - exif_ifd_thumb = (void *) pointer; - pointer += OFFSET_SIZE; - - pointer = (unsigned char *) exif_ifd_start; - pointer += offset; - - value = NUM_0TH_IFD_EXIF; - memcpy(pointer, &value, NUM_SIZE); - pointer += NUM_SIZE; - - offset += NUM_SIZE + NUM_0TH_IFD_EXIF * IFD_SIZE + OFFSET_SIZE; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_TIME, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_time, sizeof(exif_attributes->exposure_time)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_FNUMBER, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->fnumber, sizeof(exif_attributes->fnumber)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_PROGRAM, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_program, sizeof(exif_attributes->exposure_program)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_ISO_SPEED_RATING, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->iso_speed_rating, sizeof(exif_attributes->iso_speed_rating)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_VERSION, - EXIF_TYPE_UNDEFINED, 4, NULL, NULL, &exif_attributes->exif_version, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_ORG, - EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_DIGITIZE, - EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_SHUTTER_SPEED, - EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->shutter_speed, sizeof(exif_attributes->shutter_speed)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_APERTURE, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->aperture, sizeof(exif_attributes->aperture)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_BRIGHTNESS, - EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->brightness, sizeof(exif_attributes->brightness)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_BIAS, - EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_bias, sizeof(exif_attributes->exposure_bias)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_MAX_APERTURE, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->max_aperture, sizeof(exif_attributes->max_aperture)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_METERING_MODE, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->metering_mode, sizeof(exif_attributes->metering_mode)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_FLASH, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->flash, sizeof(exif_attributes->flash)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_FOCAL_LENGTH, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->focal_length, sizeof(exif_attributes->focal_length)); - pointer += count; - - value = strlen((char *) exif_attributes->user_comment) + 1; - memmove(exif_attributes->user_comment + sizeof(user_comment_code), exif_attributes->user_comment, value); - memcpy(exif_attributes->user_comment, user_comment_code, sizeof(user_comment_code)); - - count = exynos_exif_write_data(pointer, EXIF_TAG_USER_COMMENT, - EXIF_TYPE_UNDEFINED, value + sizeof(user_comment_code), &offset, exif_ifd_start, &exif_attributes->user_comment, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_COLOR_SPACE, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->color_space, sizeof(exif_attributes->color_space)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_X_DIMENSION, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_Y_DIMENSION, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_MODE, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_mode, sizeof(exif_attributes->exposure_mode)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_WHITE_BALANCE, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->white_balance, sizeof(exif_attributes->white_balance)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_SCENCE_CAPTURE_TYPE, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->scene_capture_type, sizeof(exif_attributes->scene_capture_type)); - pointer += count; - - value = 0; - memcpy(pointer, &value, OFFSET_SIZE); - pointer += OFFSET_SIZE; - - // GPS - if (exif_attributes->enableGps) { - pointer = (unsigned char *) exif_ifd_gps; - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_IFD_POINTER, - EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); - - pointer = exif_ifd_start + offset; - - if (exif_attributes->gps_processing_method[0] == 0) - value = NUM_0TH_IFD_GPS - 1; - else - value = NUM_0TH_IFD_GPS; - - memcpy(pointer, &value, NUM_SIZE); - pointer += NUM_SIZE; - - offset += NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_VERSION_ID, - EXIF_TYPE_BYTE, 4, NULL, NULL, &exif_attributes->gps_version_id, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE_REF, - EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_latitude_ref, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE, - EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_latitude, sizeof(exif_attributes->gps_latitude[0])); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE_REF, - EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_longitude_ref, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE, - EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_longitude, sizeof(exif_attributes->gps_longitude[0])); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE_REF, - EXIF_TYPE_BYTE, 1, NULL, NULL, &exif_attributes->gps_altitude_ref, sizeof(char)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->gps_altitude, sizeof(exif_attributes->gps_altitude)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_TIMESTAMP, - EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_timestamp, sizeof(exif_attributes->gps_timestamp[0])); - pointer += count; - - value = strlen((char *) exif_attributes->gps_processing_method); - if (value > 0) { - value = value > 100 ? 100 : value; - - data = calloc(1, value + sizeof(exif_ascii_prefix)); - memcpy(data, &exif_ascii_prefix, sizeof(exif_ascii_prefix)); - memcpy((void *) ((int) data + (int) sizeof(exif_ascii_prefix)), exif_attributes->gps_processing_method, value); - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_PROCESSING_METHOD, - EXIF_TYPE_UNDEFINED, value + sizeof(exif_ascii_prefix), &offset, exif_ifd_start, data, sizeof(char)); - pointer += count; - - free(data); - } - - count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_DATESTAMP, - EXIF_TYPE_ASCII, 11, &offset, exif_ifd_start, &exif_attributes->gps_datestamp, 1); - pointer += count; - - value = 0; - memcpy(pointer, &value, OFFSET_SIZE); - pointer += OFFSET_SIZE; - } - - if (exif_attributes->enableThumb && jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_size > 0) { - exif_thumb_size = (unsigned int) jpeg_thumbnail_size; - exif_thumb_data = (void *) jpeg_thumbnail_data_memory->data; - - value = offset; - memcpy(exif_ifd_thumb, &value, OFFSET_SIZE); - - pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset); - - value = NUM_1TH_IFD_TIFF; - memcpy(pointer, &value, NUM_SIZE); - pointer += NUM_SIZE; - - offset += NUM_SIZE + NUM_1TH_IFD_TIFF * IFD_SIZE + OFFSET_SIZE; - - count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->widthThumb, sizeof(exif_attributes->widthThumb)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->heightThumb, sizeof(exif_attributes->heightThumb)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_COMPRESSION_SCHEME, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->compression_scheme, sizeof(exif_attributes->compression_scheme)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_X_RESOLUTION, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->x_resolution, sizeof(exif_attributes->x_resolution)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_Y_RESOLUTION, - EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->y_resolution, sizeof(exif_attributes->y_resolution)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_RESOLUTION_UNIT, - EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->resolution_unit, sizeof(exif_attributes->resolution_unit)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, - EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); - pointer += count; - - count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, - EXIF_TYPE_LONG, 1, NULL, NULL, &exif_thumb_size, sizeof(exif_thumb_size)); - pointer += count; - - value = 0; - memcpy(pointer, &value, OFFSET_SIZE); - - pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset); - - memcpy(pointer, exif_thumb_data, exif_thumb_size); - offset += exif_thumb_size; - } else { - value = 0; - memcpy(exif_ifd_thumb, &value, OFFSET_SIZE); - - } - - pointer = (unsigned char *) exif_ifd_data_start; - - memcpy(pointer, exif_app1_marker, sizeof(exif_app1_marker)); - pointer += sizeof(exif_app1_marker); - - exif_size = offset + 10; - value = exif_size - 2; - exif_app1_size[0] = (value >> 8) & 0xff; - exif_app1_size[1] = value & 0xff; - - memcpy(pointer, exif_app1_size, sizeof(exif_app1_size)); - - *exif_data_memory_p = exif_data_memory; - *exif_size_p = exif_size; - - return 0; - -error: - if (exif_data_memory != NULL && exif_data_memory->release != NULL) - exif_data_memory->release(exif_data_memory); - - *exif_data_memory_p = NULL; - *exif_size_p = 0; - - return -1; -} diff --git a/camera/exynos_param.c b/camera/exynos_param.c deleted file mode 100644 index 3de4036..0000000 --- a/camera/exynos_param.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (C) 2013 Paul Kocialkowski - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#define LOG_TAG "exynos_param" -#include - -#include "exynos_camera.h" - -int list_head_insert(struct list_head *list, struct list_head *prev, - struct list_head *next) -{ - if (list == NULL) - return -EINVAL; - - list->prev = prev; - list->next = next; - - if(prev != NULL) - prev->next = list; - if(next != NULL) - next->prev = list; - - return 0; -} - -void list_head_remove(struct list_head *list) -{ - if(list == NULL) - return; - - if(list->next != NULL) - list->next->prev = list->prev; - if(list->prev != NULL) - list->prev->next = list->next; -} - -int exynos_param_register(struct exynos_camera *exynos_camera, char *key, - union exynos_param_data data, enum exynos_param_type type) -{ - struct list_head *list_end; - struct list_head *list; - struct exynos_param *param; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - param = (struct exynos_param *) calloc(1, sizeof(struct exynos_param)); - if (param == NULL) - return -ENOMEM; - - param->key = strdup(key); - switch (type) { - case EXYNOS_PARAM_INT: - param->data.integer = data.integer; - break; - case EXYNOS_PARAM_FLOAT: - param->data.floating = data.floating; - break; - case EXYNOS_PARAM_STRING: - param->data.string = strdup(data.string); - break; - default: - ALOGE("%s: Invalid type", __func__); - goto error; - } - param->type = type; - - list_end = (struct list_head *) exynos_camera->params; - while (list_end != NULL && list_end->next != NULL) - list_end = list_end->next; - - list = (struct list_head *) param; - list_head_insert(list, list_end, NULL); - - if (exynos_camera->params == NULL) - exynos_camera->params = param; - - return 0; - -error: - if (param != NULL) { - if (param->key != NULL) - free(param->key); - - free(param); - } - - return -1; -} - -void exynos_param_unregister(struct exynos_camera *exynos_camera, - struct exynos_param *param) -{ - struct list_head *list; - - if (exynos_camera == NULL || param == NULL) - return; - - list = (struct list_head *) exynos_camera->params; - while (list != NULL) { - if ((void *) list == (void *) param) { - list_head_remove(list); - - if ((void *) list == (void *) exynos_camera->params) - exynos_camera->params = (struct exynos_param *) list->next; - - if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL) - free(param->data.string); - - memset(param, 0, sizeof(struct exynos_param)); - free(param); - - break; - } - -list_continue: - list = list->next; - } -} - -struct exynos_param *exynos_param_find_key(struct exynos_camera *exynos_camera, - char *key) -{ - struct exynos_param *param; - struct list_head *list; - - if (exynos_camera == NULL || key == NULL) - return NULL; - - list = (struct list_head *) exynos_camera->params; - while (list != NULL) { - param = (struct exynos_param *) list; - if (param->key == NULL) - goto list_continue; - - if (strcmp(param->key, key) == 0) - return param; - -list_continue: - list = list->next; - } - - return NULL; -} - -int exynos_param_data_set(struct exynos_camera *exynos_camera, char *key, - union exynos_param_data data, enum exynos_param_type type) -{ - struct exynos_param *param; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - if (strchr(key, '=') || strchr(key, ';')) - return -EINVAL; - - if (type == EXYNOS_PARAM_STRING && data.string != NULL && - (strchr(data.string, '=') || strchr(data.string, ';'))) - return -EINVAL; - - param = exynos_param_find_key(exynos_camera, key); - if (param == NULL) { - // The key isn't in the list yet - exynos_param_register(exynos_camera, key, data, type); - return 0; - } - - if (param->type != type) - ALOGE("%s: Mismatching types for key %s", __func__, key); - - if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL) - free(param->data.string); - - switch (type) { - case EXYNOS_PARAM_INT: - param->data.integer = data.integer; - break; - case EXYNOS_PARAM_FLOAT: - param->data.floating = data.floating; - break; - case EXYNOS_PARAM_STRING: - param->data.string = strdup(data.string); - break; - default: - ALOGE("%s: Invalid type", __func__); - return -1; - } - param->type = type; - - return 0; -} - -int exynos_param_data_get(struct exynos_camera *exynos_camera, char *key, - union exynos_param_data *data, enum exynos_param_type type) -{ - struct exynos_param *param; - - if (exynos_camera == NULL || key == NULL || data == NULL) - return -EINVAL; - - param = exynos_param_find_key(exynos_camera, key); - if (param == NULL || param->type != type) - return -1; - - memcpy(data, ¶m->data, sizeof(param->data)); - - return 0; -} - -int exynos_param_int_get(struct exynos_camera *exynos_camera, - char *key) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_INT); - if (rc < 0) { - ALOGE("%s: Unable to get data for key %s", __func__, key); - return -1; - } - - return data.integer; -} - -float exynos_param_float_get(struct exynos_camera *exynos_camera, - char *key) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_FLOAT); - if (rc < 0) { - ALOGE("%s: Unable to get data for key %s", __func__, key); - return -1; - } - - return data.floating; -} - -char *exynos_param_string_get(struct exynos_camera *exynos_camera, - char *key) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL) - return NULL; - - rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_STRING); - if (rc < 0) { - ALOGE("%s: Unable to get data for key %s", __func__, key); - return NULL; - } - - return data.string; -} - -int exynos_param_int_set(struct exynos_camera *exynos_camera, - char *key, int integer) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - data.integer = integer; - - rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_INT); - if (rc < 0) { - ALOGE("%s: Unable to set data for key %s", __func__, key); - return -1; - } - - return 0; -} - -int exynos_param_float_set(struct exynos_camera *exynos_camera, - char *key, float floating) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL) - return -EINVAL; - - data.floating = floating; - - rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_FLOAT); - if (rc < 0) { - ALOGE("%s: Unable to set data for key %s", __func__, key); - return -1; - } - - return 0; -} - -int exynos_param_string_set(struct exynos_camera *exynos_camera, - char *key, char *string) -{ - union exynos_param_data data; - int rc; - - if (exynos_camera == NULL || key == NULL || string == NULL) - return -EINVAL; - - data.string = string; - - rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_STRING); - if (rc < 0) { - ALOGE("%s: Unable to set data for key %s", __func__, key); - return -1; - } - - return 0; -} - -char *exynos_params_string_get(struct exynos_camera *exynos_camera) -{ - struct exynos_param *param; - struct list_head *list; - char *string = NULL; - char *s = NULL; - int length = 0; - int l = 0; - - if (exynos_camera == NULL) - return NULL; - - list = (struct list_head *) exynos_camera->params; - while (list != NULL) { - param = (struct exynos_param *) list; - if (param->key == NULL) - goto list_continue_length; - - length += strlen(param->key); - length++; - - switch (param->type) { - case EXYNOS_PARAM_INT: - case EXYNOS_PARAM_FLOAT: - length += 16; - break; - case EXYNOS_PARAM_STRING: - length += strlen(param->data.string); - break; - default: - ALOGE("%s: Invalid type", __func__); - return NULL; - } - - length++; - -list_continue_length: - list = list->next; - } - - if (length == 0) - return NULL; - - string = calloc(1, length); - s = string; - - list = (struct list_head *) exynos_camera->params; - while (list != NULL) { - param = (struct exynos_param *) list; - if (param->key == NULL) - goto list_continue; - - l = sprintf(s, "%s=", param->key); - s += l; - - switch (param->type) { - case EXYNOS_PARAM_INT: - l = snprintf(s, 16, "%d", param->data.integer); - s += l; - break; - case EXYNOS_PARAM_FLOAT: - l = snprintf(s, 16, "%g", param->data.floating); - s += l; - break; - case EXYNOS_PARAM_STRING: - l = sprintf(s, "%s", param->data.string); - s += l; - break; - default: - ALOGE("%s: Invalid type", __func__); - return NULL; - } - - if (list->next != NULL) { - *s = ';'; - s++; - } else { - *s = '\0'; - break; - } - -list_continue: - list = list->next; - } - - return string; -} - -int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string) -{ - union exynos_param_data data; - enum exynos_param_type type; - - char *d = NULL; - char *s = NULL; - char *k = NULL; - char *v = NULL; - - char *key; - char *value; - - int rc; - int i; - - if (exynos_camera == NULL || string == NULL) - return -1; - - d = strdup(string); - s = d; - - while (1) { - k = strchr(s, '='); - if (k == NULL) - break; - *k = '\0'; - key = s; - - v = strchr(k+1, ';'); - if (v != NULL) - *v = '\0'; - value = k+1; - - k = value; - if (isdigit(k[0]) || k[0] == '-') { - type = EXYNOS_PARAM_INT; - - for (i=1 ; k[i] != '\0' ; i++) { - if (k[i] == '.') { - type = EXYNOS_PARAM_FLOAT; - } else if (!isdigit(k[i])) { - type = EXYNOS_PARAM_STRING; - break; - } - } - } else { - type = EXYNOS_PARAM_STRING; - } - - switch (type) { - case EXYNOS_PARAM_INT: - data.integer = atoi(value); - break; - case EXYNOS_PARAM_FLOAT: - data.floating = atof(value); - break; - case EXYNOS_PARAM_STRING: - data.string = value; - break; - default: - ALOGE("%s: Invalid type", __func__); - goto error; - } - - rc = exynos_param_data_set(exynos_camera, key, data, type); - if (rc < 0) { - ALOGE("%s: Unable to set data for key %s", __func__, key); - goto error; - } - - if (v == NULL) - break; - - s = v+1; - } - - if (d != NULL) - free(d); - - return 0; - -error: - if (d != NULL) - free(d); - - return -1; -} diff --git a/camera/smdk4210_camera.c b/camera/smdk4210_camera.c new file mode 100644 index 0000000..55b01a1 --- /dev/null +++ b/camera/smdk4210_camera.c @@ -0,0 +1,2865 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * + * Based on crespo libcamera and exynos4 hal libcamera: + * Copyright 2008, The Android Open Source Project, Apache License 2.0 + * Copyright 2010, Samsung Electronics Co. LTD, Apache License 2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LOG_TAG "smdk4210_camera" +#include +#include + +#include "smdk4210_camera.h" + +/* + * Devices configurations + */ + +struct smdk4210_camera_preset smdk4210_camera_presets_galaxys2[] = { + { + .name = "M5MO", + .facing = CAMERA_FACING_BACK, + .orientation = 90, + .rotation = 0, + .hflip = 0, + .vflip = 0, + .picture_format = V4L2_PIX_FMT_JPEG, + .focal_length = 4.03f, + .horizontal_view_angle = 60.5f, + .vertical_view_angle = 47.1f, + .metering = METERING_CENTER, + .params = { + .preview_size_values = "1280x720,640x480,720x480,800x480,800x450,352x288,320x240,176x144", + .preview_size = "640x480", + .preview_format_values = "yuv420sp,yuv420p,rgb565", + .preview_format = "yuv420sp", + .preview_frame_rate_values = "30,25,20,15,10,7", + .preview_frame_rate = 30, + .preview_fps_range_values = "(7000,30000)", + .preview_fps_range = "7000,30000", + + .picture_size_values = "3264x2448,3264x1968,2048x1536,2048x1232,1280x960,800x480,640x480", + .picture_size = "3264x2448", + .picture_format_values = "jpeg", + .picture_format = "jpeg", + .jpeg_thumbnail_size_values = "320x240,400x240,0x0", + .jpeg_thumbnail_width = 320, + .jpeg_thumbnail_height = 240, + .jpeg_thumbnail_quality = 100, + .jpeg_quality = 90, + + .recording_size = "720x480", + .recording_size_values = "1920x1080,1280x720,720x480,640x480", + .recording_format = "yuv420sp", + + .focus_mode = "auto", + .focus_mode_values = "auto,infinity,macro,fixed,facedetect,continuous-video", + .focus_distances = "0.15,1.20,Infinity", + .focus_areas = "(0,0,0,0,0)", + .max_num_focus_areas = 1, + + .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", + .zoom = 0, + .max_zoom = 30, + + .flash_mode = "off", + .flash_mode_values = "off,auto,on,torch", + + .exposure_compensation = 0, + .exposure_compensation_step = 0.5, + .min_exposure_compensation = -4, + .max_exposure_compensation = 4, + + .whitebalance = "auto", + .whitebalance_values = "auto,incandescent,fluorescent,daylight,cloudy-daylight", + + .scene_mode = "auto", + .scene_mode_values = "auto,portrait,landscape,night,beach,snow,sunset,fireworks,sports,party,candlelight,dusk-dawn,fall-color,back-light,text", + + .effect = "none", + .effect_values = "none,mono,negative,sepia,aqua", + + .iso = "auto", + .iso_values = "auto,ISO50,ISO100,ISO200,ISO400,ISO800", + }, + }, + { + .name = "S5K5BAFX", + .facing = CAMERA_FACING_FRONT, + .orientation = 270, + .rotation = 0, + .hflip = 0, + .vflip = 0, + .picture_format = V4L2_PIX_FMT_YUYV, + .focal_length = 2.73f, + .horizontal_view_angle = 51.2f, + .vertical_view_angle = 39.4f, + .metering = METERING_CENTER, + .params = { + .preview_size_values = "640x480,352x288,320x240,176x144", + .preview_size = "640x480", + .preview_format_values = "yuv420sp,yuv420p,rgb565", + .preview_format = "yuv420sp", + .preview_frame_rate_values = "30,25,20,15,10,7", + .preview_frame_rate = 30, + .preview_fps_range_values = "(7000,30000)", + .preview_fps_range = "7000,30000", + + .picture_size_values = "1600x1200,640x480", + .picture_size = "1600x1200", + .picture_format_values = "jpeg", + .picture_format = "jpeg", + .jpeg_thumbnail_size_values = "160x120,0x0", + .jpeg_thumbnail_width = 160, + .jpeg_thumbnail_height = 120, + .jpeg_thumbnail_quality = 100, + .jpeg_quality = 90, + + .recording_size = "640x480", + .recording_size_values = "640x480", + .recording_format = "yuv420sp", + + .focus_mode = "fixed", + .focus_mode_values = "fixed", + .focus_distances = "0.20,0.25,Infinity", + .focus_areas = NULL, + .max_num_focus_areas = 0, + + .zoom_supported = 0, + + .flash_mode = NULL, + .flash_mode_values = NULL, + + .exposure_compensation = 0, + .exposure_compensation_step = 0.5, + .min_exposure_compensation = -4, + .max_exposure_compensation = 4, + + .whitebalance = NULL, + .whitebalance_values = NULL, + + .scene_mode = NULL, + .scene_mode_values = NULL, + + .effect = NULL, + .effect_values = NULL, + + .iso = "auto", + .iso_values = "auto", + }, + }, +}; + +struct smdk4210_v4l2_node smdk4210_v4l2_nodes_galaxys2[] = { + { + .id = 0, + .node = "/dev/video0", + }, + { + .id = 1, + .node = "/dev/video1", + }, + { + .id = 2, + .node = "/dev/video2", + }, +}; + +struct exynox_camera_config smdk4210_camera_config_galaxys2 = { + .presets = (struct smdk4210_camera_preset *) &smdk4210_camera_presets_galaxys2, + .presets_count = 2, + .v4l2_nodes = (struct smdk4210_v4l2_node *) &smdk4210_v4l2_nodes_galaxys2, + .v4l2_nodes_count = 3, +}; + +/* + * SMDK4210 Camera + */ + +struct exynox_camera_config *smdk4210_camera_config = + &smdk4210_camera_config_galaxys2; + +int smdk4210_camera_init(struct smdk4210_camera *smdk4210_camera, int id) +{ + char firmware_version[7] = { 0 }; + struct smdk4210_v4l2_ext_control control; + int rc; + + if (smdk4210_camera == NULL || id >= smdk4210_camera->config->presets_count) + return -EINVAL; + + // Init FIMC1 + rc = smdk4210_v4l2_open(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("Unable to open v4l2 device"); + return -1; + } + + rc = smdk4210_v4l2_querycap_cap(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: querycap failed", __func__); + return -1; + } + + rc = smdk4210_v4l2_enum_input(smdk4210_camera, 0, id); + if (rc < 0) { + ALOGE("%s: enum input failed", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_input(smdk4210_camera, 0, id); + if (rc < 0) { + ALOGE("%s: s input failed", __func__); + return -1; + } + + // Init FIMC2 + rc = smdk4210_v4l2_open(smdk4210_camera, 2); + if (rc < 0) { + ALOGE("Unable to open v4l2 device"); + return -1; + } + + rc = smdk4210_v4l2_querycap_cap(smdk4210_camera, 2); + if (rc < 0) { + ALOGE("%s: querycap failed", __func__); + return -1; + } + + rc = smdk4210_v4l2_enum_input(smdk4210_camera, 2, id); + if (rc < 0) { + ALOGE("%s: enum input failed", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_input(smdk4210_camera, 2, id); + if (rc < 0) { + ALOGE("%s: s input failed", __func__); + return -1; + } + + // Get firmware information + memset(&control, 0, sizeof(control)); + control.id = V4L2_CID_CAM_SENSOR_FW_VER; + control.data.string = firmware_version; + + rc = smdk4210_v4l2_g_ext_ctrls(smdk4210_camera, 0, (struct v4l2_ext_control *) &control, 1); + if (rc < 0) { + ALOGE("%s: g ext ctrls failed", __func__); + } else { + ALOGD("Firmware version: %s", firmware_version); + } + + // Params + rc = smdk4210_camera_params_init(smdk4210_camera, id); + if (rc < 0) + ALOGE("%s: Unable to init params", __func__); + + // Gralloc + rc = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const struct hw_module_t **) &smdk4210_camera->gralloc); + if (rc) + ALOGE("%s: Unable to get gralloc module", __func__); + + return 0; +} + +void smdk4210_camera_deinit(struct smdk4210_camera *smdk4210_camera) +{ + int i; + int id; + + if (smdk4210_camera == NULL || smdk4210_camera->config == NULL) + return; + + smdk4210_v4l2_close(smdk4210_camera, 0); + smdk4210_v4l2_close(smdk4210_camera, 2); +} + +// Params + +int smdk4210_camera_params_init(struct smdk4210_camera *smdk4210_camera, int id) +{ + int rc; + + if (smdk4210_camera == NULL || id >= smdk4210_camera->config->presets_count) + return -EINVAL; + + // Camera params + smdk4210_camera->camera_rotation = smdk4210_camera->config->presets[id].rotation; + smdk4210_camera->camera_hflip = smdk4210_camera->config->presets[id].hflip; + smdk4210_camera->camera_vflip = smdk4210_camera->config->presets[id].vflip; + smdk4210_camera->camera_picture_format = smdk4210_camera->config->presets[id].picture_format; + smdk4210_camera->camera_focal_length = (int) (smdk4210_camera->config->presets[id].focal_length * 100); + smdk4210_camera->camera_metering = smdk4210_camera->config->presets[id].metering; + + // Recording preview + smdk4210_param_string_set(smdk4210_camera, "preferred-preview-size-for-video", + smdk4210_camera->config->presets[id].params.preview_size); + + // Preview + smdk4210_param_string_set(smdk4210_camera, "preview-size-values", + smdk4210_camera->config->presets[id].params.preview_size_values); + smdk4210_param_string_set(smdk4210_camera, "preview-size", + smdk4210_camera->config->presets[id].params.preview_size); + smdk4210_param_string_set(smdk4210_camera, "preview-format-values", + smdk4210_camera->config->presets[id].params.preview_format_values); + smdk4210_param_string_set(smdk4210_camera, "preview-format", + smdk4210_camera->config->presets[id].params.preview_format); + smdk4210_param_string_set(smdk4210_camera, "preview-frame-rate-values", + smdk4210_camera->config->presets[id].params.preview_frame_rate_values); + smdk4210_param_int_set(smdk4210_camera, "preview-frame-rate", + smdk4210_camera->config->presets[id].params.preview_frame_rate); + smdk4210_param_string_set(smdk4210_camera, "preview-fps-range-values", + smdk4210_camera->config->presets[id].params.preview_fps_range_values); + smdk4210_param_string_set(smdk4210_camera, "preview-fps-range", + smdk4210_camera->config->presets[id].params.preview_fps_range); + + // Picture + smdk4210_param_string_set(smdk4210_camera, "picture-size-values", + smdk4210_camera->config->presets[id].params.picture_size_values); + smdk4210_param_string_set(smdk4210_camera, "picture-size", + smdk4210_camera->config->presets[id].params.picture_size); + smdk4210_param_string_set(smdk4210_camera, "picture-format-values", + smdk4210_camera->config->presets[id].params.picture_format_values); + smdk4210_param_string_set(smdk4210_camera, "picture-format", + smdk4210_camera->config->presets[id].params.picture_format); + smdk4210_param_string_set(smdk4210_camera, "jpeg-thumbnail-size-values", + smdk4210_camera->config->presets[id].params.jpeg_thumbnail_size_values); + smdk4210_param_int_set(smdk4210_camera, "jpeg-thumbnail-width", + smdk4210_camera->config->presets[id].params.jpeg_thumbnail_width); + smdk4210_param_int_set(smdk4210_camera, "jpeg-thumbnail-height", + smdk4210_camera->config->presets[id].params.jpeg_thumbnail_height); + smdk4210_param_int_set(smdk4210_camera, "jpeg-thumbnail-quality", + smdk4210_camera->config->presets[id].params.jpeg_thumbnail_quality); + smdk4210_param_int_set(smdk4210_camera, "jpeg-quality", + smdk4210_camera->config->presets[id].params.jpeg_quality); + + // Recording + smdk4210_param_string_set(smdk4210_camera, "video-size", + smdk4210_camera->config->presets[id].params.recording_size); + smdk4210_param_string_set(smdk4210_camera, "video-size-values", + smdk4210_camera->config->presets[id].params.recording_size_values); + smdk4210_param_string_set(smdk4210_camera, "video-frame-format", + smdk4210_camera->config->presets[id].params.recording_format); + + // Focus + smdk4210_param_string_set(smdk4210_camera, "focus-mode", + smdk4210_camera->config->presets[id].params.focus_mode); + smdk4210_param_string_set(smdk4210_camera, "focus-mode-values", + smdk4210_camera->config->presets[id].params.focus_mode_values); + smdk4210_param_string_set(smdk4210_camera, "focus-distances", + smdk4210_camera->config->presets[id].params.focus_distances); + if (smdk4210_camera->config->presets[id].params.max_num_focus_areas > 0) { + smdk4210_param_string_set(smdk4210_camera, "focus-areas", + smdk4210_camera->config->presets[id].params.focus_areas); + smdk4210_param_int_set(smdk4210_camera, "max-num-focus-areas", + smdk4210_camera->config->presets[id].params.max_num_focus_areas); + } + + // Zoom + if (smdk4210_camera->config->presets[id].params.zoom_supported == 1) { + smdk4210_param_string_set(smdk4210_camera, "zoom-supported", "true"); + + if (smdk4210_camera->config->presets[id].params.smooth_zoom_supported == 1) + smdk4210_param_string_set(smdk4210_camera, "smooth-zoom-supported", "true"); + + if (smdk4210_camera->config->presets[id].params.zoom_ratios != NULL) + smdk4210_param_string_set(smdk4210_camera, "zoom-ratios", smdk4210_camera->config->presets[id].params.zoom_ratios); + + smdk4210_param_int_set(smdk4210_camera, "zoom", smdk4210_camera->config->presets[id].params.zoom); + smdk4210_param_int_set(smdk4210_camera, "max-zoom", smdk4210_camera->config->presets[id].params.max_zoom); + + } else { + smdk4210_param_string_set(smdk4210_camera, "zoom-supported", "false"); + } + + // Flash + smdk4210_param_string_set(smdk4210_camera, "flash-mode", + smdk4210_camera->config->presets[id].params.flash_mode); + smdk4210_param_string_set(smdk4210_camera, "flash-mode-values", + smdk4210_camera->config->presets[id].params.flash_mode_values); + + // Exposure + smdk4210_param_int_set(smdk4210_camera, "exposure-compensation", + smdk4210_camera->config->presets[id].params.exposure_compensation); + smdk4210_param_float_set(smdk4210_camera, "exposure-compensation-step", + smdk4210_camera->config->presets[id].params.exposure_compensation_step); + smdk4210_param_int_set(smdk4210_camera, "min-exposure-compensation", + smdk4210_camera->config->presets[id].params.min_exposure_compensation); + smdk4210_param_int_set(smdk4210_camera, "max-exposure-compensation", + smdk4210_camera->config->presets[id].params.max_exposure_compensation); + + // WB + smdk4210_param_string_set(smdk4210_camera, "whitebalance", + smdk4210_camera->config->presets[id].params.whitebalance); + smdk4210_param_string_set(smdk4210_camera, "whitebalance-values", + smdk4210_camera->config->presets[id].params.whitebalance_values); + + // Scene mode + smdk4210_param_string_set(smdk4210_camera, "scene-mode", + smdk4210_camera->config->presets[id].params.scene_mode); + smdk4210_param_string_set(smdk4210_camera, "scene-mode-values", + smdk4210_camera->config->presets[id].params.scene_mode_values); + + // Effect + smdk4210_param_string_set(smdk4210_camera, "effect", + smdk4210_camera->config->presets[id].params.effect); + smdk4210_param_string_set(smdk4210_camera, "effect-values", + smdk4210_camera->config->presets[id].params.effect_values); + + // ISO + smdk4210_param_string_set(smdk4210_camera, "iso", + smdk4210_camera->config->presets[id].params.iso); + smdk4210_param_string_set(smdk4210_camera, "iso-values", + smdk4210_camera->config->presets[id].params.iso_values); + + // Camera + smdk4210_param_float_set(smdk4210_camera, "focal-length", + smdk4210_camera->config->presets[id].focal_length); + smdk4210_param_float_set(smdk4210_camera, "horizontal-view-angle", + smdk4210_camera->config->presets[id].horizontal_view_angle); + smdk4210_param_float_set(smdk4210_camera, "vertical-view-angle", + smdk4210_camera->config->presets[id].vertical_view_angle); + + rc = smdk4210_camera_params_apply(smdk4210_camera); + if (rc < 0) { + ALOGE("%s: Unable to apply params", __func__); + return -1; + } + + return 0; +} + +int smdk4210_camera_params_apply(struct smdk4210_camera *smdk4210_camera) +{ + char *recording_hint_string; + char *recording_preview_size_string; + + char *preview_size_string; + int preview_width = 0; + int preview_height = 0; + char *preview_format_string; + int preview_format; + float preview_format_bpp; + int preview_fps; + + char *picture_size_string; + int picture_width = 0; + int picture_height = 0; + char *picture_format_string; + int picture_format; + + int jpeg_thumbnail_width; + int jpeg_thumbnail_height; + int jpeg_thumbnail_quality; + int jpeg_quality; + + char *video_size_string; + int recording_width = 0; + int recording_height = 0; + char *video_frame_format_string; + int recording_format; + int camera_sensor_mode; + int camera_sensor_output_size; + + char *focus_mode_string; + int focus_mode = 0; + char *focus_areas_string; + int focus_left, focus_top, focus_right, focus_bottom, focus_weigth; + int focus_x; + int focus_y; + + char *zoom_supported_string; + int zoom, max_zoom; + + char *flash_mode_string; + int flash_mode; + + int exposure_compensation; + int min_exposure_compensation; + int max_exposure_compensation; + + char *whitebalance_string; + int whitebalance; + + char *scene_mode_string; + int scene_mode; + + char *effect_string; + int effect; + + char *iso_string; + int iso; + + int force = 0; + + int w, h; + char *k; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + if (!smdk4210_camera->preview_params_set) { + ALOGE("%s: Setting preview params", __func__); + smdk4210_camera->preview_params_set = 1; + force = 1; + } + + // Preview + preview_size_string = smdk4210_param_string_get(smdk4210_camera, "preview-size"); + if (preview_size_string != NULL) { + sscanf(preview_size_string, "%dx%d", &preview_width, &preview_height); + + if (preview_width != 0 && preview_width != smdk4210_camera->preview_width) + smdk4210_camera->preview_width = preview_width; + if (preview_height != 0 && preview_height != smdk4210_camera->preview_height) + smdk4210_camera->preview_height = preview_height; + } + + preview_format_string = smdk4210_param_string_get(smdk4210_camera, "preview-format"); + if (preview_format_string != NULL) { + if (strcmp(preview_format_string, "yuv420sp") == 0) { + preview_format = V4L2_PIX_FMT_NV21; + preview_format_bpp = 1.5f; + } else if (strcmp(preview_format_string, "yuv420p") == 0) { + preview_format = V4L2_PIX_FMT_YUV420; + preview_format_bpp = 1.5f; + } else if (strcmp(preview_format_string, "rgb565") == 0) { + preview_format = V4L2_PIX_FMT_RGB565; + preview_format_bpp = 2.0f; + } else if (strcmp(preview_format_string, "rgb8888") == 0) { + preview_format = V4L2_PIX_FMT_RGB32; + preview_format_bpp = 4.0f; + } else { + ALOGE("%s: Unsupported preview format: %s", __func__, preview_format_string); + preview_format = V4L2_PIX_FMT_NV21; + preview_format_bpp = 1.5f; + } + + if (preview_format != smdk4210_camera->preview_format) { + smdk4210_camera->preview_format = preview_format; + smdk4210_camera->preview_format_bpp = preview_format_bpp; + } + } + + preview_fps = smdk4210_param_int_get(smdk4210_camera, "preview-frame-rate"); + if (preview_fps > 0) + smdk4210_camera->preview_fps = preview_fps; + else + smdk4210_camera->preview_fps = 0; + + // Picture + picture_size_string = smdk4210_param_string_get(smdk4210_camera, "picture-size"); + if (picture_size_string != NULL) { + sscanf(picture_size_string, "%dx%d", &picture_width, &picture_height); + + if (picture_width != 0 && picture_width != smdk4210_camera->picture_width) + smdk4210_camera->picture_width = picture_width; + if (picture_height != 0 && picture_height != smdk4210_camera->picture_height) + smdk4210_camera->picture_height = picture_height; + } + + picture_format_string = smdk4210_param_string_get(smdk4210_camera, "picture-format"); + if (picture_format_string != NULL) { + if (strcmp(picture_format_string, "jpeg") == 0) { + picture_format = V4L2_PIX_FMT_JPEG; + } else { + ALOGE("%s: Unsupported picture format: %s", __func__, picture_format_string); + picture_format = V4L2_PIX_FMT_JPEG; + } + + if (picture_format != smdk4210_camera->picture_format) + smdk4210_camera->picture_format = picture_format; + } + + jpeg_thumbnail_width = smdk4210_param_int_get(smdk4210_camera, "jpeg-thumbnail-width"); + if (jpeg_thumbnail_width > 0) + smdk4210_camera->jpeg_thumbnail_width = jpeg_thumbnail_width; + + jpeg_thumbnail_height = smdk4210_param_int_get(smdk4210_camera, "jpeg-thumbnail-height"); + if (jpeg_thumbnail_height > 0) + smdk4210_camera->jpeg_thumbnail_height = jpeg_thumbnail_height; + + jpeg_thumbnail_quality = smdk4210_param_int_get(smdk4210_camera, "jpeg-thumbnail-quality"); + if (jpeg_thumbnail_quality > 0) + smdk4210_camera->jpeg_thumbnail_quality = jpeg_thumbnail_quality; + + jpeg_quality = smdk4210_param_int_get(smdk4210_camera, "jpeg-quality"); + if (jpeg_quality <= 100 && jpeg_quality >= 0 && (jpeg_quality != smdk4210_camera->jpeg_quality || force)) { + smdk4210_camera->jpeg_quality = jpeg_quality; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAM_JPEG_QUALITY, jpeg_quality); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + // Recording + video_size_string = smdk4210_param_string_get(smdk4210_camera, "video-size"); + if (video_size_string == NULL) + video_size_string = smdk4210_param_string_get(smdk4210_camera, "preview-size"); + + if (video_size_string != NULL) { + sscanf(video_size_string, "%dx%d", &recording_width, &recording_height); + + if (recording_width != 0 && recording_width != smdk4210_camera->recording_width) + smdk4210_camera->recording_width = recording_width; + if (recording_height != 0 && recording_height != smdk4210_camera->recording_height) + smdk4210_camera->recording_height = recording_height; + } + + video_frame_format_string = smdk4210_param_string_get(smdk4210_camera, "video-frame-format"); + if (video_frame_format_string != NULL) { + if (strcmp(video_frame_format_string, "yuv420sp") == 0) { + recording_format = V4L2_PIX_FMT_NV12; + } else if (strcmp(video_frame_format_string, "yuv420p") == 0) { + recording_format = V4L2_PIX_FMT_YUV420; + } else if (strcmp(video_frame_format_string, "rgb565") == 0) { + recording_format = V4L2_PIX_FMT_RGB565; + } else if (strcmp(video_frame_format_string, "rgb8888") == 0) { + recording_format = V4L2_PIX_FMT_RGB32; + } else { + ALOGE("%s: Unsupported recording format: %s", __func__, video_frame_format_string); + recording_format = V4L2_PIX_FMT_NV12; + } + + if (recording_format != smdk4210_camera->recording_format) + smdk4210_camera->recording_format = recording_format; + } + + recording_hint_string = smdk4210_param_string_get(smdk4210_camera, "recording-hint"); + if (recording_hint_string != NULL && strcmp(recording_hint_string, "true") == 0) { + camera_sensor_mode = SENSOR_MOVIE; + + k = smdk4210_param_string_get(smdk4210_camera, "preview-size-values"); + while (recording_width != 0 && recording_height != 0) { + if (k == NULL) + break; + + sscanf(k, "%dx%d", &w, &h); + + // Look for same aspect ratio + if ((recording_width * h) / recording_height == w) { + preview_width = w; + preview_height = h; + break; + } + + k = strchr(k, ','); + if (k == NULL) + break; + + k++; + } + + if (preview_width != 0 && preview_width != smdk4210_camera->preview_width) + smdk4210_camera->preview_width = preview_width; + if (preview_height != 0 && preview_height != smdk4210_camera->preview_height) + smdk4210_camera->preview_height = preview_height; + + camera_sensor_output_size = ((recording_width & 0xffff) << 16) | (recording_height & 0xffff); + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_SENSOR_OUTPUT_SIZE, + camera_sensor_output_size); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } else { + camera_sensor_mode = SENSOR_CAMERA; + } + + // Switching modes + if (camera_sensor_mode != smdk4210_camera->camera_sensor_mode) { + smdk4210_camera->camera_sensor_mode = camera_sensor_mode; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_SENSOR_MODE, camera_sensor_mode); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + // Focus + focus_areas_string = smdk4210_param_string_get(smdk4210_camera, "focus-areas"); + if (focus_areas_string != NULL) { + focus_left = focus_top = focus_right = focus_bottom = focus_weigth = 0; + + rc = sscanf(focus_areas_string, "(%d,%d,%d,%d,%d)", + &focus_left, &focus_top, &focus_right, &focus_bottom, &focus_weigth); + if (rc != 5) { + ALOGE("%s: sscanf failed!", __func__); + } else if (focus_left != 0 && focus_top != 0 && focus_right != 0 && focus_bottom != 0) { + focus_x = (((focus_left + focus_right) / 2) + 1000) * preview_width / 2000; + focus_y = (((focus_top + focus_bottom) / 2) + 1000) * preview_height / 2000; + + if (focus_x != smdk4210_camera->focus_x || force) { + smdk4210_camera->focus_x = focus_x; + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_X, focus_x); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + if (focus_y != smdk4210_camera->focus_y || force) { + smdk4210_camera->focus_y = focus_y; + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_Y, focus_y); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + focus_mode = FOCUS_MODE_TOUCH; + } + } + + focus_mode_string = smdk4210_param_string_get(smdk4210_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; + else if (strcmp(focus_mode_string, "continuous-picture") == 0) + focus_mode = FOCUS_MODE_CONTINOUS; + else + focus_mode = FOCUS_MODE_AUTO; + } + + if (focus_mode != smdk4210_camera->focus_mode || force) { + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + if (focus_mode == FOCUS_MODE_TOUCH) { + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, 1); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } else if (smdk4210_camera->focus_mode == FOCUS_MODE_TOUCH) { + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, 0); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + smdk4210_camera->focus_mode = focus_mode; + } + + // Zoom + zoom_supported_string = smdk4210_param_string_get(smdk4210_camera, "zoom-supported"); + if (zoom_supported_string != NULL && strcmp(zoom_supported_string, "true") == 0) { + zoom = smdk4210_param_int_get(smdk4210_camera, "zoom"); + max_zoom = smdk4210_param_int_get(smdk4210_camera, "max-zoom"); + if (zoom <= max_zoom && zoom >= 0 && (zoom != smdk4210_camera->zoom || force)) { + smdk4210_camera->zoom = zoom; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_ZOOM, zoom); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + } + + // Flash + flash_mode_string = smdk4210_param_string_get(smdk4210_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 + flash_mode = FLASH_MODE_AUTO; + + if (flash_mode != smdk4210_camera->flash_mode || force) { + smdk4210_camera->flash_mode = flash_mode; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_FLASH_MODE, flash_mode); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + } + + // Exposure + exposure_compensation = smdk4210_param_int_get(smdk4210_camera, "exposure-compensation"); + min_exposure_compensation = smdk4210_param_int_get(smdk4210_camera, "min-exposure-compensation"); + max_exposure_compensation = smdk4210_param_int_get(smdk4210_camera, "max-exposure-compensation"); + + if (exposure_compensation <= max_exposure_compensation && exposure_compensation >= min_exposure_compensation && + (exposure_compensation != smdk4210_camera->exposure_compensation || force)) { + smdk4210_camera->exposure_compensation = exposure_compensation; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_BRIGHTNESS, exposure_compensation); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + + // WB + whitebalance_string = smdk4210_param_string_get(smdk4210_camera, "whitebalance"); + if (whitebalance_string != NULL) { + if (strcmp(whitebalance_string, "auto") == 0) + whitebalance = WHITE_BALANCE_AUTO; + else if (strcmp(whitebalance_string, "incandescent") == 0) + whitebalance = WHITE_BALANCE_TUNGSTEN; + else if (strcmp(whitebalance_string, "fluorescent") == 0) + whitebalance = WHITE_BALANCE_FLUORESCENT; + else if (strcmp(whitebalance_string, "daylight") == 0) + whitebalance = WHITE_BALANCE_SUNNY; + else if (strcmp(whitebalance_string, "cloudy-daylight") == 0) + whitebalance = WHITE_BALANCE_CLOUDY; + else + whitebalance = WHITE_BALANCE_AUTO; + + if (whitebalance != smdk4210_camera->whitebalance || force) { + smdk4210_camera->whitebalance = whitebalance; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_WHITE_BALANCE, whitebalance); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + } + + // Scene mode + scene_mode_string = smdk4210_param_string_get(smdk4210_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, "sports") == 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 + scene_mode = SCENE_MODE_NONE; + + if (scene_mode != smdk4210_camera->scene_mode || force) { + smdk4210_camera->scene_mode = scene_mode; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_SCENE_MODE, scene_mode); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + } + + // Effect + effect_string = smdk4210_param_string_get(smdk4210_camera, "effect"); + if (effect_string != NULL) { + if (strcmp(effect_string, "auto") == 0) + effect = IMAGE_EFFECT_NONE; + else if (strcmp(effect_string, "mono") == 0) + effect = IMAGE_EFFECT_BNW; + else if (strcmp(effect_string, "negative") == 0) + effect = IMAGE_EFFECT_NEGATIVE; + else if (strcmp(effect_string, "sepia") == 0) + effect = IMAGE_EFFECT_SEPIA; + else if (strcmp(effect_string, "aqua") == 0) + effect = IMAGE_EFFECT_AQUA; + else + effect = IMAGE_EFFECT_NONE; + + if (effect != smdk4210_camera->effect || force) { + smdk4210_camera->effect = effect; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EFFECT, effect); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + } + + // ISO + iso_string = smdk4210_param_string_get(smdk4210_camera, "iso"); + if (iso_string != NULL) { + if (strcmp(iso_string, "auto") == 0) + iso = ISO_AUTO; + else if (strcmp(iso_string, "ISO50") == 0) + iso = ISO_50; + else if (strcmp(iso_string, "ISO100") == 0) + iso = ISO_100; + else if (strcmp(iso_string, "ISO200") == 0) + iso = ISO_200; + else if (strcmp(iso_string, "ISO400") == 0) + iso = ISO_400; + else if (strcmp(iso_string, "ISO800") == 0) + iso = ISO_800; + else + iso = ISO_AUTO; + + if (iso != smdk4210_camera->iso || force) { + smdk4210_camera->iso = iso; + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_ISO, iso); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + } + } + + ALOGD("%s: Preview size: %dx%d, picture size: %dx%d, recording size: %dx%d", + __func__, preview_width, preview_height, picture_width, picture_height, + recording_width, recording_height); + + return 0; +} + +// Picture + +int smdk4210_camera_picture(struct smdk4210_camera *smdk4210_camera) +{ + camera_memory_t *data_memory = NULL; + camera_memory_t *exif_data_memory = NULL; + camera_memory_t *picture_data_memory = NULL; + camera_memory_t *jpeg_thumbnail_data_memory = NULL; + + int camera_picture_format; + int picture_width; + int picture_height; + int picture_format; + + int jpeg_thumbnail_width; + int jpeg_thumbnail_height; + int jpeg_thumbnail_quality; + int jpeg_quality; + + int data_size; + + int offset = 0; + void *picture_addr = NULL; + int picture_size = 0; + void *jpeg_thumbnail_addr = NULL; + int jpeg_thumbnail_size = 0; + + int jpeg_fd; + struct jpeg_enc_param jpeg_enc_params; + enum jpeg_frame_format jpeg_in_format; + enum jpeg_stream_format jpeg_out_format; + enum jpeg_ret_type jpeg_result; + void *jpeg_in_buffer; + int jpeg_in_size; + void *jpeg_out_buffer; + int jpeg_out_size; + + exif_attribute_t exif_attributes; + int exif_size = 0; + + int index; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + picture_width = smdk4210_camera->picture_width; + picture_height = smdk4210_camera->picture_height; + picture_format = smdk4210_camera->picture_format; + camera_picture_format = smdk4210_camera->camera_picture_format; + jpeg_thumbnail_width = smdk4210_camera->jpeg_thumbnail_width; + jpeg_thumbnail_height = smdk4210_camera->jpeg_thumbnail_height; + jpeg_thumbnail_quality = smdk4210_camera->jpeg_thumbnail_quality; + jpeg_quality = smdk4210_camera->jpeg_quality; + + if (camera_picture_format == 0) + camera_picture_format = picture_format; + + // V4L2 + + rc = smdk4210_v4l2_poll(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: poll failed!", __func__); + return -1; + } else if (rc == 0) { + ALOGE("%s: poll timeout!", __func__); + return -1; + } + + rc = smdk4210_v4l2_streamoff_cap(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: streamoff failed!", __func__); + return -1; + } + + index = smdk4210_v4l2_dqbuf_cap(smdk4210_camera, 0); + if (index < 0) { + ALOGE("%s: dqbuf failed!", __func__); + return -1; + } + + // This assumes that the output format is JPEG + + if (camera_picture_format == V4L2_PIX_FMT_JPEG) { + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAM_JPEG_MAIN_SIZE, + &picture_size); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAM_JPEG_MAIN_OFFSET, + &offset); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + return -1; + } + + picture_addr = (void *) ((int) smdk4210_camera->picture_memory->data + offset); + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAM_JPEG_THUMB_SIZE, + &jpeg_thumbnail_size); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAM_JPEG_THUMB_OFFSET, + &offset); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + return -1; + } + + jpeg_thumbnail_addr = (void *) ((int) smdk4210_camera->picture_memory->data + offset); + } + + // Thumbnail + + if (camera_picture_format == V4L2_PIX_FMT_JPEG && jpeg_thumbnail_addr != NULL && jpeg_thumbnail_size >= 0) { + if (smdk4210_camera->callbacks.request_memory != NULL) { + jpeg_thumbnail_data_memory = + smdk4210_camera->callbacks.request_memory(-1, + jpeg_thumbnail_size, 1, 0); + if (jpeg_thumbnail_data_memory == NULL) { + ALOGE("%s: thumb memory request failed!", __func__); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + goto error; + } + + memcpy(jpeg_thumbnail_data_memory->data, jpeg_thumbnail_addr, jpeg_thumbnail_size); + } else { + jpeg_fd = api_jpeg_encode_init(); + if (jpeg_fd < 0) { + ALOGE("%s: Failed to init JPEG", __func__); + goto error; + } + + switch (camera_picture_format) { + case V4L2_PIX_FMT_RGB565: + jpeg_in_format = RGB_565; + jpeg_out_format = JPEG_420; + jpeg_in_size = (picture_width * picture_height * 2); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + jpeg_in_format = YUV_420; + jpeg_out_format = JPEG_420; + jpeg_in_size = (picture_width * picture_height * 1.5); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + default: + jpeg_in_format = YUV_422; + jpeg_out_format = JPEG_422; + jpeg_in_size = (picture_width * picture_height * 2); + break; + } + + memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params)); + + jpeg_enc_params.width = jpeg_thumbnail_width; + jpeg_enc_params.height = jpeg_thumbnail_height; + jpeg_enc_params.in_fmt = jpeg_in_format; + jpeg_enc_params.out_fmt = jpeg_out_format; + + if (jpeg_thumbnail_quality >= 90) + jpeg_enc_params.quality = QUALITY_LEVEL_1; + else if (jpeg_thumbnail_quality >= 80) + jpeg_enc_params.quality = QUALITY_LEVEL_2; + else if (jpeg_thumbnail_quality >= 70) + jpeg_enc_params.quality = QUALITY_LEVEL_3; + else + jpeg_enc_params.quality = QUALITY_LEVEL_4; + + api_jpeg_set_encode_param(&jpeg_enc_params); + + jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size); + if (jpeg_in_buffer == NULL) { + ALOGE("%s: Failed to get JPEG in buffer", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd); + if (jpeg_out_buffer == NULL) { + ALOGE("%s: Failed to get JPEG out buffer", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + memcpy(jpeg_in_buffer, smdk4210_camera->picture_memory->data, jpeg_in_size); + + jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params); + if (jpeg_result != JPEG_ENCODE_OK) { + ALOGE("%s: Failed to encode JPEG", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + jpeg_out_size = jpeg_enc_params.size; + if (jpeg_out_size <= 0) { + ALOGE("%s: Failed to get JPEG out size", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + if (smdk4210_camera->callbacks.request_memory != NULL) { + jpeg_thumbnail_data_memory = + smdk4210_camera->callbacks.request_memory(-1, + jpeg_out_size, 1, 0); + if (jpeg_thumbnail_data_memory == NULL) { + ALOGE("%s: thumbnail memory request failed!", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + memcpy(jpeg_thumbnail_data_memory->data, jpeg_out_buffer, jpeg_out_size); + jpeg_thumbnail_size = jpeg_out_size; + + api_jpeg_encode_deinit(jpeg_fd); + } + + // Picture + + if (camera_picture_format == V4L2_PIX_FMT_JPEG && picture_addr != NULL && picture_size >= 0) { + if (smdk4210_camera->callbacks.request_memory != NULL) { + picture_data_memory = + smdk4210_camera->callbacks.request_memory(-1, + picture_size, 1, 0); + if (picture_data_memory == NULL) { + ALOGE("%s: picture memory request failed!", __func__); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + goto error; + } + + memcpy(picture_data_memory->data, picture_addr, picture_size); + } else { + jpeg_fd = api_jpeg_encode_init(); + if (jpeg_fd < 0) { + ALOGE("%s: Failed to init JPEG", __func__); + goto error; + } + + switch (camera_picture_format) { + case V4L2_PIX_FMT_RGB565: + jpeg_in_format = RGB_565; + jpeg_out_format = JPEG_420; + jpeg_in_size = (picture_width * picture_height * 2); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_YUV420: + jpeg_in_format = YUV_420; + jpeg_out_format = JPEG_420; + jpeg_in_size = (picture_width * picture_height * 1.5); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + default: + jpeg_in_format = YUV_422; + jpeg_out_format = JPEG_422; + jpeg_in_size = (picture_width * picture_height * 2); + break; + } + + memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params)); + + jpeg_enc_params.width = picture_width; + jpeg_enc_params.height = picture_height; + jpeg_enc_params.in_fmt = jpeg_in_format; + jpeg_enc_params.out_fmt = jpeg_out_format; + + if (jpeg_quality >= 90) + jpeg_enc_params.quality = QUALITY_LEVEL_1; + else if (jpeg_quality >= 80) + jpeg_enc_params.quality = QUALITY_LEVEL_2; + else if (jpeg_quality >= 70) + jpeg_enc_params.quality = QUALITY_LEVEL_3; + else + jpeg_enc_params.quality = QUALITY_LEVEL_4; + + api_jpeg_set_encode_param(&jpeg_enc_params); + + jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size); + if (jpeg_in_buffer == NULL) { + ALOGE("%s: Failed to get JPEG in buffer", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd); + if (jpeg_out_buffer == NULL) { + ALOGE("%s: Failed to get JPEG out buffer", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + memcpy(jpeg_in_buffer, smdk4210_camera->picture_memory->data, jpeg_in_size); + + jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params); + if (jpeg_result != JPEG_ENCODE_OK) { + ALOGE("%s: Failed to encode JPEG", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + jpeg_out_size = jpeg_enc_params.size; + if (jpeg_out_size <= 0) { + ALOGE("%s: Failed to get JPEG out size", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + if (smdk4210_camera->callbacks.request_memory != NULL) { + picture_data_memory = + smdk4210_camera->callbacks.request_memory(-1, + jpeg_out_size, 1, 0); + if (picture_data_memory == NULL) { + ALOGE("%s: picture memory request failed!", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + api_jpeg_encode_deinit(jpeg_fd); + goto error; + } + + memcpy(picture_data_memory->data, jpeg_out_buffer, jpeg_out_size); + picture_size = jpeg_out_size; + + api_jpeg_encode_deinit(jpeg_fd); + } + + // EXIF + + memset(&exif_attributes, 0, sizeof(exif_attributes)); + smdk4210_exif_attributes_create_static(smdk4210_camera, &exif_attributes); + smdk4210_exif_attributes_create_params(smdk4210_camera, &exif_attributes); + + rc = smdk4210_exif_create(smdk4210_camera, &exif_attributes, + jpeg_thumbnail_data_memory, jpeg_thumbnail_size, + &exif_data_memory, &exif_size); + if (rc < 0 || exif_data_memory == NULL || exif_size <= 0) { + ALOGE("%s: EXIF create failed!", __func__); + goto error; + } + + data_size = exif_size + picture_size; + + if (smdk4210_camera->callbacks.request_memory != NULL) { + data_memory = + smdk4210_camera->callbacks.request_memory(-1, + data_size, 1, 0); + if (data_memory == NULL) { + ALOGE("%s: data memory request failed!", __func__); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + goto error; + } + + // Copy the first two bytes of the JPEG picture + memcpy(data_memory->data, picture_data_memory->data, 2); + + // Copy the EXIF data + memcpy((void *) ((int) data_memory->data + 2), exif_data_memory->data, + exif_size); + + // Copy the JPEG picture + memcpy((void *) ((int) data_memory->data + 2 + exif_size), + (void *) ((int) picture_data_memory->data + 2), picture_size - 2); + + // Callbacks + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_SHUTTER) && SMDK4210_CAMERA_CALLBACK_DEFINED(notify)) + smdk4210_camera->callbacks.notify(CAMERA_MSG_SHUTTER, 0, 0, + smdk4210_camera->callbacks.user); + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && SMDK4210_CAMERA_CALLBACK_DEFINED(data) && + jpeg_thumbnail_data_memory != NULL) + smdk4210_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE, + jpeg_thumbnail_data_memory, 0, NULL, smdk4210_camera->callbacks.user); + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && SMDK4210_CAMERA_CALLBACK_DEFINED(data) && + data_memory != NULL) + smdk4210_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE, + data_memory, 0, NULL, smdk4210_camera->callbacks.user); + + // Release memory + + if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL) + jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory); + + if (picture_data_memory != NULL && picture_data_memory->release != NULL) + picture_data_memory->release(picture_data_memory); + + if (exif_data_memory != NULL && exif_data_memory->release != NULL) + exif_data_memory->release(exif_data_memory); + + if (data_memory != NULL && data_memory->release != NULL) + data_memory->release(data_memory); + + return 0; + +error: + if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL) + jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory); + + if (picture_data_memory != NULL && picture_data_memory->release != NULL) + picture_data_memory->release(picture_data_memory); + + if (exif_data_memory != NULL && exif_data_memory->release != NULL) + exif_data_memory->release(exif_data_memory); + + if (data_memory != NULL && data_memory->release != NULL) + data_memory->release(data_memory); + + return -1; +} + +void *smdk4210_camera_picture_thread(void *data) +{ + struct smdk4210_camera *smdk4210_camera; + int rc; + int i; + + if (data == NULL) + return NULL; + + smdk4210_camera = (struct smdk4210_camera *) data; + + ALOGE("%s: Starting thread", __func__); + smdk4210_camera->picture_thread_running = 1; + + if (smdk4210_camera->picture_enabled == 1) { + pthread_mutex_lock(&smdk4210_camera->picture_mutex); + + rc = smdk4210_camera_picture(smdk4210_camera); + if (rc < 0) { + ALOGE("%s: picture failed!", __func__); + smdk4210_camera->picture_enabled = 0; + } + + if (smdk4210_camera->picture_memory != NULL && smdk4210_camera->picture_memory->release != NULL) { + smdk4210_camera->picture_memory->release(smdk4210_camera->picture_memory); + smdk4210_camera->picture_memory = NULL; + } + + pthread_mutex_unlock(&smdk4210_camera->picture_mutex); + } + + smdk4210_camera->picture_thread_running = 0; + smdk4210_camera->picture_enabled = 0; + + ALOGE("%s: Exiting thread", __func__); + + return NULL; +} + +int smdk4210_camera_picture_start(struct smdk4210_camera *smdk4210_camera) +{ + pthread_attr_t thread_attr; + + int width, height, format, camera_format; + + int fd; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + // Stop preview thread + smdk4210_camera_preview_stop(smdk4210_camera); + + width = smdk4210_camera->picture_width; + height = smdk4210_camera->picture_height; + format = smdk4210_camera->picture_format; + camera_format = smdk4210_camera->camera_picture_format; + + // V4L2 + + if (camera_format == 0) + camera_format = format; + + rc = smdk4210_v4l2_enum_fmt_cap(smdk4210_camera, 0, camera_format); + if (rc < 0) { + ALOGE("%s: enum fmt failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_fmt_pix_cap(smdk4210_camera, 0, width, height, camera_format, V4L2_PIX_FMT_MODE_CAPTURE); + if (rc < 0) { + ALOGE("%s: s fmt failed!", __func__); + return -1; + } + + // Only use 1 buffer + rc = smdk4210_v4l2_reqbufs_cap(smdk4210_camera, 0, 1); + if (rc < 0) { + ALOGE("%s: reqbufs failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_querybuf_cap(smdk4210_camera, 0, 0); + if (rc < 0) { + ALOGE("%s: querybuf failed!", __func__); + return -1; + } + + smdk4210_camera->picture_buffer_length = rc; + + if (smdk4210_camera->callbacks.request_memory != NULL) { + fd = smdk4210_v4l2_find_fd(smdk4210_camera, 0); + if (fd < 0) { + ALOGE("%s: Unable to find v4l2 fd", __func__); + return -1; + } + + if (smdk4210_camera->picture_memory != NULL && smdk4210_camera->picture_memory->release != NULL) + smdk4210_camera->picture_memory->release(smdk4210_camera->picture_memory); + + smdk4210_camera->picture_memory = + smdk4210_camera->callbacks.request_memory(fd, + smdk4210_camera->picture_buffer_length, 1, 0); + if (smdk4210_camera->picture_memory == NULL) { + ALOGE("%s: memory request failed!", __func__); + return -1; + } + } else { + ALOGE("%s: No memory request function!", __func__); + return -1; + } + + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 0, 0); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_streamon_cap(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: streamon failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_CAPTURE, 0); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + return -1; + } + + // Thread + + if (smdk4210_camera->picture_thread_running) { + ALOGE("Picture thread is already running!"); + return -1; + } + + pthread_mutex_init(&smdk4210_camera->picture_mutex, NULL); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + + smdk4210_camera->picture_enabled = 1; + + rc = pthread_create(&smdk4210_camera->picture_thread, &thread_attr, + smdk4210_camera_picture_thread, (void *) smdk4210_camera); + if (rc < 0) { + ALOGE("%s: Unable to create thread", __func__); + return -1; + } + + return 0; +} + +void smdk4210_camera_picture_stop(struct smdk4210_camera *smdk4210_camera) +{ + int rc; + int i; + + if (smdk4210_camera == NULL) + return; + + if (!smdk4210_camera->picture_enabled) { + ALOGE("Picture was already stopped!"); + return; + } + + pthread_mutex_lock(&smdk4210_camera->picture_mutex); + + // Disable picture to make the thread end + smdk4210_camera->picture_enabled = 0; + + pthread_mutex_unlock(&smdk4210_camera->picture_mutex); + + // Wait for the thread to end + for (i = 0; i < 10; i++) { + if (!smdk4210_camera->picture_thread_running) + break; + + usleep(500); + } + + pthread_mutex_destroy(&smdk4210_camera->picture_mutex); +} + +// Auto-focus + +void *smdk4210_camera_auto_focus_thread(void *data) +{ + struct smdk4210_camera *smdk4210_camera; + int auto_focus_status = -1; + int auto_focus_result = 0; + int rc; + int i; + + if (data == NULL) + return NULL; + + smdk4210_camera = (struct smdk4210_camera *) data; + + ALOGE("%s: Starting thread", __func__); + smdk4210_camera->auto_focus_thread_running = 1; + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_ON); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + auto_focus_result = 0; + goto thread_exit; + } + + while (smdk4210_camera->auto_focus_enabled == 1) { + pthread_mutex_lock(&smdk4210_camera->auto_focus_mutex); + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT, &auto_focus_status); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + auto_focus_result = 0; + pthread_mutex_unlock(&smdk4210_camera->auto_focus_mutex); + goto thread_exit; + } + + if (auto_focus_status & M5MO_AF_STATUS_IN_PROGRESS) { + usleep(10000); + } else if (auto_focus_status == M5MO_AF_STATUS_SUCCESS || auto_focus_status == M5MO_AF_STATUS_1ST_SUCCESS) { + auto_focus_result = 1; + pthread_mutex_unlock(&smdk4210_camera->auto_focus_mutex); + goto thread_exit; + } else { + auto_focus_result = 0; + pthread_mutex_unlock(&smdk4210_camera->auto_focus_mutex); + goto thread_exit; + } + + pthread_mutex_unlock(&smdk4210_camera->auto_focus_mutex); + } + +thread_exit: + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF); + if (rc < 0) + ALOGE("%s: s ctrl failed!", __func__); + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && SMDK4210_CAMERA_CALLBACK_DEFINED(notify)) + smdk4210_camera->callbacks.notify(CAMERA_MSG_FOCUS, + (int32_t) auto_focus_result, 0, smdk4210_camera->callbacks.user); + + smdk4210_camera->auto_focus_thread_running = 0; + smdk4210_camera->auto_focus_enabled = 0; + + ALOGE("%s: Exiting thread", __func__); + + return NULL; +} + +int smdk4210_camera_auto_focus_start(struct smdk4210_camera *smdk4210_camera) +{ + pthread_attr_t thread_attr; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + // Thread + + if (smdk4210_camera->auto_focus_thread_running) { + ALOGE("Auto-focus thread is already running!"); + return -1; + } + + pthread_mutex_init(&smdk4210_camera->auto_focus_mutex, NULL); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + + smdk4210_camera->auto_focus_enabled = 1; + + rc = pthread_create(&smdk4210_camera->auto_focus_thread, &thread_attr, + smdk4210_camera_auto_focus_thread, (void *) smdk4210_camera); + if (rc < 0) { + ALOGE("%s: Unable to create thread", __func__); + return -1; + } + + return 0; +} + +void smdk4210_camera_auto_focus_stop(struct smdk4210_camera *smdk4210_camera) +{ + int rc; + int i; + + if (smdk4210_camera == NULL) + return; + + if (!smdk4210_camera->auto_focus_enabled) { + ALOGE("Auto-focus was already stopped!"); + return; + } + + pthread_mutex_lock(&smdk4210_camera->auto_focus_mutex); + + // Disable auto-focus to make the thread end + smdk4210_camera->auto_focus_enabled = 0; + + pthread_mutex_unlock(&smdk4210_camera->auto_focus_mutex); + + // Wait for the thread to end + for (i = 0; i < 10; i++) { + if (!smdk4210_camera->auto_focus_thread_running) + break; + + usleep(500); + } + + pthread_mutex_destroy(&smdk4210_camera->auto_focus_mutex); +} + +// Preview + +int smdk4210_camera_preview(struct smdk4210_camera *smdk4210_camera) +{ + buffer_handle_t *buffer; + int stride; + + int width, height; + float format_bpp; + + char *preview_format_string; + int frame_size, offset; + void *preview_data; + void *window_data; + + unsigned int recording_y_addr; + unsigned int recording_cbcr_addr; + nsecs_t timestamp; + struct smdk4210_camera_addrs *addrs; + struct timespec ts; + + int index; + int rc; + int i; + + if (smdk4210_camera == NULL || smdk4210_camera->preview_memory == NULL || + smdk4210_camera->preview_window == NULL) + return -EINVAL; + + timestamp = systemTime(1); + + // V4L2 + + rc = smdk4210_v4l2_poll(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: poll failed!", __func__); + return -1; + } else if (rc == 0) { + ALOGE("%s: poll timeout!", __func__); + return -1; + } + + index = smdk4210_v4l2_dqbuf_cap(smdk4210_camera, 0); + if (index < 0 || index >= smdk4210_camera->preview_buffers_count) { + ALOGE("%s: dqbuf failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 0, index); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + return -1; + } + + // Preview window + + width = smdk4210_camera->preview_width; + height = smdk4210_camera->preview_height; + format_bpp = smdk4210_camera->preview_format_bpp; + + smdk4210_camera->preview_window->dequeue_buffer(smdk4210_camera->preview_window, + &buffer, &stride); + smdk4210_camera->gralloc->lock(smdk4210_camera->gralloc, *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, + 0, 0, width, height, &window_data); + + if (window_data == NULL) { + ALOGE("%s: gralloc lock failed!", __func__); + return -1; + } + + frame_size = smdk4210_camera->preview_frame_size; + offset = index * frame_size; + + preview_data = (void *) ((int) smdk4210_camera->preview_memory->data + offset); + memcpy(window_data, preview_data, frame_size); + + smdk4210_camera->gralloc->unlock(smdk4210_camera->gralloc, *buffer); + smdk4210_camera->preview_window->enqueue_buffer(smdk4210_camera->preview_window, + buffer); + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_PREVIEW_FRAME) && SMDK4210_CAMERA_CALLBACK_DEFINED(data)) { + smdk4210_camera->callbacks.data(CAMERA_MSG_PREVIEW_FRAME, + smdk4210_camera->preview_memory, index, NULL, smdk4210_camera->callbacks.user); + } + + // Recording + + if (smdk4210_camera->recording_enabled && smdk4210_camera->recording_memory != NULL) { + pthread_mutex_lock(&smdk4210_camera->recording_mutex); + + // V4L2 + + rc = smdk4210_v4l2_poll(smdk4210_camera, 2); + if (rc < 0) { + ALOGE("%s: poll failed!", __func__); + goto error_recording; + } else if (rc == 0) { + ALOGE("%s: poll timeout!", __func__); + goto error_recording; + } + + index = smdk4210_v4l2_dqbuf_cap(smdk4210_camera, 2); + if (index < 0) { + ALOGE("%s: dqbuf failed!", __func__); + goto error_recording; + } + + recording_y_addr = smdk4210_v4l2_s_ctrl(smdk4210_camera, 2, V4L2_CID_PADDR_Y, index); + if (recording_y_addr == 0xffffffff) { + ALOGE("%s: s ctrl failed!", __func__); + goto error_recording; + } + + recording_cbcr_addr = smdk4210_v4l2_s_ctrl(smdk4210_camera, 2, V4L2_CID_PADDR_CBCR, index); + if (recording_cbcr_addr == 0xffffffff) { + ALOGE("%s: s ctrl failed!", __func__); + goto error_recording; + } + + addrs = (struct smdk4210_camera_addrs *) smdk4210_camera->recording_memory->data; + + addrs[index].type = 0; // kMetadataBufferTypeCameraSource + addrs[index].y = recording_y_addr; + addrs[index].cbcr = recording_cbcr_addr; + addrs[index].index = index; + addrs[index].reserved = 0; + + pthread_mutex_unlock(&smdk4210_camera->recording_mutex); + + if (SMDK4210_CAMERA_MSG_ENABLED(CAMERA_MSG_VIDEO_FRAME) && SMDK4210_CAMERA_CALLBACK_DEFINED(data_timestamp)) { + smdk4210_camera->callbacks.data_timestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, + smdk4210_camera->recording_memory, index, smdk4210_camera->callbacks.user); + } else { + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 2, index); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + return -1; + } + } + } + + return 0; + +error_recording: + pthread_mutex_lock(&smdk4210_camera->recording_mutex); + + return -1; +} + +void *smdk4210_camera_preview_thread(void *data) +{ + struct smdk4210_camera *smdk4210_camera; + int rc; + + if (data == NULL) + return NULL; + + smdk4210_camera = (struct smdk4210_camera *) data; + + ALOGE("%s: Starting thread", __func__); + smdk4210_camera->preview_thread_running = 1; + + if (smdk4210_camera->preview_window == NULL) { + // Lock preview lock mutex + pthread_mutex_lock(&smdk4210_camera->preview_lock_mutex); + } + + while (smdk4210_camera->preview_enabled == 1) { + pthread_mutex_lock(&smdk4210_camera->preview_mutex); + + rc = smdk4210_camera_preview(smdk4210_camera); + if (rc < 0) { + ALOGE("%s: preview failed!", __func__); + smdk4210_camera->preview_enabled = 0; + } + + pthread_mutex_unlock(&smdk4210_camera->preview_mutex); + } + + smdk4210_camera->preview_thread_running = 0; + ALOGE("%s: Exiting thread", __func__); + + return NULL; +} + +int smdk4210_camera_preview_start(struct smdk4210_camera *smdk4210_camera) +{ + struct v4l2_streamparm streamparm; + int width, height, format; + float format_bpp; + int fps, frame_size; + int fd; + + pthread_attr_t thread_attr; + + int rc; + int i; + + if (smdk4210_camera == NULL) + return -EINVAL; + + if (smdk4210_camera->preview_enabled) { + ALOGE("Preview was already started!"); + return 0; + } + + // V4L2 + + format = smdk4210_camera->preview_format; + + rc = smdk4210_v4l2_enum_fmt_cap(smdk4210_camera, 0, format); + if (rc < 0) { + ALOGE("%s: enum fmt failed!", __func__); + return -1; + } + + width = smdk4210_camera->preview_width; + height = smdk4210_camera->preview_height; + format_bpp = smdk4210_camera->preview_format_bpp; + + rc = smdk4210_v4l2_s_fmt_pix_cap(smdk4210_camera, 0, width, height, format, V4L2_PIX_FMT_MODE_PREVIEW); + if (rc < 0) { + ALOGE("%s: s fmt failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_CACHEABLE, 1); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + return -1; + } + + for (i = SMDK4210_CAMERA_MAX_BUFFERS_COUNT; i >= SMDK4210_CAMERA_MIN_BUFFERS_COUNT; i--) { + rc = smdk4210_v4l2_reqbufs_cap(smdk4210_camera, 0, i); + if (rc >= 0) + break; + } + + if (rc < 0) { + ALOGE("%s: reqbufs failed!", __func__); + return -1; + } + + smdk4210_camera->preview_buffers_count = rc; + ALOGD("Found %d preview buffers available!", smdk4210_camera->preview_buffers_count); + + fps = smdk4210_camera->preview_fps; + memset(&streamparm, 0, sizeof(streamparm)); + streamparm.parm.capture.timeperframe.numerator = 1; + streamparm.parm.capture.timeperframe.denominator = fps; + + rc = smdk4210_v4l2_s_parm_cap(smdk4210_camera, 0, &streamparm); + if (rc < 0) { + ALOGE("%s: s parm failed!", __func__); + return -1; + } + + frame_size = (int) ((float) width * (float) height * format_bpp); + for (i = 0; i < smdk4210_camera->preview_buffers_count; i++) { + rc = smdk4210_v4l2_querybuf_cap(smdk4210_camera, 0, i); + if (rc < 0) { + ALOGE("%s: querybuf failed!", __func__); + return -1; + } + + if (rc < frame_size) { + ALOGE("%s: problematic frame size: %d/%d", __func__, rc, frame_size); + return -1; + } + } + + frame_size = rc; + smdk4210_camera->preview_frame_size = frame_size; + + if (smdk4210_camera->callbacks.request_memory != NULL) { + fd = smdk4210_v4l2_find_fd(smdk4210_camera, 0); + if (fd < 0) { + ALOGE("%s: Unable to find v4l2 fd", __func__); + return -1; + } + + if (smdk4210_camera->preview_memory != NULL && smdk4210_camera->preview_memory->release != NULL) + smdk4210_camera->preview_memory->release(smdk4210_camera->preview_memory); + + smdk4210_camera->preview_memory = + smdk4210_camera->callbacks.request_memory(fd, + frame_size, smdk4210_camera->preview_buffers_count, 0); + if (smdk4210_camera->preview_memory == NULL) { + ALOGE("%s: memory request failed!", __func__); + return -1; + } + } else { + ALOGE("%s: No memory request function!", __func__); + return -1; + } + + for (i = 0; i < smdk4210_camera->preview_buffers_count; i++) { + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 0, i); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + return -1; + } + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_ROTATION, + smdk4210_camera->camera_rotation); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_HFLIP, + smdk4210_camera->camera_hflip); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 0, V4L2_CID_VFLIP, + smdk4210_camera->camera_vflip); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + return -1; + } + + rc = smdk4210_v4l2_streamon_cap(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: streamon failed!", __func__); + return -1; + } + + // Thread + + pthread_mutex_init(&smdk4210_camera->preview_mutex, NULL); + pthread_mutex_init(&smdk4210_camera->preview_lock_mutex, NULL); + + // Lock preview lock + pthread_mutex_lock(&smdk4210_camera->preview_lock_mutex); + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + + smdk4210_camera->preview_enabled = 1; + + rc = pthread_create(&smdk4210_camera->preview_thread, &thread_attr, + smdk4210_camera_preview_thread, (void *) smdk4210_camera); + if (rc < 0) { + ALOGE("%s: Unable to create thread", __func__); + return -1; + } + + return 0; +} + +void smdk4210_camera_preview_stop(struct smdk4210_camera *smdk4210_camera) +{ + int rc; + int i; + + if (smdk4210_camera == NULL) + return; + + if (!smdk4210_camera->preview_enabled) { + ALOGE("Preview was already stopped!"); + return; + } + + smdk4210_camera->preview_enabled = 0; + + // Unlock preview lock + pthread_mutex_unlock(&smdk4210_camera->preview_lock_mutex); + + pthread_mutex_lock(&smdk4210_camera->preview_mutex); + + // Wait for the thread to end + for (i = 0; i < 10; i++) { + if (!smdk4210_camera->preview_thread_running) + break; + + usleep(1000); + } + + rc = smdk4210_v4l2_streamoff_cap(smdk4210_camera, 0); + if (rc < 0) { + ALOGE("%s: streamoff failed!", __func__); + } + + smdk4210_camera->preview_params_set = 0; + + if (smdk4210_camera->preview_memory != NULL && smdk4210_camera->preview_memory->release != NULL) { + smdk4210_camera->preview_memory->release(smdk4210_camera->preview_memory); + smdk4210_camera->preview_memory = NULL; + } + + smdk4210_camera->preview_window = NULL; + + pthread_mutex_unlock(&smdk4210_camera->preview_mutex); + + pthread_mutex_destroy(&smdk4210_camera->preview_lock_mutex); + pthread_mutex_destroy(&smdk4210_camera->preview_mutex); +} + +// Recording + +void smdk4210_camera_recording_frame_release(struct smdk4210_camera *smdk4210_camera, void *data) +{ + struct smdk4210_camera_addrs *addrs; + int rc; + + if (smdk4210_camera == NULL || data == NULL) + return; + + addrs = (struct smdk4210_camera_addrs *) data; + if (addrs->index >= (unsigned int) smdk4210_camera->recording_buffers_count) + return; + + pthread_mutex_lock(&smdk4210_camera->recording_mutex); + + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 2, addrs->index); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + goto error; + } + +error: + pthread_mutex_unlock(&smdk4210_camera->recording_mutex); +} + +int smdk4210_camera_recording_start(struct smdk4210_camera *smdk4210_camera) +{ + int width, height, format; + int fd; + + int rc; + int i; + + if (smdk4210_camera == NULL) + return -EINVAL; + + if (smdk4210_camera->recording_enabled) { + ALOGE("Recording was already started!"); + return 0; + } + + pthread_mutex_lock(&smdk4210_camera->preview_mutex); + + // V4L2 + + format = smdk4210_camera->recording_format; + + rc = smdk4210_v4l2_enum_fmt_cap(smdk4210_camera, 2, format); + if (rc < 0) { + ALOGE("%s: enum fmt failed!", __func__); + goto error; + } + + width = smdk4210_camera->recording_width; + height = smdk4210_camera->recording_height; + + rc = smdk4210_v4l2_s_fmt_pix_cap(smdk4210_camera, 2, width, height, format, V4L2_PIX_FMT_MODE_CAPTURE); + if (rc < 0) { + ALOGE("%s: s fmt failed!", __func__); + goto error; + } + + for (i = SMDK4210_CAMERA_MAX_BUFFERS_COUNT; i >= SMDK4210_CAMERA_MIN_BUFFERS_COUNT; i--) { + rc = smdk4210_v4l2_reqbufs_cap(smdk4210_camera, 2, i); + if (rc >= 0) + break; + } + + if (rc < 0) { + ALOGE("%s: reqbufs failed!", __func__); + goto error; + } + + smdk4210_camera->recording_buffers_count = rc; + ALOGD("Found %d recording buffers available!", smdk4210_camera->recording_buffers_count); + + for (i = 0; i < smdk4210_camera->recording_buffers_count; i++) { + rc = smdk4210_v4l2_querybuf_cap(smdk4210_camera, 2, i); + if (rc < 0) { + ALOGE("%s: querybuf failed!", __func__); + goto error; + } + } + + if (smdk4210_camera->callbacks.request_memory != NULL) { + if (smdk4210_camera->recording_memory != NULL && smdk4210_camera->recording_memory->release != NULL) + smdk4210_camera->recording_memory->release(smdk4210_camera->recording_memory); + + smdk4210_camera->recording_memory = + smdk4210_camera->callbacks.request_memory(-1, sizeof(struct smdk4210_camera_addrs), + smdk4210_camera->recording_buffers_count, 0); + if (smdk4210_camera->recording_memory == NULL) { + ALOGE("%s: memory request failed!", __func__); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + goto error; + } + + for (i = 0; i < smdk4210_camera->recording_buffers_count; i++) { + rc = smdk4210_v4l2_qbuf_cap(smdk4210_camera, 2, i); + if (rc < 0) { + ALOGE("%s: qbuf failed!", __func__); + goto error; + } + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 2, V4L2_CID_ROTATION, + smdk4210_camera->camera_rotation); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + goto error; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 2, V4L2_CID_HFLIP, + smdk4210_camera->camera_hflip); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + goto error; + } + + rc = smdk4210_v4l2_s_ctrl(smdk4210_camera, 2, V4L2_CID_VFLIP, + smdk4210_camera->camera_vflip); + if (rc < 0) { + ALOGE("%s: s ctrl failed!", __func__); + goto error; + } + + rc = smdk4210_v4l2_streamon_cap(smdk4210_camera, 2); + if (rc < 0) { + ALOGE("%s: streamon failed!", __func__); + goto error; + } + + pthread_mutex_init(&smdk4210_camera->recording_mutex, NULL); + + smdk4210_camera->recording_enabled = 1; + + pthread_mutex_unlock(&smdk4210_camera->preview_mutex); + + return 0; +error: + pthread_mutex_unlock(&smdk4210_camera->preview_mutex); + + return -1; +} + +void smdk4210_camera_recording_stop(struct smdk4210_camera *smdk4210_camera) +{ + int rc; + + if (smdk4210_camera == NULL) + return; + + if (!smdk4210_camera->recording_enabled) { + ALOGE("Recording was already stopped!"); + return; + } + + smdk4210_camera->recording_enabled = 0; + + pthread_mutex_lock(&smdk4210_camera->preview_mutex); + + rc = smdk4210_v4l2_streamoff_cap(smdk4210_camera, 2); + if (rc < 0) { + ALOGE("%s: streamoff failed!", __func__); + } + + if (smdk4210_camera->recording_memory != NULL && smdk4210_camera->recording_memory->release != NULL) { + smdk4210_camera->recording_memory->release(smdk4210_camera->recording_memory); + smdk4210_camera->recording_memory = NULL; + } + + pthread_mutex_unlock(&smdk4210_camera->preview_mutex); + + pthread_mutex_destroy(&smdk4210_camera->recording_mutex); +} + +/* + * SMDK4210 Camera OPS + */ + +int smdk4210_camera_set_preview_window(struct camera_device *dev, + struct preview_stream_ops *w) +{ + struct smdk4210_camera *smdk4210_camera; + + int width, height, format, hal_format; + + buffer_handle_t *buffer; + int stride; + void *addr = NULL; + + int rc; + + ALOGD("%s(%p, %p)", __func__, dev, w); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + if (w == NULL) + return 0; + + smdk4210_camera->preview_window = w; + + if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL) + return -EINVAL; + + if (smdk4210_camera->preview_buffers_count <= 0) { + ALOGE("%s: Invalid preview buffers count", __func__); + smdk4210_camera->preview_buffers_count = SMDK4210_CAMERA_MAX_BUFFERS_COUNT; + } + + rc = w->set_buffer_count(w, smdk4210_camera->preview_buffers_count); + if (rc) { + ALOGE("%s: Unable to set buffer count (%d)", __func__, + smdk4210_camera->preview_buffers_count); + return -1; + } + + rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN); + if (rc) { + ALOGE("%s: Unable to set usage", __func__); + return -1; + } + + width = smdk4210_camera->preview_width; + height = smdk4210_camera->preview_height; + format = smdk4210_camera->preview_format; + + switch (format) { + case V4L2_PIX_FMT_NV21: + hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; + break; + case V4L2_PIX_FMT_YUV420: + hal_format = HAL_PIXEL_FORMAT_YV12; + break; + case V4L2_PIX_FMT_RGB565: + hal_format = HAL_PIXEL_FORMAT_RGB_565; + break; + case V4L2_PIX_FMT_RGB32: + hal_format = HAL_PIXEL_FORMAT_RGBX_8888; + break; + default: + hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; + break; + } + + rc = w->set_buffers_geometry(w, width, height, hal_format); + if (rc) { + ALOGE("%s: Unable to set buffers geometry", __func__); + return -1; + } + + // Unlock preview lock + pthread_mutex_unlock(&smdk4210_camera->preview_lock_mutex); + + return 0; +} + +void smdk4210_camera_set_callbacks(struct camera_device *dev, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p, %p)", __func__, dev, user); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera->callbacks.notify = notify_cb; + smdk4210_camera->callbacks.data = data_cb; + smdk4210_camera->callbacks.data_timestamp = data_cb_timestamp; + smdk4210_camera->callbacks.request_memory = get_memory; + smdk4210_camera->callbacks.user = user; +} + +void smdk4210_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p, %d)", __func__, dev, msg_type); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera->messages_enabled |= msg_type; +} + +void smdk4210_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p, %d)", __func__, dev, msg_type); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera->messages_enabled &= ~msg_type; +} + +int smdk4210_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p, %d)", __func__, dev, msg_type); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera->messages_enabled & msg_type; +} + +int smdk4210_camera_start_preview(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera_preview_start(smdk4210_camera); +} + +void smdk4210_camera_stop_preview(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera_preview_stop(smdk4210_camera); +} + +int smdk4210_camera_preview_enabled(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera->preview_enabled; +} + +int smdk4210_camera_store_meta_data_in_buffers(struct camera_device *dev, + int enable) +{ + ALOGD("%s(%p, %d)", __func__, dev, enable); + + if (!enable) { + ALOGE("%s: Cannot disable meta-data in buffers!", __func__); + return -1; + } + + return 0; +} + +int smdk4210_camera_start_recording(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera_recording_start(smdk4210_camera); +} + +void smdk4210_camera_stop_recording(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera_recording_stop(smdk4210_camera); +} + +int smdk4210_camera_recording_enabled(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera->recording_enabled; +} + +void smdk4210_camera_release_recording_frame(struct camera_device *dev, + const void *opaque) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGV("%s(%p, %p)", __func__, dev, opaque); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera_recording_frame_release(smdk4210_camera, (void *) opaque); +} + +int smdk4210_camera_auto_focus(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera_auto_focus_start(smdk4210_camera); +} + +int smdk4210_camera_cancel_auto_focus(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera_auto_focus_stop(smdk4210_camera); + + return 0; +} + +int smdk4210_camera_take_picture(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + return smdk4210_camera_picture_start(smdk4210_camera); +} + +int smdk4210_camera_cancel_picture(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + smdk4210_camera_picture_stop(smdk4210_camera); + + return 0; +} + +int smdk4210_camera_set_parameters(struct camera_device *dev, + const char *params) +{ + struct smdk4210_camera *smdk4210_camera; + int rc; + + ALOGD("%s(%p, %s)", __func__, dev, params); + + if (dev == NULL || dev->priv == NULL || params == NULL) + return -EINVAL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + rc = smdk4210_params_string_set(smdk4210_camera, (char *) params); + if (rc < 0) { + ALOGE("%s: Unable to set params string", __func__); + return -1; + } + + rc = smdk4210_camera_params_apply(smdk4210_camera); + if (rc < 0) { + ALOGE("%s: Unable to apply params", __func__); + return -1; + } + + return 0; +} + +char *smdk4210_camera_get_parameters(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + char *params; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return NULL; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + params = smdk4210_params_string_get(smdk4210_camera); + if (params == NULL) { + ALOGE("%s: Couldn't find any param", __func__); + return strdup(""); + } + + return params; +} + +void smdk4210_camera_put_parameters(struct camera_device *dev, char *params) +{ + ALOGD("%s(%p)", __func__, dev); + + if (params != NULL) + free(params); +} + +int smdk4210_camera_send_command(struct camera_device *dev, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + ALOGD("%s(%p, %d, %d, %d)", __func__, dev, cmd, arg1, arg2); + + return 0; +} + +void smdk4210_camera_release(struct camera_device *dev) +{ + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, dev); + + if (dev == NULL || dev->priv == NULL) + return; + + smdk4210_camera = (struct smdk4210_camera *) dev->priv; + + if (smdk4210_camera->preview_memory != NULL && smdk4210_camera->preview_memory->release != NULL) { + smdk4210_camera->preview_memory->release(smdk4210_camera->preview_memory); + smdk4210_camera->preview_memory = NULL; + } + + if (smdk4210_camera->picture_memory != NULL && smdk4210_camera->picture_memory->release != NULL) { + smdk4210_camera->picture_memory->release(smdk4210_camera->picture_memory); + smdk4210_camera->picture_memory = NULL; + } + + smdk4210_camera_deinit(smdk4210_camera); +} + +int smdk4210_camera_dump(struct camera_device *dev, int fd) +{ + ALOGD("%s(%p, %d)", __func__, dev, fd); + + return 0; +} + +/* + * Interface + */ + +struct camera_device_ops smdk4210_camera_ops = { + .set_preview_window = smdk4210_camera_set_preview_window, + .set_callbacks = smdk4210_camera_set_callbacks, + .enable_msg_type = smdk4210_camera_enable_msg_type, + .disable_msg_type = smdk4210_camera_disable_msg_type, + .msg_type_enabled = smdk4210_camera_msg_type_enabled, + .start_preview = smdk4210_camera_start_preview, + .stop_preview = smdk4210_camera_stop_preview, + .preview_enabled = smdk4210_camera_preview_enabled, + .store_meta_data_in_buffers = smdk4210_camera_store_meta_data_in_buffers, + .start_recording = smdk4210_camera_start_recording, + .stop_recording = smdk4210_camera_stop_recording, + .recording_enabled = smdk4210_camera_recording_enabled, + .release_recording_frame = smdk4210_camera_release_recording_frame, + .auto_focus = smdk4210_camera_auto_focus, + .cancel_auto_focus = smdk4210_camera_cancel_auto_focus, + .take_picture = smdk4210_camera_take_picture, + .cancel_picture = smdk4210_camera_cancel_picture, + .set_parameters = smdk4210_camera_set_parameters, + .get_parameters = smdk4210_camera_get_parameters, + .put_parameters = smdk4210_camera_put_parameters, + .send_command = smdk4210_camera_send_command, + .release = smdk4210_camera_release, + .dump = smdk4210_camera_dump, +}; + +int smdk4210_camera_close(hw_device_t *device) +{ + struct camera_device *camera_device; + struct smdk4210_camera *smdk4210_camera; + + ALOGD("%s(%p)", __func__, device); + + if (device == NULL) + return -EINVAL; + + camera_device = (struct camera_device *) device; + + if (camera_device->priv != NULL) { + free(camera_device->priv); + } + + free(camera_device); + + return 0; +} + +int smdk4210_camera_open(const struct hw_module_t* module, const char *camera_id, + struct hw_device_t** device) +{ + struct camera_device *camera_device = NULL; + struct smdk4210_camera *smdk4210_camera = NULL; + int id; + int rc; + + ALOGD("%s(%p, %s, %p)", __func__, module, camera_id, device); + + if (module == NULL || camera_id == NULL || device == NULL) + return -EINVAL; + + id = atoi(camera_id); + if (id < 0) + return -EINVAL; + + smdk4210_camera = calloc(1, sizeof(struct smdk4210_camera)); + smdk4210_camera->config = smdk4210_camera_config; + + if (smdk4210_camera->config->presets_count > SMDK4210_CAMERA_MAX_PRESETS_COUNT || + smdk4210_camera->config->v4l2_nodes_count > SMDK4210_CAMERA_MAX_V4L2_NODES_COUNT) + goto error_preset; + + if (id >= smdk4210_camera->config->presets_count) + goto error_preset; + + rc = smdk4210_camera_init(smdk4210_camera, id); + if (rc < 0) { + ALOGE("%s: Unable to init camera", __func__); + goto error; + } + + camera_device = calloc(1, sizeof(struct camera_device)); + camera_device->common.tag = HARDWARE_DEVICE_TAG; + camera_device->common.version = 0; + camera_device->common.module = (struct hw_module_t *) module; + camera_device->common.close = smdk4210_camera_close; + + camera_device->ops = &smdk4210_camera_ops; + camera_device->priv = smdk4210_camera; + + *device = (struct hw_device_t *) &(camera_device->common); + + return 0; + +error: + smdk4210_camera_deinit(smdk4210_camera); + +error_device: + if (camera_device != NULL) + free(camera_device); + +error_preset: + if (smdk4210_camera != NULL) + free(smdk4210_camera); + + return -1; +} + +int smdk4210_camera_get_number_of_cameras(void) +{ + ALOGD("%s()", __func__); + + if (smdk4210_camera_config == NULL || smdk4210_camera_config->presets == NULL) { + ALOGE("%s: Unable to find proper camera config", __func__); + return -1; + } + + return smdk4210_camera_config->presets_count; +} + +int smdk4210_camera_get_camera_info(int id, struct camera_info *info) +{ + ALOGD("%s(%d, %p)", __func__, id, info); + + if (id < 0 || info == NULL) + return -EINVAL; + + if (smdk4210_camera_config == NULL || smdk4210_camera_config->presets == NULL) { + ALOGE("%s: Unable to find proper camera config", __func__); + return -1; + } + + if (id >= smdk4210_camera_config->presets_count) + return -EINVAL; + + ALOGD("Selected camera: %s", smdk4210_camera_config->presets[id].name); + + info->facing = smdk4210_camera_config->presets[id].facing; + info->orientation = smdk4210_camera_config->presets[id].orientation; + + return 0; +} + +struct hw_module_methods_t smdk4210_camera_module_methods = { + .open = smdk4210_camera_open, +}; + +struct camera_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .module_api_version = CAMERA_MODULE_API_VERSION_1_0, + .id = CAMERA_HARDWARE_MODULE_ID, + .name = "SMDK4210 Camera", + .author = "Paul Kocialkowski", + .methods = &smdk4210_camera_module_methods, + }, + .get_number_of_cameras = smdk4210_camera_get_number_of_cameras, + .get_camera_info = smdk4210_camera_get_camera_info, +}; diff --git a/camera/smdk4210_camera.h b/camera/smdk4210_camera.h new file mode 100644 index 0000000..e6cf911 --- /dev/null +++ b/camera/smdk4210_camera.h @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#ifndef _SMDK4210_CAMERA_H_ +#define _SMDK4210_CAMERA_H_ + +#define SMDK4210_CAMERA_MAX_PRESETS_COUNT 2 +#define SMDK4210_CAMERA_MAX_V4L2_NODES_COUNT 4 +#define SMDK4210_CAMERA_MIN_BUFFERS_COUNT 3 +#define SMDK4210_CAMERA_MAX_BUFFERS_COUNT 8 + +#define SMDK4210_CAMERA_MSG_ENABLED(msg) \ + (smdk4210_camera->messages_enabled & msg) +#define SMDK4210_CAMERA_CALLBACK_DEFINED(cb) \ + (smdk4210_camera->callbacks.cb != NULL) + +/* + * Structures + */ + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +enum smdk4210_param_type { + SMDK4210_PARAM_INT, + SMDK4210_PARAM_FLOAT, + SMDK4210_PARAM_STRING, +}; + +union smdk4210_param_data { + int integer; + float floating; + char *string; +}; + +struct smdk4210_param { + struct list_head list; + + char *key; + union smdk4210_param_data data; + enum smdk4210_param_type type; +}; + +struct smdk4210_camera_params { + char *preview_size_values; + char *preview_size; + char *preview_format_values; + char *preview_format; + char *preview_frame_rate_values; + int preview_frame_rate; + char *preview_fps_range_values; + char *preview_fps_range; + + char *picture_size_values; + char *picture_size; + char *picture_format_values; + char *picture_format; + char *jpeg_thumbnail_size_values; + int jpeg_thumbnail_width; + int jpeg_thumbnail_height; + int jpeg_thumbnail_quality; + int jpeg_quality; + + char *recording_size; + char *recording_size_values; + char *recording_format; + + char *focus_mode; + char *focus_mode_values; + char *focus_distances; + char *focus_areas; + int max_num_focus_areas; + + int zoom_supported; + int smooth_zoom_supported; + char *zoom_ratios; + int zoom; + int max_zoom; + + char *flash_mode; + char *flash_mode_values; + + int exposure_compensation; + float exposure_compensation_step; + int min_exposure_compensation; + int max_exposure_compensation; + + char *whitebalance; + char *whitebalance_values; + + char *scene_mode; + char *scene_mode_values; + + char *effect; + char *effect_values; + + char *iso; + char *iso_values; +}; + +struct smdk4210_camera_preset { + char *name; + int facing; + int orientation; + + int rotation; + int hflip; + int vflip; + + int picture_format; + + float focal_length; + float horizontal_view_angle; + float vertical_view_angle; + + int metering; + + struct smdk4210_camera_params params; +}; + +struct smdk4210_v4l2_node { + int id; + char *node; +}; + +struct exynox_camera_config { + struct smdk4210_camera_preset *presets; + int presets_count; + + struct smdk4210_v4l2_node *v4l2_nodes; + int v4l2_nodes_count; +}; + +struct smdk4210_camera_callbacks { + camera_notify_callback notify; + camera_data_callback data; + camera_data_timestamp_callback data_timestamp; + camera_request_memory request_memory; + void *user; +}; + +struct smdk4210_camera { + int v4l2_fds[SMDK4210_CAMERA_MAX_V4L2_NODES_COUNT]; + + struct exynox_camera_config *config; + struct smdk4210_param *params; + + struct smdk4210_camera_callbacks callbacks; + int messages_enabled; + + gralloc_module_t *gralloc; + + // Picture + pthread_t picture_thread; + pthread_mutex_t picture_mutex; + int picture_thread_running; + + int picture_enabled; + camera_memory_t *picture_memory; + int picture_buffer_length; + + // Auto-focus + pthread_t auto_focus_thread; + pthread_mutex_t auto_focus_mutex; + int auto_focus_thread_running; + + int auto_focus_enabled; + + // Preview + pthread_t preview_thread; + pthread_mutex_t preview_mutex; + pthread_mutex_t preview_lock_mutex; + int preview_thread_running; + + int preview_enabled; + struct preview_stream_ops *preview_window; + camera_memory_t *preview_memory; + int preview_buffers_count; + int preview_frame_size; + int preview_params_set; + + // Recording + pthread_mutex_t recording_mutex; + + int recording_enabled; + camera_memory_t *recording_memory; + int recording_buffers_count; + + // Camera params + int camera_rotation; + int camera_hflip; + int camera_vflip; + int camera_picture_format; + int camera_focal_length; + int camera_metering; + + int camera_sensor_mode; + + // Params + int preview_width; + int preview_height; + int preview_format; + float preview_format_bpp; + int preview_fps; + int picture_width; + int picture_height; + int picture_format; + int jpeg_thumbnail_width; + int jpeg_thumbnail_height; + int jpeg_thumbnail_quality; + int jpeg_quality; + int recording_width; + int recording_height; + int recording_format; + int focus_mode; + int focus_x; + int focus_y; + int zoom; + int flash_mode; + int exposure_compensation; + int whitebalance; + int scene_mode; + int effect; + int iso; + int metering; +}; + +struct smdk4210_camera_addrs { + unsigned int type; + unsigned int y; + unsigned int cbcr; + unsigned int index; + unsigned int reserved; +}; + +// This is because the linux header uses anonymous union +struct smdk4210_v4l2_ext_control { + __u32 id; + __u32 size; + __u32 reserved2[1]; + union { + __s32 value; + __s64 value64; + char *string; + } data; +} __attribute__ ((packed)); + +enum m5mo_af_status { + M5MO_AF_STATUS_FAIL = 0, + M5MO_AF_STATUS_IN_PROGRESS, + M5MO_AF_STATUS_SUCCESS, + M5MO_AF_STATUS_1ST_SUCCESS = 4, +}; + +/* + * Camera + */ + +int smdk4210_camera_params_init(struct smdk4210_camera *smdk4210_camera, int id); +int smdk4210_camera_params_apply(struct smdk4210_camera *smdk4210_camera); + +int smdk4210_camera_auto_focus_start(struct smdk4210_camera *smdk4210_camera); +void smdk4210_camera_auto_focus_stop(struct smdk4210_camera *smdk4210_camera); + +int smdk4210_camera_picture(struct smdk4210_camera *smdk4210_camera); +int smdk4210_camera_picture_start(struct smdk4210_camera *smdk4210_camera); + +int smdk4210_camera_preview(struct smdk4210_camera *smdk4210_camera); +int smdk4210_camera_preview_start(struct smdk4210_camera *smdk4210_camera); +void smdk4210_camera_preview_stop(struct smdk4210_camera *smdk4210_camera); + +/* + * EXIF + */ + +int smdk4210_exif_attributes_create_static(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes); +int smdk4210_exif_attributes_create_params(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes); + +int smdk4210_exif_create(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes, + camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size, + camera_memory_t **exif_data_memory_p, int *exif_size_p); + +/* + * Param + */ + +int smdk4210_param_int_get(struct smdk4210_camera *smdk4210_camera, + char *key); +float smdk4210_param_float_get(struct smdk4210_camera *smdk4210_camera, + char *key); +char *smdk4210_param_string_get(struct smdk4210_camera *smdk4210_camera, + char *key); + +int smdk4210_param_int_set(struct smdk4210_camera *smdk4210_camera, + char *key, int integer); +int smdk4210_param_float_set(struct smdk4210_camera *smdk4210_camera, + char *key, float floating); +int smdk4210_param_string_set(struct smdk4210_camera *smdk4210_camera, + char *key, char *string); + +char *smdk4210_params_string_get(struct smdk4210_camera *smdk4210_camera); +int smdk4210_params_string_set(struct smdk4210_camera *smdk4210_camera, char *string); + +/* + * V4L2 + */ + +// Utils +int smdk4210_v4l2_find_index(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_find_fd(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); + +// File ops +int smdk4210_v4l2_open(struct smdk4210_camera *smdk4210_camera, int id); +void smdk4210_v4l2_close(struct smdk4210_camera *smdk4210_camera, int id); +int smdk4210_v4l2_ioctl(struct smdk4210_camera *smdk4210_camera, int id, int request, void *data); +int smdk4210_v4l2_poll(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); + +// VIDIOC +int smdk4210_v4l2_qbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int index); +int smdk4210_v4l2_qbuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index); +int smdk4210_v4l2_qbuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index); +int smdk4210_v4l2_dqbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory); +int smdk4210_v4l2_dqbuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_dqbuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_reqbufs(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int count); +int smdk4210_v4l2_reqbufs_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int count); +int smdk4210_v4l2_reqbufs_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int count); +int smdk4210_v4l2_querybuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int index); +int smdk4210_v4l2_querybuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index); +int smdk4210_v4l2_querybuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index); +int smdk4210_v4l2_querycap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int flags); +int smdk4210_v4l2_querycap_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_querycap_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_streamon(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type); +int smdk4210_v4l2_streamon_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_streamon_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_streamoff(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type); +int smdk4210_v4l2_streamoff_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_streamoff_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id); +int smdk4210_v4l2_g_fmt(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int *width, int *height, int *fmt); +int smdk4210_v4l2_g_fmt_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int *width, int *height, int *fmt); +int smdk4210_v4l2_g_fmt_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int *width, int *height, int *fmt); +int smdk4210_v4l2_s_fmt_pix(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int width, int height, int fmt, int priv); +int smdk4210_v4l2_s_fmt_pix_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int width, int height, int fmt, int priv); +int smdk4210_v4l2_s_fmt_pix_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int width, int height, int fmt, int priv); +int smdk4210_v4l2_s_fmt_win(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height); +int smdk4210_v4l2_enum_fmt(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int fmt); +int smdk4210_v4l2_enum_fmt_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int fmt); +int smdk4210_v4l2_enum_fmt_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int fmt); +int smdk4210_v4l2_enum_input(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id); +int smdk4210_v4l2_s_input(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id); +int smdk4210_v4l2_g_ext_ctrls(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_ext_control *control, int count); +int smdk4210_v4l2_g_ctrl(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id, int *value); +int smdk4210_v4l2_s_ctrl(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id, int value); +int smdk4210_v4l2_s_parm(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, struct v4l2_streamparm *streamparm); +int smdk4210_v4l2_s_parm_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_streamparm *streamparm); +int smdk4210_v4l2_s_parm_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_streamparm *streamparm); +int smdk4210_v4l2_s_crop(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int left, int top, int width, int height); +int smdk4210_v4l2_s_crop_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height); +int smdk4210_v4l2_s_crop_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height); +int smdk4210_v4l2_g_fbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + void **base, int *width, int *height, int *fmt); +int smdk4210_v4l2_s_fbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + void *base, int width, int height, int fmt); + +#endif diff --git a/camera/smdk4210_exif.c b/camera/smdk4210_exif.c new file mode 100644 index 0000000..8ac8b8c --- /dev/null +++ b/camera/smdk4210_exif.c @@ -0,0 +1,791 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * + * Based on crespo libcamera and exynos4 hal libcamera: + * Copyright 2008, The Android Open Source Project, Apache License 2.0 + * Copyright 2010, Samsung Electronics Co. LTD, Apache License 2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_TAG "smdk4210_camera" +#include +#include + +#include "smdk4210_camera.h" + +int smdk4210_exif_attributes_create_static(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes) +{ + unsigned char gps_version[] = { 0x02, 0x02, 0x00, 0x00 }; + char property[PROPERTY_VALUE_MAX]; + uint32_t av; + + if (smdk4210_camera == NULL || exif_attributes == NULL) + return -EINVAL; + + // Device + property_get("ro.product.brand", property, EXIF_DEF_MAKER); + strncpy((char *) exif_attributes->maker, property, + sizeof(exif_attributes->maker) - 1); + exif_attributes->maker[sizeof(exif_attributes->maker) - 1] = '\0'; + + property_get("ro.product.model", property, EXIF_DEF_MODEL); + strncpy((char *) exif_attributes->model, property, + sizeof(exif_attributes->model) - 1); + exif_attributes->model[sizeof(exif_attributes->model) - 1] = '\0'; + + property_get("ro.build.id", property, EXIF_DEF_SOFTWARE); + strncpy((char *) exif_attributes->software, property, + sizeof(exif_attributes->software) - 1); + exif_attributes->software[sizeof(exif_attributes->software) - 1] = '\0'; + + exif_attributes->ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING; + + exif_attributes->fnumber.num = EXIF_DEF_FNUMBER_NUM; + exif_attributes->fnumber.den = EXIF_DEF_FNUMBER_DEN; + + exif_attributes->exposure_program = EXIF_DEF_EXPOSURE_PROGRAM; + + memcpy(exif_attributes->exif_version, EXIF_DEF_EXIF_VERSION, + sizeof(exif_attributes->exif_version)); + + av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num / + exif_attributes->fnumber.den); + exif_attributes->aperture.num = av; + exif_attributes->aperture.den = EXIF_DEF_APEX_DEN; + exif_attributes->max_aperture.num = av; + exif_attributes->max_aperture.den = EXIF_DEF_APEX_DEN; + + strcpy((char *) exif_attributes->user_comment, EXIF_DEF_USERCOMMENTS); + exif_attributes->color_space = EXIF_DEF_COLOR_SPACE; + exif_attributes->exposure_mode = EXIF_DEF_EXPOSURE_MODE; + + // GPS version + memcpy(exif_attributes->gps_version_id, gps_version, sizeof(gps_version)); + + exif_attributes->compression_scheme = EXIF_DEF_COMPRESSION; + exif_attributes->x_resolution.num = EXIF_DEF_RESOLUTION_NUM; + exif_attributes->x_resolution.den = EXIF_DEF_RESOLUTION_DEN; + exif_attributes->y_resolution.num = EXIF_DEF_RESOLUTION_NUM; + exif_attributes->y_resolution.den = EXIF_DEF_RESOLUTION_DEN; + exif_attributes->resolution_unit = EXIF_DEF_RESOLUTION_UNIT; + + return 0; +} + +int smdk4210_exif_attributes_create_gps(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes) +{ + float gps_latitude_float, gps_longitude_float, gps_altitude_float; + int gps_timestamp_int; + char *gps_processing_method_string; + long gps_latitude, gps_longitude; + long gps_altitude, gps_timestamp; + double gps_latitude_abs, gps_longitude_abs, gps_altitude_abs; + + struct tm time_info; + + if (smdk4210_camera == NULL || exif_attributes == NULL) + return -EINVAL; + + gps_latitude_float = smdk4210_param_float_get(smdk4210_camera, "gps-latitude"); + gps_longitude_float = smdk4210_param_float_get(smdk4210_camera, "gps-longitude"); + gps_altitude_float = smdk4210_param_float_get(smdk4210_camera, "gps-altitude"); + if (gps_altitude_float == -1) + gps_altitude_float = (float) smdk4210_param_int_get(smdk4210_camera, "gps-altitude"); + gps_timestamp_int = smdk4210_param_int_get(smdk4210_camera, "gps-timestamp"); + gps_processing_method_string = smdk4210_param_string_get(smdk4210_camera, "gps-processing-method"); + + if (gps_latitude_float == -1 || gps_longitude_float == -1 || + gps_altitude_float == -1 || gps_timestamp_int <= 0 || + gps_processing_method_string == NULL) { + exif_attributes->enableGps = false; + return 0; + } + + gps_latitude = (long) (gps_latitude_float * 10000000) / 1; + gps_longitude = (long) (gps_longitude_float * 10000000) / 1; + gps_altitude = (long) (gps_altitude_float * 100) / 1; + gps_timestamp = (long) gps_timestamp_int; + + if (gps_latitude == 0 || gps_longitude == 0) { + exif_attributes->enableGps = false; + return 0; + } + + if (gps_latitude > 0) + strcpy((char *) exif_attributes->gps_latitude_ref, "N"); + else + strcpy((char *) exif_attributes->gps_latitude_ref, "S"); + + if (gps_longitude > 0) + strcpy((char *) exif_attributes->gps_longitude_ref, "E"); + else + strcpy((char *) exif_attributes->gps_longitude_ref, "W"); + + if (gps_altitude > 0) + exif_attributes->gps_altitude_ref = 0; + else + exif_attributes->gps_altitude_ref = 1; + + + gps_latitude_abs = fabs(gps_latitude); + gps_longitude_abs = fabs(gps_longitude); + gps_altitude_abs = fabs(gps_altitude); + + exif_attributes->gps_latitude[0].num = (uint32_t) gps_latitude_abs; + exif_attributes->gps_latitude[0].den = 10000000; + exif_attributes->gps_latitude[1].num = 0; + exif_attributes->gps_latitude[1].den = 1; + exif_attributes->gps_latitude[2].num = 0; + exif_attributes->gps_latitude[2].den = 1; + + exif_attributes->gps_longitude[0].num = (uint32_t) gps_longitude_abs; + exif_attributes->gps_longitude[0].den = 10000000; + exif_attributes->gps_longitude[1].num = 0; + exif_attributes->gps_longitude[1].den = 1; + exif_attributes->gps_longitude[2].num = 0; + exif_attributes->gps_longitude[2].den = 1; + + exif_attributes->gps_altitude.num = (uint32_t) gps_altitude_abs; + exif_attributes->gps_altitude.den = 100; + + gmtime_r(&gps_timestamp, &time_info); + + exif_attributes->gps_timestamp[0].num = time_info.tm_hour; + exif_attributes->gps_timestamp[0].den = 1; + exif_attributes->gps_timestamp[1].num = time_info.tm_min; + exif_attributes->gps_timestamp[1].den = 1; + exif_attributes->gps_timestamp[2].num = time_info.tm_sec; + exif_attributes->gps_timestamp[2].den = 1; + snprintf((char *) exif_attributes->gps_datestamp, sizeof(exif_attributes->gps_datestamp), + "%04d:%02d:%02d", time_info.tm_year + 1900, time_info.tm_mon + 1, time_info.tm_mday); + + exif_attributes->enableGps = true; + + return 0; +} + +int smdk4210_exif_attributes_create_params(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes) +{ + uint32_t av, tv, bv, sv, ev; + time_t time_data; + struct tm *time_info; + int rotation; + int shutter_speed; + int exposure_time; + int iso_speed; + int exposure; + int flash_results; + + int rc; + + if (smdk4210_camera == NULL || exif_attributes == NULL) + return -EINVAL; + + // Picture size + exif_attributes->width = smdk4210_camera->picture_width; + exif_attributes->height = smdk4210_camera->picture_height; + + // Thumbnail + exif_attributes->widthThumb = smdk4210_camera->jpeg_thumbnail_width; + exif_attributes->heightThumb = smdk4210_camera->jpeg_thumbnail_height; + exif_attributes->enableThumb = true; + + // Orientation + rotation = smdk4210_param_int_get(smdk4210_camera, "rotation"); + switch (rotation) { + case 90: + exif_attributes->orientation = EXIF_ORIENTATION_90; + break; + case 180: + exif_attributes->orientation = EXIF_ORIENTATION_180; + break; + case 270: + exif_attributes->orientation = EXIF_ORIENTATION_270; + break; + case 0: + default: + exif_attributes->orientation = EXIF_ORIENTATION_UP; + break; + } + + // Time + time(&time_data); + time_info = localtime(&time_data); + strftime((char *) exif_attributes->date_time, sizeof(exif_attributes->date_time), + "%Y:%m:%d %H:%M:%S", time_info); + + exif_attributes->focal_length.num = smdk4210_camera->camera_focal_length; + exif_attributes->focal_length.den = EXIF_DEF_FOCAL_LEN_DEN; + + shutter_speed = 100; + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EXIF_TV, + &shutter_speed); + if (rc < 0) + ALOGE("%s: g ctrl failed!", __func__); + + exif_attributes->shutter_speed.num = shutter_speed; + exif_attributes->shutter_speed.den = 100; + + exif_attributes->exposure_time.num = 1; + exif_attributes->exposure_time.den = APEX_SHUTTER_TO_EXPOSURE(shutter_speed); + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EXIF_ISO, + &iso_speed); + if (rc < 0) + ALOGE("%s: g ctrl failed!", __func__); + + exif_attributes->iso_speed_rating = iso_speed; + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EXIF_FLASH, + &flash_results); + if (rc < 0) + ALOGE("%s: g ctrl failed!", __func__); + + exif_attributes->flash = flash_results; + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EXIF_BV, + (int *) &bv); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + goto bv_static; + } + + rc = smdk4210_v4l2_g_ctrl(smdk4210_camera, 0, V4L2_CID_CAMERA_EXIF_EBV, + (int *) &ev); + if (rc < 0) { + ALOGE("%s: g ctrl failed!", __func__); + goto bv_static; + } + + goto bv_ioctl; + +bv_static: + exposure = smdk4210_param_int_get(smdk4210_camera, "exposure-compensation"); + if (exposure < 0) + exposure = EV_DEFAULT; + + av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num / + exif_attributes->fnumber.den); + tv = APEX_EXPOSURE_TO_SHUTTER((double) exif_attributes->exposure_time.num / + exif_attributes->exposure_time.den); + sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed); + bv = av + tv - sv; + ev = exposure - EV_DEFAULT; + +bv_ioctl: + exif_attributes->brightness.num = bv; + exif_attributes->brightness.den = EXIF_DEF_APEX_DEN; + + if (smdk4210_camera->scene_mode == SCENE_MODE_BEACH_SNOW) { + exif_attributes->exposure_bias.num = EXIF_DEF_APEX_DEN; + exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN; + } else { + exif_attributes->exposure_bias.num = ev * EXIF_DEF_APEX_DEN; + exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN; + } + + switch (smdk4210_camera->camera_metering) { + case METERING_CENTER: + exif_attributes->metering_mode = EXIF_METERING_CENTER; + break; + case METERING_MATRIX: + exif_attributes->metering_mode = EXIF_METERING_AVERAGE; + break; + case METERING_SPOT: + exif_attributes->metering_mode = EXIF_METERING_SPOT; + break; + default: + exif_attributes->metering_mode = EXIF_METERING_AVERAGE; + break; + } + + if (smdk4210_camera->whitebalance == WHITE_BALANCE_AUTO || + smdk4210_camera->whitebalance == WHITE_BALANCE_BASE) + exif_attributes->white_balance = EXIF_WB_AUTO; + else + exif_attributes->white_balance = EXIF_WB_MANUAL; + + switch (smdk4210_camera->scene_mode) { + case SCENE_MODE_PORTRAIT: + exif_attributes->scene_capture_type = EXIF_SCENE_PORTRAIT; + break; + case SCENE_MODE_LANDSCAPE: + exif_attributes->scene_capture_type = EXIF_SCENE_LANDSCAPE; + break; + case SCENE_MODE_NIGHTSHOT: + exif_attributes->scene_capture_type = EXIF_SCENE_NIGHT; + break; + default: + exif_attributes->scene_capture_type = EXIF_SCENE_STANDARD; + break; + } + + rc = smdk4210_exif_attributes_create_gps(smdk4210_camera, exif_attributes); + if (rc < 0) { + ALOGE("%s: Failed to create GPS attributes", __func__); + return -1; + } + + return 0; +} + +int smdk4210_exif_write_data(void *exif_data, unsigned short tag, + unsigned short type, unsigned int count, int *offset, void *start, + void *data, int length) +{ + unsigned char *pointer; + int size; + + if (exif_data == NULL || data == NULL || length <= 0) + return -EINVAL; + + pointer = (unsigned char *) exif_data; + + memcpy(pointer, &tag, sizeof(tag)); + pointer += sizeof(tag); + + memcpy(pointer, &type, sizeof(type)); + pointer += sizeof(type); + + memcpy(pointer, &count, sizeof(count)); + pointer += sizeof(count); + + if (offset != NULL && start != NULL) { + memcpy(pointer, offset, sizeof(*offset)); + pointer += sizeof(*offset); + + memcpy((void *) ((int) start + *offset), data, count * length); + *offset += count * length; + } else { + memcpy(pointer, data, count * length); + pointer += 4; + } + + size = (int) pointer - (int) exif_data; + return size; +} + +int smdk4210_exif_create(struct smdk4210_camera *smdk4210_camera, + exif_attribute_t *exif_attributes, + camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size, + camera_memory_t **exif_data_memory_p, int *exif_size_p) +{ + // Markers + unsigned char exif_app1_marker[] = { 0xff, 0xe1 }; + unsigned char exif_app1_size[] = { 0x00, 0x00 }; + unsigned char exif_marker[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + unsigned char tiff_marker[] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; + + unsigned char user_comment_code[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + unsigned char exif_ascii_prefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + + camera_memory_t *exif_data_memory; + void *exif_data; + int exif_data_size; + int exif_size; + + void *exif_ifd_data_start, *exif_ifd_start, *exif_ifd_gps, *exif_ifd_thumb; + + void *exif_thumb_data; + unsigned int exif_thumb_size; + + unsigned char *pointer; + unsigned int offset; + void *data; + int count; + + unsigned int value; + + if (smdk4210_camera == NULL || exif_attributes == NULL || + jpeg_thumbnail_data_memory == NULL || jpeg_thumbnail_size <= 0 || + exif_data_memory_p == NULL || exif_size_p == NULL) + return -EINVAL; + + exif_data_size = EXIF_FILE_SIZE + jpeg_thumbnail_size; + + if (smdk4210_camera->callbacks.request_memory != NULL) { + exif_data_memory = smdk4210_camera->callbacks.request_memory(-1, + exif_data_size, 1, 0); + if (exif_data_memory == NULL) { + ALOGE("%s: exif memory request failed!", __func__); + goto error; + } + } else { + ALOGE("%s: No memory request function!", __func__); + goto error; + } + + exif_data = exif_data_memory->data; + memset(exif_data, 0, exif_data_size); + + pointer = (unsigned char *) exif_data; + exif_ifd_data_start = (void *) pointer; + + // Skip 4 bytes for APP1 marker + pointer += 4; + + // Copy EXIF marker + memcpy(pointer, exif_marker, sizeof(exif_marker)); + pointer += sizeof(exif_marker); + + // Copy TIFF marker + memcpy(pointer, tiff_marker, sizeof(tiff_marker)); + exif_ifd_start = (void *) pointer; + pointer += sizeof(tiff_marker); + + if (exif_attributes->enableGps) + value = NUM_0TH_IFD_TIFF; + else + value = NUM_0TH_IFD_TIFF - 1; + + memcpy(pointer, &value, NUM_SIZE); + pointer += NUM_SIZE; + + offset = 8 + NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE; + + // Write EXIF data + count = smdk4210_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_MAKE, + EXIF_TYPE_ASCII, strlen((char *) exif_attributes->maker) + 1, + &offset, exif_ifd_start, &exif_attributes->maker, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_MODEL, + EXIF_TYPE_ASCII, strlen((char *) exif_attributes->model) + 1, + &offset, exif_ifd_start, &exif_attributes->model, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_ORIENTATION, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_SOFTWARE, + EXIF_TYPE_ASCII, strlen((char *) exif_attributes->software) + 1, + &offset, exif_ifd_start, &exif_attributes->software, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_DATE_TIME, + EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_YCBCR_POSITIONING, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->ycbcr_positioning, sizeof(exif_attributes->ycbcr_positioning)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXIF_IFD_POINTER, + EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); + pointer += count; + + if (exif_attributes->enableGps) { + exif_ifd_gps = (void *) pointer; + pointer += IFD_SIZE; + } + + exif_ifd_thumb = (void *) pointer; + pointer += OFFSET_SIZE; + + pointer = (unsigned char *) exif_ifd_start; + pointer += offset; + + value = NUM_0TH_IFD_EXIF; + memcpy(pointer, &value, NUM_SIZE); + pointer += NUM_SIZE; + + offset += NUM_SIZE + NUM_0TH_IFD_EXIF * IFD_SIZE + OFFSET_SIZE; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXPOSURE_TIME, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_time, sizeof(exif_attributes->exposure_time)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_FNUMBER, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->fnumber, sizeof(exif_attributes->fnumber)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXPOSURE_PROGRAM, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_program, sizeof(exif_attributes->exposure_program)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_ISO_SPEED_RATING, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->iso_speed_rating, sizeof(exif_attributes->iso_speed_rating)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXIF_VERSION, + EXIF_TYPE_UNDEFINED, 4, NULL, NULL, &exif_attributes->exif_version, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_DATE_TIME_ORG, + EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_DATE_TIME_DIGITIZE, + EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_SHUTTER_SPEED, + EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->shutter_speed, sizeof(exif_attributes->shutter_speed)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_APERTURE, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->aperture, sizeof(exif_attributes->aperture)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_BRIGHTNESS, + EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->brightness, sizeof(exif_attributes->brightness)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXPOSURE_BIAS, + EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_bias, sizeof(exif_attributes->exposure_bias)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_MAX_APERTURE, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->max_aperture, sizeof(exif_attributes->max_aperture)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_METERING_MODE, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->metering_mode, sizeof(exif_attributes->metering_mode)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_FLASH, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->flash, sizeof(exif_attributes->flash)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_FOCAL_LENGTH, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->focal_length, sizeof(exif_attributes->focal_length)); + pointer += count; + + value = strlen((char *) exif_attributes->user_comment) + 1; + memmove(exif_attributes->user_comment + sizeof(user_comment_code), exif_attributes->user_comment, value); + memcpy(exif_attributes->user_comment, user_comment_code, sizeof(user_comment_code)); + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_USER_COMMENT, + EXIF_TYPE_UNDEFINED, value + sizeof(user_comment_code), &offset, exif_ifd_start, &exif_attributes->user_comment, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_COLOR_SPACE, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->color_space, sizeof(exif_attributes->color_space)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_PIXEL_X_DIMENSION, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_PIXEL_Y_DIMENSION, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_EXPOSURE_MODE, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_mode, sizeof(exif_attributes->exposure_mode)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_WHITE_BALANCE, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->white_balance, sizeof(exif_attributes->white_balance)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_SCENCE_CAPTURE_TYPE, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->scene_capture_type, sizeof(exif_attributes->scene_capture_type)); + pointer += count; + + value = 0; + memcpy(pointer, &value, OFFSET_SIZE); + pointer += OFFSET_SIZE; + + // GPS + if (exif_attributes->enableGps) { + pointer = (unsigned char *) exif_ifd_gps; + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_IFD_POINTER, + EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); + + pointer = exif_ifd_start + offset; + + if (exif_attributes->gps_processing_method[0] == 0) + value = NUM_0TH_IFD_GPS - 1; + else + value = NUM_0TH_IFD_GPS; + + memcpy(pointer, &value, NUM_SIZE); + pointer += NUM_SIZE; + + offset += NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_VERSION_ID, + EXIF_TYPE_BYTE, 4, NULL, NULL, &exif_attributes->gps_version_id, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE_REF, + EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_latitude_ref, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE, + EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_latitude, sizeof(exif_attributes->gps_latitude[0])); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE_REF, + EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_longitude_ref, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE, + EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_longitude, sizeof(exif_attributes->gps_longitude[0])); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE_REF, + EXIF_TYPE_BYTE, 1, NULL, NULL, &exif_attributes->gps_altitude_ref, sizeof(char)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->gps_altitude, sizeof(exif_attributes->gps_altitude)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_TIMESTAMP, + EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_timestamp, sizeof(exif_attributes->gps_timestamp[0])); + pointer += count; + + value = strlen((char *) exif_attributes->gps_processing_method); + if (value > 0) { + value = value > 100 ? 100 : value; + + data = calloc(1, value + sizeof(exif_ascii_prefix)); + memcpy(data, &exif_ascii_prefix, sizeof(exif_ascii_prefix)); + memcpy((void *) ((int) data + (int) sizeof(exif_ascii_prefix)), exif_attributes->gps_processing_method, value); + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_PROCESSING_METHOD, + EXIF_TYPE_UNDEFINED, value + sizeof(exif_ascii_prefix), &offset, exif_ifd_start, data, sizeof(char)); + pointer += count; + + free(data); + } + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_GPS_DATESTAMP, + EXIF_TYPE_ASCII, 11, &offset, exif_ifd_start, &exif_attributes->gps_datestamp, 1); + pointer += count; + + value = 0; + memcpy(pointer, &value, OFFSET_SIZE); + pointer += OFFSET_SIZE; + } + + if (exif_attributes->enableThumb && jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_size > 0) { + exif_thumb_size = (unsigned int) jpeg_thumbnail_size; + exif_thumb_data = (void *) jpeg_thumbnail_data_memory->data; + + value = offset; + memcpy(exif_ifd_thumb, &value, OFFSET_SIZE); + + pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset); + + value = NUM_1TH_IFD_TIFF; + memcpy(pointer, &value, NUM_SIZE); + pointer += NUM_SIZE; + + offset += NUM_SIZE + NUM_1TH_IFD_TIFF * IFD_SIZE + OFFSET_SIZE; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->widthThumb, sizeof(exif_attributes->widthThumb)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->heightThumb, sizeof(exif_attributes->heightThumb)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_COMPRESSION_SCHEME, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->compression_scheme, sizeof(exif_attributes->compression_scheme)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_ORIENTATION, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_X_RESOLUTION, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->x_resolution, sizeof(exif_attributes->x_resolution)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_Y_RESOLUTION, + EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->y_resolution, sizeof(exif_attributes->y_resolution)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_RESOLUTION_UNIT, + EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->resolution_unit, sizeof(exif_attributes->resolution_unit)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, + EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset)); + pointer += count; + + count = smdk4210_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, + EXIF_TYPE_LONG, 1, NULL, NULL, &exif_thumb_size, sizeof(exif_thumb_size)); + pointer += count; + + value = 0; + memcpy(pointer, &value, OFFSET_SIZE); + + pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset); + + memcpy(pointer, exif_thumb_data, exif_thumb_size); + offset += exif_thumb_size; + } else { + value = 0; + memcpy(exif_ifd_thumb, &value, OFFSET_SIZE); + + } + + pointer = (unsigned char *) exif_ifd_data_start; + + memcpy(pointer, exif_app1_marker, sizeof(exif_app1_marker)); + pointer += sizeof(exif_app1_marker); + + exif_size = offset + 10; + value = exif_size - 2; + exif_app1_size[0] = (value >> 8) & 0xff; + exif_app1_size[1] = value & 0xff; + + memcpy(pointer, exif_app1_size, sizeof(exif_app1_size)); + + *exif_data_memory_p = exif_data_memory; + *exif_size_p = exif_size; + + return 0; + +error: + if (exif_data_memory != NULL && exif_data_memory->release != NULL) + exif_data_memory->release(exif_data_memory); + + *exif_data_memory_p = NULL; + *exif_size_p = 0; + + return -1; +} diff --git a/camera/smdk4210_param.c b/camera/smdk4210_param.c new file mode 100644 index 0000000..c7745f9 --- /dev/null +++ b/camera/smdk4210_param.c @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "smdk4210_param" +#include + +#include "smdk4210_camera.h" + +int list_head_insert(struct list_head *list, struct list_head *prev, + struct list_head *next) +{ + if (list == NULL) + return -EINVAL; + + list->prev = prev; + list->next = next; + + if(prev != NULL) + prev->next = list; + if(next != NULL) + next->prev = list; + + return 0; +} + +void list_head_remove(struct list_head *list) +{ + if(list == NULL) + return; + + if(list->next != NULL) + list->next->prev = list->prev; + if(list->prev != NULL) + list->prev->next = list->next; +} + +int smdk4210_param_register(struct smdk4210_camera *smdk4210_camera, char *key, + union smdk4210_param_data data, enum smdk4210_param_type type) +{ + struct list_head *list_end; + struct list_head *list; + struct smdk4210_param *param; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + param = (struct smdk4210_param *) calloc(1, sizeof(struct smdk4210_param)); + if (param == NULL) + return -ENOMEM; + + param->key = strdup(key); + switch (type) { + case SMDK4210_PARAM_INT: + param->data.integer = data.integer; + break; + case SMDK4210_PARAM_FLOAT: + param->data.floating = data.floating; + break; + case SMDK4210_PARAM_STRING: + param->data.string = strdup(data.string); + break; + default: + ALOGE("%s: Invalid type", __func__); + goto error; + } + param->type = type; + + list_end = (struct list_head *) smdk4210_camera->params; + while (list_end != NULL && list_end->next != NULL) + list_end = list_end->next; + + list = (struct list_head *) param; + list_head_insert(list, list_end, NULL); + + if (smdk4210_camera->params == NULL) + smdk4210_camera->params = param; + + return 0; + +error: + if (param != NULL) { + if (param->key != NULL) + free(param->key); + + free(param); + } + + return -1; +} + +void smdk4210_param_unregister(struct smdk4210_camera *smdk4210_camera, + struct smdk4210_param *param) +{ + struct list_head *list; + + if (smdk4210_camera == NULL || param == NULL) + return; + + list = (struct list_head *) smdk4210_camera->params; + while (list != NULL) { + if ((void *) list == (void *) param) { + list_head_remove(list); + + if ((void *) list == (void *) smdk4210_camera->params) + smdk4210_camera->params = (struct smdk4210_param *) list->next; + + if (param->type == SMDK4210_PARAM_STRING && param->data.string != NULL) + free(param->data.string); + + memset(param, 0, sizeof(struct smdk4210_param)); + free(param); + + break; + } + +list_continue: + list = list->next; + } +} + +struct smdk4210_param *smdk4210_param_find_key(struct smdk4210_camera *smdk4210_camera, + char *key) +{ + struct smdk4210_param *param; + struct list_head *list; + + if (smdk4210_camera == NULL || key == NULL) + return NULL; + + list = (struct list_head *) smdk4210_camera->params; + while (list != NULL) { + param = (struct smdk4210_param *) list; + if (param->key == NULL) + goto list_continue; + + if (strcmp(param->key, key) == 0) + return param; + +list_continue: + list = list->next; + } + + return NULL; +} + +int smdk4210_param_data_set(struct smdk4210_camera *smdk4210_camera, char *key, + union smdk4210_param_data data, enum smdk4210_param_type type) +{ + struct smdk4210_param *param; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + if (strchr(key, '=') || strchr(key, ';')) + return -EINVAL; + + if (type == SMDK4210_PARAM_STRING && data.string != NULL && + (strchr(data.string, '=') || strchr(data.string, ';'))) + return -EINVAL; + + param = smdk4210_param_find_key(smdk4210_camera, key); + if (param == NULL) { + // The key isn't in the list yet + smdk4210_param_register(smdk4210_camera, key, data, type); + return 0; + } + + if (param->type != type) + ALOGE("%s: Mismatching types for key %s", __func__, key); + + if (param->type == SMDK4210_PARAM_STRING && param->data.string != NULL) + free(param->data.string); + + switch (type) { + case SMDK4210_PARAM_INT: + param->data.integer = data.integer; + break; + case SMDK4210_PARAM_FLOAT: + param->data.floating = data.floating; + break; + case SMDK4210_PARAM_STRING: + param->data.string = strdup(data.string); + break; + default: + ALOGE("%s: Invalid type", __func__); + return -1; + } + param->type = type; + + return 0; +} + +int smdk4210_param_data_get(struct smdk4210_camera *smdk4210_camera, char *key, + union smdk4210_param_data *data, enum smdk4210_param_type type) +{ + struct smdk4210_param *param; + + if (smdk4210_camera == NULL || key == NULL || data == NULL) + return -EINVAL; + + param = smdk4210_param_find_key(smdk4210_camera, key); + if (param == NULL || param->type != type) + return -1; + + memcpy(data, ¶m->data, sizeof(param->data)); + + return 0; +} + +int smdk4210_param_int_get(struct smdk4210_camera *smdk4210_camera, + char *key) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + rc = smdk4210_param_data_get(smdk4210_camera, key, &data, SMDK4210_PARAM_INT); + if (rc < 0) { + ALOGE("%s: Unable to get data for key %s", __func__, key); + return -1; + } + + return data.integer; +} + +float smdk4210_param_float_get(struct smdk4210_camera *smdk4210_camera, + char *key) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + rc = smdk4210_param_data_get(smdk4210_camera, key, &data, SMDK4210_PARAM_FLOAT); + if (rc < 0) { + ALOGE("%s: Unable to get data for key %s", __func__, key); + return -1; + } + + return data.floating; +} + +char *smdk4210_param_string_get(struct smdk4210_camera *smdk4210_camera, + char *key) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL) + return NULL; + + rc = smdk4210_param_data_get(smdk4210_camera, key, &data, SMDK4210_PARAM_STRING); + if (rc < 0) { + ALOGE("%s: Unable to get data for key %s", __func__, key); + return NULL; + } + + return data.string; +} + +int smdk4210_param_int_set(struct smdk4210_camera *smdk4210_camera, + char *key, int integer) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + data.integer = integer; + + rc = smdk4210_param_data_set(smdk4210_camera, key, data, SMDK4210_PARAM_INT); + if (rc < 0) { + ALOGE("%s: Unable to set data for key %s", __func__, key); + return -1; + } + + return 0; +} + +int smdk4210_param_float_set(struct smdk4210_camera *smdk4210_camera, + char *key, float floating) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL) + return -EINVAL; + + data.floating = floating; + + rc = smdk4210_param_data_set(smdk4210_camera, key, data, SMDK4210_PARAM_FLOAT); + if (rc < 0) { + ALOGE("%s: Unable to set data for key %s", __func__, key); + return -1; + } + + return 0; +} + +int smdk4210_param_string_set(struct smdk4210_camera *smdk4210_camera, + char *key, char *string) +{ + union smdk4210_param_data data; + int rc; + + if (smdk4210_camera == NULL || key == NULL || string == NULL) + return -EINVAL; + + data.string = string; + + rc = smdk4210_param_data_set(smdk4210_camera, key, data, SMDK4210_PARAM_STRING); + if (rc < 0) { + ALOGE("%s: Unable to set data for key %s", __func__, key); + return -1; + } + + return 0; +} + +char *smdk4210_params_string_get(struct smdk4210_camera *smdk4210_camera) +{ + struct smdk4210_param *param; + struct list_head *list; + char *string = NULL; + char *s = NULL; + int length = 0; + int l = 0; + + if (smdk4210_camera == NULL) + return NULL; + + list = (struct list_head *) smdk4210_camera->params; + while (list != NULL) { + param = (struct smdk4210_param *) list; + if (param->key == NULL) + goto list_continue_length; + + length += strlen(param->key); + length++; + + switch (param->type) { + case SMDK4210_PARAM_INT: + case SMDK4210_PARAM_FLOAT: + length += 16; + break; + case SMDK4210_PARAM_STRING: + length += strlen(param->data.string); + break; + default: + ALOGE("%s: Invalid type", __func__); + return NULL; + } + + length++; + +list_continue_length: + list = list->next; + } + + if (length == 0) + return NULL; + + string = calloc(1, length); + s = string; + + list = (struct list_head *) smdk4210_camera->params; + while (list != NULL) { + param = (struct smdk4210_param *) list; + if (param->key == NULL) + goto list_continue; + + l = sprintf(s, "%s=", param->key); + s += l; + + switch (param->type) { + case SMDK4210_PARAM_INT: + l = snprintf(s, 16, "%d", param->data.integer); + s += l; + break; + case SMDK4210_PARAM_FLOAT: + l = snprintf(s, 16, "%g", param->data.floating); + s += l; + break; + case SMDK4210_PARAM_STRING: + l = sprintf(s, "%s", param->data.string); + s += l; + break; + default: + ALOGE("%s: Invalid type", __func__); + return NULL; + } + + if (list->next != NULL) { + *s = ';'; + s++; + } else { + *s = '\0'; + break; + } + +list_continue: + list = list->next; + } + + return string; +} + +int smdk4210_params_string_set(struct smdk4210_camera *smdk4210_camera, char *string) +{ + union smdk4210_param_data data; + enum smdk4210_param_type type; + + char *d = NULL; + char *s = NULL; + char *k = NULL; + char *v = NULL; + + char *key; + char *value; + + int rc; + int i; + + if (smdk4210_camera == NULL || string == NULL) + return -1; + + d = strdup(string); + s = d; + + while (1) { + k = strchr(s, '='); + if (k == NULL) + break; + *k = '\0'; + key = s; + + v = strchr(k+1, ';'); + if (v != NULL) + *v = '\0'; + value = k+1; + + k = value; + if (isdigit(k[0]) || k[0] == '-') { + type = SMDK4210_PARAM_INT; + + for (i=1 ; k[i] != '\0' ; i++) { + if (k[i] == '.') { + type = SMDK4210_PARAM_FLOAT; + } else if (!isdigit(k[i])) { + type = SMDK4210_PARAM_STRING; + break; + } + } + } else { + type = SMDK4210_PARAM_STRING; + } + + switch (type) { + case SMDK4210_PARAM_INT: + data.integer = atoi(value); + break; + case SMDK4210_PARAM_FLOAT: + data.floating = atof(value); + break; + case SMDK4210_PARAM_STRING: + data.string = value; + break; + default: + ALOGE("%s: Invalid type", __func__); + goto error; + } + + rc = smdk4210_param_data_set(smdk4210_camera, key, data, type); + if (rc < 0) { + ALOGE("%s: Unable to set data for key %s", __func__, key); + goto error; + } + + if (v == NULL) + break; + + s = v+1; + } + + if (d != NULL) + free(d); + + return 0; + +error: + if (d != NULL) + free(d); + + return -1; +} diff --git a/camera/smdk4210_v4l2.c b/camera/smdk4210_v4l2.c new file mode 100644 index 0000000..19e14b7 --- /dev/null +++ b/camera/smdk4210_v4l2.c @@ -0,0 +1,796 @@ +/* + * Copyright (C) 2013 Paul Kocialkowski + * + * Based on crespo libcamera and exynos4 hal libcamera: + * Copyright 2008, The Android Open Source Project + * Copyright 2010, Samsung Electronics Co. LTD + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_TAG "smdk4210_v4l2" +#include + +#include "smdk4210_camera.h" + +/* + * Utils + */ + +int smdk4210_v4l2_find_index(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + int index; + int i; + + if (smdk4210_camera == NULL || smdk4210_camera->config == NULL || + smdk4210_camera->config->v4l2_nodes == NULL) + return -EINVAL; + + if (smdk4210_v4l2_id > smdk4210_camera->config->v4l2_nodes_count) + return -1; + + index = -1; + for (i = 0; i < smdk4210_camera->config->v4l2_nodes_count; i++) { + if (smdk4210_camera->config->v4l2_nodes[i].id == smdk4210_v4l2_id && + smdk4210_camera->config->v4l2_nodes[i].node != NULL) { + index = i; + } + } + + return index; +} + +int smdk4210_v4l2_find_fd(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + int index; + + if (smdk4210_camera == NULL) + return -EINVAL; + + index = smdk4210_v4l2_find_index(smdk4210_camera, smdk4210_v4l2_id); + if (index < 0) + return -1; + + return smdk4210_camera->v4l2_fds[index]; +} + +/* + * File ops + */ + +int smdk4210_v4l2_open(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + char *node; + int index; + int fd; + + if (smdk4210_camera == NULL || smdk4210_camera->config == NULL || + smdk4210_camera->config->v4l2_nodes == NULL) + return -EINVAL; + + index = smdk4210_v4l2_find_index(smdk4210_camera, smdk4210_v4l2_id); + if (index < 0) { + ALOGE("%s: Unable to find v4l2 node #%d", __func__, smdk4210_v4l2_id); + return -1; + } + + node = smdk4210_camera->config->v4l2_nodes[index].node; + fd = open(node, O_RDWR); + if (fd < 0) { + ALOGE("%s: Unable to open v4l2 node #%d", __func__, smdk4210_v4l2_id); + return -1; + } + + smdk4210_camera->v4l2_fds[index] = fd; + + return 0; +} + +void smdk4210_v4l2_close(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + int index; + + if (smdk4210_camera == NULL || smdk4210_camera->config == NULL || + smdk4210_camera->config->v4l2_nodes == NULL) + return; + + index = smdk4210_v4l2_find_index(smdk4210_camera, smdk4210_v4l2_id); + if (index < 0) { + ALOGE("%s: Unable to find v4l2 node #%d", __func__, smdk4210_v4l2_id); + return; + } + + if (smdk4210_camera->v4l2_fds[index] > 0) + close(smdk4210_camera->v4l2_fds[index]); + + smdk4210_camera->v4l2_fds[index] = -1; +} + +int smdk4210_v4l2_ioctl(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int request, void *data) +{ + int fd; + + if (smdk4210_camera == NULL) + return -EINVAL; + + fd = smdk4210_v4l2_find_fd(smdk4210_camera, smdk4210_v4l2_id); + if (fd < 0) { + ALOGE("%s: Unable to find v4l2 fd #%d", __func__, smdk4210_v4l2_id); + return -1; + } + + return ioctl(fd, request, data); +} + +int smdk4210_v4l2_poll(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + struct pollfd events; + int fd; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + fd = smdk4210_v4l2_find_fd(smdk4210_camera, smdk4210_v4l2_id); + if (fd < 0) { + ALOGE("%s: Unable to find v4l2 fd #%d", __func__, smdk4210_v4l2_id); + return -1; + } + + memset(&events, 0, sizeof(events)); + events.fd = fd; + events.events = POLLIN | POLLERR; + + rc = poll(&events, 1, 1000); + if (rc < 0 || events.revents & POLLERR) { + ALOGE("%s: poll failed", __func__); + return -1; + } + + return rc; +} + +/* + * VIDIOC + */ + +int smdk4210_v4l2_qbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int index) +{ + struct v4l2_buffer buffer; + int rc; + + if (smdk4210_camera == NULL || index < 0) + return -EINVAL; + + buffer.type = type; + buffer.memory = memory; + buffer.index = index; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_QBUF, &buffer); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_qbuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index) +{ + return smdk4210_v4l2_qbuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_MMAP, index); +} + +int smdk4210_v4l2_qbuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index) +{ + return smdk4210_v4l2_qbuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_USERPTR, index); +} + +int smdk4210_v4l2_dqbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory) +{ + struct v4l2_buffer buffer; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + memset(&buffer, 0, sizeof(buffer)); + buffer.type = type; + buffer.memory = memory; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_DQBUF, &buffer); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return buffer.index; +} + +int smdk4210_v4l2_dqbuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_dqbuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_MMAP); +} + +int smdk4210_v4l2_dqbuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_dqbuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_USERPTR); +} + +int smdk4210_v4l2_reqbufs(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int count) +{ + struct v4l2_requestbuffers requestbuffers; + int rc; + + if (smdk4210_camera == NULL || count < 0) + return -EINVAL; + + requestbuffers.type = type; + requestbuffers.count = count; + requestbuffers.memory = memory; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_REQBUFS, &requestbuffers); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return requestbuffers.count; +} + +int smdk4210_v4l2_reqbufs_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int count) +{ + return smdk4210_v4l2_reqbufs(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_MMAP, count); +} + +int smdk4210_v4l2_reqbufs_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int count) +{ + return smdk4210_v4l2_reqbufs(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_USERPTR, count); +} + +int smdk4210_v4l2_querybuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int memory, int index) +{ + struct v4l2_buffer buffer; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + memset(&buffer, 0, sizeof(buffer)); + buffer.type = type; + buffer.memory = memory; + buffer.index = index; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_QUERYBUF, &buffer); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return buffer.length; +} + +int smdk4210_v4l2_querybuf_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index) +{ + return smdk4210_v4l2_querybuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_MEMORY_MMAP, index); +} + +int smdk4210_v4l2_querybuf_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int index) +{ + return smdk4210_v4l2_querybuf(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_MEMORY_USERPTR, index); +} + +int smdk4210_v4l2_querycap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int flags) +{ + struct v4l2_capability cap; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_QUERYCAP, &cap); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (!(cap.capabilities & flags)) + return -1; + + return 0; +} + +int smdk4210_v4l2_querycap_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_querycap(smdk4210_camera, smdk4210_v4l2_id, V4L2_CAP_VIDEO_CAPTURE); +} + +int smdk4210_v4l2_querycap_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_querycap(smdk4210_camera, smdk4210_v4l2_id, V4L2_CAP_VIDEO_OUTPUT); +} + +int smdk4210_v4l2_streamon(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type) +{ + enum v4l2_buf_type buf_type; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + buf_type = type; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_STREAMON, &buf_type); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_streamon_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_streamon(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE); +} + +int smdk4210_v4l2_streamon_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_streamon(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT); +} + +int smdk4210_v4l2_streamoff(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type) +{ + enum v4l2_buf_type buf_type; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + buf_type = type; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_STREAMOFF, &buf_type); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_streamoff_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_streamoff(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE); +} + +int smdk4210_v4l2_streamoff_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id) +{ + return smdk4210_v4l2_streamoff(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT); +} + +int smdk4210_v4l2_g_fmt(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int *width, int *height, int *fmt) +{ + struct v4l2_format format; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + format.type = type; + format.fmt.pix.field = V4L2_FIELD_NONE; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_G_FMT, &format); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (width != NULL) + *width = format.fmt.pix.width; + if (height != NULL) + *height = format.fmt.pix.height; + if (fmt != NULL) + *fmt = format.fmt.pix.pixelformat; + + return 0; +} + +int smdk4210_v4l2_g_fmt_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int *width, int *height, int *fmt) +{ + return smdk4210_v4l2_g_fmt(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + width, height, fmt); +} + +int smdk4210_v4l2_g_fmt_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int *width, int *height, int *fmt) +{ + return smdk4210_v4l2_g_fmt(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + width, height, fmt); +} + +int smdk4210_v4l2_s_fmt_pix(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int width, int height, int fmt, int priv) +{ + struct v4l2_format format; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + memset(&format, 0, sizeof(format)); + format.type = type; + format.fmt.pix.width = width; + format.fmt.pix.height = height; + format.fmt.pix.pixelformat = fmt; + format.fmt.pix.field = V4L2_FIELD_NONE; + format.fmt.pix.priv = priv; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_FMT, &format); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_s_fmt_pix_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int width, int height, int fmt, int priv) +{ + return smdk4210_v4l2_s_fmt_pix(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + width, height, fmt, priv); +} + +int smdk4210_v4l2_s_fmt_pix_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int width, int height, int fmt, int priv) +{ + return smdk4210_v4l2_s_fmt_pix(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + width, height, fmt, priv); +} + +int smdk4210_v4l2_s_fmt_win(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height) +{ + struct v4l2_format format; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + memset(&format, 0, sizeof(format)); + format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + format.fmt.win.w.left = left; + format.fmt.win.w.top = top; + format.fmt.win.w.width = width; + format.fmt.win.w.height = height; + + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_FMT, &format); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_enum_fmt(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int fmt) +{ + struct v4l2_fmtdesc fmtdesc; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + fmtdesc.type = type; + fmtdesc.index = 0; + + do { + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_ENUM_FMT, &fmtdesc); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (fmtdesc.pixelformat == (unsigned int) fmt) + return 0; + + fmtdesc.index++; + } while (rc >= 0); + + return -1; +} + +int smdk4210_v4l2_enum_fmt_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int fmt) +{ + return smdk4210_v4l2_enum_fmt(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + fmt); +} + +int smdk4210_v4l2_enum_fmt_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int fmt) +{ + return smdk4210_v4l2_enum_fmt(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + fmt); +} + +int smdk4210_v4l2_enum_input(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id) +{ + struct v4l2_input input; + int rc; + + if (smdk4210_camera == NULL || id < 0) + return -EINVAL; + + input.index = id; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_ENUMINPUT, &input); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (input.name[0] == '\0') + return -1; + + return 0; +} + +int smdk4210_v4l2_s_input(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id) +{ + struct v4l2_input input; + int rc; + + if (smdk4210_camera == NULL || id < 0) + return -EINVAL; + + input.index = id; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_INPUT, &input); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_g_ext_ctrls(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_ext_control *control, int count) +{ + struct v4l2_ext_controls controls; + int rc; + + if (smdk4210_camera == NULL || control == NULL) + return -EINVAL; + + memset(&controls, 0, sizeof(controls)); + controls.ctrl_class = V4L2_CTRL_CLASS_CAMERA; + controls.count = count; + controls.controls = control; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_G_EXT_CTRLS, &controls); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_g_ctrl(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id, int *value) +{ + struct v4l2_control control; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + control.id = id; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_G_CTRL, &control); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (value != NULL) + *value = control.value; + + return 0; +} + +int smdk4210_v4l2_s_ctrl(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int id, int value) +{ + struct v4l2_control control; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + control.id = id; + control.value = value; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_CTRL, &control); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return control.value; +} + +int smdk4210_v4l2_s_parm(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, struct v4l2_streamparm *streamparm) +{ + int rc; + + if (smdk4210_camera == NULL || streamparm == NULL) + return -EINVAL; + + streamparm->type = type; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_PARM, streamparm); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_s_parm_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_streamparm *streamparm) +{ + return smdk4210_v4l2_s_parm(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + streamparm); +} + +int smdk4210_v4l2_s_parm_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + struct v4l2_streamparm *streamparm) +{ + return smdk4210_v4l2_s_parm(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + streamparm); +} + +int smdk4210_v4l2_s_crop(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int type, int left, int top, int width, int height) +{ + struct v4l2_crop crop; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + crop.type = type; + crop.c.left = left; + crop.c.top = top; + crop.c.width = width; + crop.c.height = height; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_CROP, &crop); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} + +int smdk4210_v4l2_s_crop_cap(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height) +{ + return smdk4210_v4l2_s_crop(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, + left, top, width, height); +} + +int smdk4210_v4l2_s_crop_out(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + int left, int top, int width, int height) +{ + return smdk4210_v4l2_s_crop(smdk4210_camera, smdk4210_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, + left, top, width, height); +} + +int smdk4210_v4l2_g_fbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + void **base, int *width, int *height, int *fmt) +{ + struct v4l2_framebuffer framebuffer; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_G_FBUF, &framebuffer); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + if (base != NULL) + *base = framebuffer.base; + if (width != NULL) + *width = framebuffer.fmt.width; + if (height != NULL) + *height = framebuffer.fmt.height; + if (fmt != NULL) + *fmt = framebuffer.fmt.pixelformat; + + return 0; +} + +int smdk4210_v4l2_s_fbuf(struct smdk4210_camera *smdk4210_camera, int smdk4210_v4l2_id, + void *base, int width, int height, int fmt) +{ + struct v4l2_framebuffer framebuffer; + int rc; + + if (smdk4210_camera == NULL) + return -EINVAL; + + memset(&framebuffer, 0, sizeof(framebuffer)); + framebuffer.base = base; + framebuffer.fmt.width = width; + framebuffer.fmt.height = height; + framebuffer.fmt.pixelformat = fmt; + + rc = smdk4210_v4l2_ioctl(smdk4210_camera, smdk4210_v4l2_id, VIDIOC_S_FBUF, &framebuffer); + if (rc < 0) { + ALOGE("%s: ioctl failed", __func__); + return -1; + } + + return 0; +} -- cgit v1.1