/*
* 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
#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 = "800x450",
.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,
.video_snapshot_supported = 0,
.full_video_snap_supported = 0,
.recording_size = "1280x720",
.recording_size_values = "1920x1080,1280x720,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,action,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,
.video_snapshot_supported = 0,
.full_video_snap_supported = 0,
.recording_size = "640x480",
.recording_size_values = "720x480,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 = "none",
.scene_mode_values = "none",
.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);
if (exynos_camera->config->presets[id].params.video_snapshot_supported == 1)
exynos_param_string_set(exynos_camera, "video-snapshot-supported", "true");
else
exynos_param_string_set(exynos_camera, "video-snapshot-supported", "false");
if (exynos_camera->config->presets[id].params.full_video_snap_supported == 1)
exynos_param_string_set(exynos_camera, "full-video-snap-supported", "true");
else
exynos_param_string_set(exynos_camera, "full-video-snap-supported", "false");
// 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, "action") == 0)
scene_mode = SCENE_MODE_SPORTS;
else if (strcmp(scene_mode_string, "party") == 0)
scene_mode = SCENE_MODE_PARTY_INDOOR;
else if (strcmp(scene_mode_string, "candlelight") == 0)
scene_mode = SCENE_MODE_CANDLE_LIGHT;
else if (strcmp(scene_mode_string, "dusk-dawn") == 0)
scene_mode = SCENE_MODE_DUSK_DAWN;
else if (strcmp(scene_mode_string, "fall-color") == 0)
scene_mode = SCENE_MODE_FALL_COLOR;
else if (strcmp(scene_mode_string, "back-light") == 0)
scene_mode = SCENE_MODE_BACK_LIGHT;
else if (strcmp(scene_mode_string, "text") == 0)
scene_mode = SCENE_MODE_TEXT;
else
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) { // Progress
usleep(10000); // Sleep 10 ms
} else if (auto_focus_status == M5MO_AF_STATUS_SUCCESS || auto_focus_status == M5MO_AF_STATUS_1ST_SUCCESS) { // Success
auto_focus_result = 1;
pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
goto thread_exit;
} else {
auto_focus_result = 0;
ALOGE("AF failed or unknown result flag: 0x%x", auto_focus_status);
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, 0, V4L2_CID_CAMERA_FOCUS_MODE, FOCUS_MODE_CONTINOUS);
if (rc < 0) {
ALOGE("%s: s ctrl 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_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, FOCUS_MODE_AUTO);
if (rc < 0) {
ALOGE("%s: s ctrl failed!", __func__);
}
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_width == 640 || 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;
}
char *recording_hint_string = exynos_param_string_get(exynos_camera, "recording-hint");
int cam_mode = 0; // photo
if (recording_hint_string != NULL && strcmp(recording_hint_string, "true") == 0) {
cam_mode = 1; // video
}
exynos_param_int_set(exynos_camera, "cam_mode", cam_mode);
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,
};