summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
authorcodeworkx <codeworkx@cyanogenmod.org>2013-02-14 18:49:02 +0000
committerXpLoDWilD <xplodgui@gmail.com>2013-02-17 20:28:22 +0000
commit2806d8bfe0361daab80c43c9e2e38205b780237d (patch)
tree8b539c8ca1363827346183b240be58c7deb8dff0 /camera
parent2bd22a00bd6c148ddbd453896b7639d9eb86ba26 (diff)
downloaddevice_samsung_galaxys2-common-2806d8bfe0361daab80c43c9e2e38205b780237d.zip
device_samsung_galaxys2-common-2806d8bfe0361daab80c43c9e2e38205b780237d.tar.gz
device_samsung_galaxys2-common-2806d8bfe0361daab80c43c9e2e38205b780237d.tar.bz2
galaxys2: update for new kernel, cleanup, replicant camera hal
Camera HAL from: http://gitorious.org/replicant/device_samsung_galaxys2 Change-Id: I4191110be5b3368c608333d724f4217894dab4ac
Diffstat (limited to 'camera')
-rw-r--r--camera/Android.mk33
-rw-r--r--camera/CameraWrapper.cpp596
-rw-r--r--camera/MODULE_LICENSE_GPL0
-rw-r--r--camera/NOTICE674
-rw-r--r--camera/exynos_camera.c2854
-rw-r--r--camera/exynos_camera.h425
-rw-r--r--camera/exynos_exif.c797
-rw-r--r--camera/exynos_param.c520
-rw-r--r--camera/exynos_v4l2.c796
9 files changed, 6094 insertions, 601 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index 46cce24..352a36d 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -1,15 +1,38 @@
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
LOCAL_PATH := $(call my-dir)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- CameraWrapper.cpp
+ exynos_camera.c \
+ exynos_exif.c \
+ exynos_param.c \
+ exynos_v4l2.c
+
+LOCAL_C_INCLUDES := \
+ hardware/samsung/exynos4/hal/include
-LOCAL_SHARED_LIBRARIES := \
- libhardware liblog libcamera_client libutils
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libcamera_client libhardware libs5pjpeg
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE := camera.$(TARGET_BOOTLOADER_BOARD_NAME)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-LOCAL_MODULE := camera.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
-#include $(BUILD_HEAPTRACKED_SHARED_LIBRARY)
diff --git a/camera/CameraWrapper.cpp b/camera/CameraWrapper.cpp
deleted file mode 100644
index 6e2f8c0..0000000
--- a/camera/CameraWrapper.cpp
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * Copyright (C) 2012, The CyanogenMod Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
-* @file CameraWrapper.cpp
-*
-* This file wraps a vendor camera module.
-*
-*/
-
-
-#define LOG_NDEBUG 0
-//#define LOG_PARAMETERS
-
-#define LOG_TAG "CameraWrapper"
-#include <cutils/log.h>
-
-#include <utils/threads.h>
-#include <utils/String8.h>
-#include <hardware/hardware.h>
-#include <hardware/camera.h>
-#include <camera/Camera.h>
-#include <camera/CameraParameters.h>
-
-static android::Mutex gCameraWrapperLock;
-static camera_module_t *gVendorModule = 0;
-
-static int camera_device_open(const hw_module_t* module, const char* name,
- hw_device_t** device);
-static int camera_device_close(hw_device_t* device);
-static int camera_get_number_of_cameras(void);
-static int camera_get_camera_info(int camera_id, struct camera_info *info);
-
-static struct hw_module_methods_t camera_module_methods = {
- open: camera_device_open
-};
-
-camera_module_t HAL_MODULE_INFO_SYM = {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: CAMERA_HARDWARE_MODULE_ID,
- name: "Exynos4x12 Camera Wrapper",
- author: "Teamhacksung <info@teamhacksung.org>",
- methods: &camera_module_methods,
- dso: NULL, /* remove compilation warnings */
- reserved: {0}, /* remove compilation warnings */
- },
- get_number_of_cameras: camera_get_number_of_cameras,
- get_camera_info: camera_get_camera_info,
-};
-
-typedef struct wrapper_camera_device {
- camera_device_t base;
- int id;
- camera_device_t *vendor;
-} wrapper_camera_device_t;
-
-#define VENDOR_CALL(device, func, ...) ({ \
- wrapper_camera_device_t *__wrapper_dev = (wrapper_camera_device_t*) device; \
- __wrapper_dev->vendor->ops->func(__wrapper_dev->vendor, ##__VA_ARGS__); \
-})
-
-#define CAMERA_ID(device) (((wrapper_camera_device_t *)(device))->id)
-
-static int check_vendor_module()
-{
- int rv = 0;
- ALOGV("%s", __FUNCTION__);
-
- if(gVendorModule)
- return 0;
-
- rv = hw_get_module("vendor-camera", (const hw_module_t **)&gVendorModule);
- if (rv)
- ALOGE("failed to open vendor camera module");
- return rv;
-}
-
-const static char * iso_values[] = {"auto,ISO50,ISO100,ISO200,ISO400,ISO800","auto"};
-const static char * video_preview_sizes[] = {"1920x1080,1280x720,640x480",
- "640x480,352x288,320x240,176x144"};
-
-static char * camera_fixup_getparams(int id, const char * settings)
-{
- android::CameraParameters params;
- params.unflatten(android::String8(settings));
-
- // fix params here
-
- params.remove(android::CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
-
- if(params.get("cam_mode") && !strcmp(params.get("cam_mode"), "1")) {
- params.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, video_preview_sizes[id]);
- const char* videoSize = params.get(android::CameraParameters::KEY_VIDEO_SIZE);
- params.set(android::CameraParameters::KEY_PREVIEW_SIZE, videoSize);
- }
-
- params.set(android::CameraParameters::KEY_SUPPORTED_ISO_MODES, iso_values[id]);
-
- android::String8 strParams = params.flatten();
- char *ret = strdup(strParams.string());
-
- ALOGD("%s: get parameters fixed up", __FUNCTION__);
- return ret;
-}
-
-char * camera_fixup_setparams(int id, const char * settings)
-{
- android::CameraParameters params;
- params.unflatten(android::String8(settings));
-
- // fix params here
- if(params.get("iso")) {
- const char* isoMode = params.get(android::CameraParameters::KEY_ISO_MODE);
- if(strcmp(isoMode, "ISO50") == 0)
- params.set(android::CameraParameters::KEY_ISO_MODE, "50");
- else if(strcmp(isoMode, "ISO100") == 0)
- params.set(android::CameraParameters::KEY_ISO_MODE, "100");
- else if(strcmp(isoMode, "ISO200") == 0)
- params.set(android::CameraParameters::KEY_ISO_MODE, "200");
- else if(strcmp(isoMode, "ISO400") == 0)
- params.set(android::CameraParameters::KEY_ISO_MODE, "400");
- else if(strcmp(isoMode, "ISO800") == 0)
- params.set(android::CameraParameters::KEY_ISO_MODE, "800");
- }
-
- android::String8 strParams = params.flatten();
- char *ret = strdup(strParams.string());
-
- ALOGD("%s: set parameters fixed up", __FUNCTION__);
- return ret;
-}
-
-/*******************************************************************
- * implementation of camera_device_ops functions
- *******************************************************************/
-
-int camera_set_preview_window(struct camera_device * device,
- struct preview_stream_ops *window)
-{
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device || !window)
- return -EINVAL;
-
- return VENDOR_CALL(device, set_preview_window, window);
-}
-
-void camera_set_callbacks(struct camera_device * device,
- camera_notify_callback notify_cb,
- camera_data_callback data_cb,
- camera_data_timestamp_callback data_cb_timestamp,
- camera_request_memory get_memory,
- void *user)
-{
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
- ALOGV("%s", __FUNCTION__);
-
- if(!device)
- return;
-
- VENDOR_CALL(device, set_callbacks, notify_cb, data_cb, data_cb_timestamp, get_memory, user);
-}
-
-void camera_enable_msg_type(struct camera_device * device, int32_t msg_type)
-{
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
- ALOGV("%s", __FUNCTION__);
-
- if(!device)
- return;
-
- VENDOR_CALL(device, enable_msg_type, msg_type);
-}
-
-void camera_disable_msg_type(struct camera_device * device, int32_t msg_type)
-{
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
- ALOGV("%s", __FUNCTION__);
-
- if(!device)
- return;
-
- VENDOR_CALL(device, disable_msg_type, msg_type);
-}
-
-int camera_msg_type_enabled(struct camera_device * device, int32_t msg_type)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return 0;
-
- return VENDOR_CALL(device, msg_type_enabled, msg_type);
-}
-
-int camera_start_preview(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, start_preview);
-}
-
-void camera_stop_preview(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return;
-
- VENDOR_CALL(device, stop_preview);
-}
-
-int camera_preview_enabled(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, preview_enabled);
-}
-
-int camera_store_meta_data_in_buffers(struct camera_device * device, int enable)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, store_meta_data_in_buffers, enable);
-}
-
-int camera_start_recording(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return EINVAL;
-
- return VENDOR_CALL(device, start_recording);
-}
-
-void camera_stop_recording(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return;
-
-
- VENDOR_CALL(device, stop_recording);
-}
-
-int camera_recording_enabled(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, recording_enabled);
-}
-
-void camera_release_recording_frame(struct camera_device * device,
- const void *opaque)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return;
-
- VENDOR_CALL(device, release_recording_frame, opaque);
-}
-
-int camera_auto_focus(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
-
- return VENDOR_CALL(device, auto_focus);
-}
-
-int camera_cancel_auto_focus(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- // Samsung camera HAL restarts focus (CAF_RESTART) when we cancel auto focus.
- // Cancel auto focus is called just before pic is taken in autofocus mode, thus
- // the HAL crashes.
- return 0;
- //return VENDOR_CALL(device, cancel_auto_focus);
-}
-
-int camera_take_picture(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, take_picture);
-}
-
-int camera_cancel_picture(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, take_picture);
-}
-
-int camera_set_parameters(struct camera_device * device, const char *params)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- char *tmp = NULL;
- tmp = camera_fixup_setparams(CAMERA_ID(device), params);
-
-#ifdef LOG_PARAMETERS
- __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, tmp);
-#endif
-
- int ret = VENDOR_CALL(device, set_parameters, tmp);
- return ret;
-}
-
-char* camera_get_parameters(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return NULL;
-
- char* params = VENDOR_CALL(device, get_parameters);
-
-#ifdef LOG_PARAMETERS
- __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, params);
-#endif
-
- char * tmp = camera_fixup_getparams(CAMERA_ID(device), params);
- VENDOR_CALL(device, put_parameters, params);
- params = tmp;
-
-#ifdef LOG_PARAMETERS
- __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, params);
-#endif
-
- return params;
-}
-
-static void camera_put_parameters(struct camera_device *device, char *params)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(params)
- free(params);
-}
-
-int camera_send_command(struct camera_device * device,
- int32_t cmd, int32_t arg1, int32_t arg2)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return -EINVAL;
-
- /* send_command causes the camera hal do to unexpected things like lockups.
- * don't pass any command to the vendor hal to prevent this */
- return 0;
- //return VENDOR_CALL(device, send_command, cmd, arg1, arg2);
-}
-
-void camera_release(struct camera_device * device)
-{
- ALOGV("%s", __FUNCTION__);
- ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera_device_t*)device)->vendor));
-
- if(!device)
- return;
-
- VENDOR_CALL(device, release);
-}
-
-int camera_dump(struct camera_device * device, int fd)
-{
- if(!device)
- return -EINVAL;
-
- return VENDOR_CALL(device, dump, fd);
-}
-
-extern "C" void heaptracker_free_leaked_memory(void);
-
-int camera_device_close(hw_device_t* device)
-{
- int ret = 0;
- wrapper_camera_device_t *wrapper_dev = NULL;
-
- ALOGV("%s", __FUNCTION__);
-
- android::Mutex::Autolock lock(gCameraWrapperLock);
-
- if (!device) {
- ret = -EINVAL;
- goto done;
- }
-
- wrapper_dev = (wrapper_camera_device_t*) device;
-
- wrapper_dev->vendor->common.close((hw_device_t*)wrapper_dev->vendor);
- if (wrapper_dev->base.ops)
- free(wrapper_dev->base.ops);
- free(wrapper_dev);
-done:
-#ifdef HEAPTRACKER
- heaptracker_free_leaked_memory();
-#endif
- return ret;
-}
-
-/*******************************************************************
- * implementation of camera_module functions
- *******************************************************************/
-
-/* open device handle to one of the cameras
- *
- * assume camera service will keep singleton of each camera
- * so this function will always only be called once per camera instance
- */
-
-int camera_device_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
-{
- int rv = 0;
- int num_cameras = 0;
- int cameraid;
- wrapper_camera_device_t* camera_device = NULL;
- camera_device_ops_t* camera_ops = NULL;
-
- android::Mutex::Autolock lock(gCameraWrapperLock);
-
- ALOGV("camera_device open");
-
- if (name != NULL) {
- if (check_vendor_module())
- return -EINVAL;
-
- cameraid = atoi(name);
- num_cameras = gVendorModule->get_number_of_cameras();
-
- if(cameraid > num_cameras)
- {
- ALOGE("camera service provided cameraid out of bounds, "
- "cameraid = %d, num supported = %d",
- cameraid, num_cameras);
- rv = -EINVAL;
- goto fail;
- }
-
- camera_device = (wrapper_camera_device_t*)malloc(sizeof(*camera_device));
- if(!camera_device)
- {
- ALOGE("camera_device allocation fail");
- rv = -ENOMEM;
- goto fail;
- }
- memset(camera_device, 0, sizeof(*camera_device));
- camera_device->id = cameraid;
-
- if(rv = gVendorModule->common.methods->open((const hw_module_t*)gVendorModule, name, (hw_device_t**)&(camera_device->vendor)))
- {
- ALOGE("vendor camera open fail");
- goto fail;
- }
- ALOGV("%s: got vendor camera device 0x%08X", __FUNCTION__, (uintptr_t)(camera_device->vendor));
-
- camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops));
- if(!camera_ops)
- {
- ALOGE("camera_ops allocation fail");
- rv = -ENOMEM;
- goto fail;
- }
-
- memset(camera_ops, 0, sizeof(*camera_ops));
-
- camera_device->base.common.tag = HARDWARE_DEVICE_TAG;
- camera_device->base.common.version = 0;
- camera_device->base.common.module = (hw_module_t *)(module);
- camera_device->base.common.close = camera_device_close;
- camera_device->base.ops = camera_ops;
-
- camera_ops->set_preview_window = camera_set_preview_window;
- camera_ops->set_callbacks = camera_set_callbacks;
- camera_ops->enable_msg_type = camera_enable_msg_type;
- camera_ops->disable_msg_type = camera_disable_msg_type;
- camera_ops->msg_type_enabled = camera_msg_type_enabled;
- camera_ops->start_preview = camera_start_preview;
- camera_ops->stop_preview = camera_stop_preview;
- camera_ops->preview_enabled = camera_preview_enabled;
- camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;
- camera_ops->start_recording = camera_start_recording;
- camera_ops->stop_recording = camera_stop_recording;
- camera_ops->recording_enabled = camera_recording_enabled;
- camera_ops->release_recording_frame = camera_release_recording_frame;
- camera_ops->auto_focus = camera_auto_focus;
- camera_ops->cancel_auto_focus = camera_cancel_auto_focus;
- camera_ops->take_picture = camera_take_picture;
- camera_ops->cancel_picture = camera_cancel_picture;
- camera_ops->set_parameters = camera_set_parameters;
- camera_ops->get_parameters = camera_get_parameters;
- camera_ops->put_parameters = camera_put_parameters;
- camera_ops->send_command = camera_send_command;
- camera_ops->release = camera_release;
- camera_ops->dump = camera_dump;
-
- *device = &camera_device->base.common;
- }
-
- return rv;
-
-fail:
- if(camera_device) {
- free(camera_device);
- camera_device = NULL;
- }
- if(camera_ops) {
- free(camera_ops);
- camera_ops = NULL;
- }
- *device = NULL;
- return rv;
-}
-
-int camera_get_number_of_cameras(void)
-{
- ALOGV("%s", __FUNCTION__);
- if (check_vendor_module())
- return 0;
- return gVendorModule->get_number_of_cameras();
-}
-
-int camera_get_camera_info(int camera_id, struct camera_info *info)
-{
- ALOGV("%s", __FUNCTION__);
- if (check_vendor_module())
- return 0;
- return gVendorModule->get_camera_info(camera_id, info);
-}
diff --git a/camera/MODULE_LICENSE_GPL b/camera/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/MODULE_LICENSE_GPL
diff --git a/camera/NOTICE b/camera/NOTICE
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/camera/NOTICE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/camera/exynos_camera.c b/camera/exynos_camera.c
new file mode 100644
index 0000000..2a73bd7
--- /dev/null
+++ b/camera/exynos_camera.c
@@ -0,0 +1,2854 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+#include <jpeg_api.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#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 = 20,
+ .preview_fps_range_values = "(7000,30000)",
+ .preview_fps_range = "7000,30000",
+
+ .picture_size_values = "3264x2448,3264x1968,2048x1536,2048x1232,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 = 15,
+ .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;
+ 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 ;
+
+ 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;
+ } else {
+ force = 0;
+ }
+
+ // 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_height != 0 &&
+ picture_width != exynos_camera->picture_width &&
+ picture_height != exynos_camera->picture_height) {
+ exynos_camera->picture_width = picture_width;
+ 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_mode_string = exynos_param_string_get(exynos_camera, "focus-mode");
+ if (focus_mode_string != NULL) {
+ 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) {
+ exynos_camera->focus_mode = focus_mode;
+ rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode);
+ if (rc < 0)
+ ALOGE("%s: s ctrl failed!", __func__);
+ }
+ }
+
+ 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__);
+
+ 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__);
+ }
+ }
+
+ // 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;
+ }
+
+ switch (auto_focus_status) {
+ case 0x5: // in progress
+ usleep(500);
+ break;
+ case 0x2: // success
+ auto_focus_result = 1;
+ pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+ goto thread_exit;
+ case 0x0: // fail
+ auto_focus_result = 0;
+ pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+ goto thread_exit;
+ default:
+ ALOGE("Unknown AF 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 = (int) ((float) width * (float) height * format_bpp);
+ 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: Frame size mismatch: %d/%d", __func__, frame_size, 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->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_width == 640 || exynos_camera->preview_buffers_count <= 0)
+ 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_camera.h b/camera/exynos_camera.h
new file mode 100644
index 0000000..4d7edc6
--- /dev/null
+++ b/camera/exynos_camera.h
@@ -0,0 +1,425 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <videodev2.h>
+#include <videodev2_exynos_media.h>
+#include <videodev2_exynos_camera.h>
+
+#include <Exif.h>
+
+#include <hardware/hardware.h>
+#include <hardware/camera.h>
+
+#ifndef _EXYNOS_CAMERA_H_
+#define _EXYNOS_CAMERA_H_
+
+#define EXYNOS_CAMERA_MAX_PRESETS_COUNT 2
+#define EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT 4
+#define EXYNOS_CAMERA_MIN_BUFFERS_COUNT 2
+#define EXYNOS_CAMERA_MAX_BUFFERS_COUNT 8
+
+#define EXYNOS_CAMERA_MSG_ENABLED(msg) \
+ (exynos_camera->messages_enabled & msg)
+#define EXYNOS_CAMERA_CALLBACK_DEFINED(cb) \
+ (exynos_camera->callbacks.cb != NULL)
+
+/*
+ * Structures
+ */
+
+struct list_head {
+ struct list_head *next;
+ struct list_head *prev;
+};
+
+enum exynos_param_type {
+ EXYNOS_PARAM_INT,
+ EXYNOS_PARAM_FLOAT,
+ EXYNOS_PARAM_STRING,
+};
+
+union exynos_param_data {
+ int integer;
+ float floating;
+ char *string;
+};
+
+struct exynos_param {
+ struct list_head list;
+
+ char *key;
+ union exynos_param_data data;
+ enum exynos_param_type type;
+};
+
+struct exynos_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 exynos_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 exynos_camera_params params;
+};
+
+struct exynos_v4l2_node {
+ int id;
+ char *node;
+};
+
+struct exynox_camera_config {
+ struct exynos_camera_preset *presets;
+ int presets_count;
+
+ struct exynos_v4l2_node *v4l2_nodes;
+ int v4l2_nodes_count;
+};
+
+struct exynos_camera_callbacks {
+ camera_notify_callback notify;
+ camera_data_callback data;
+ camera_data_timestamp_callback data_timestamp;
+ camera_request_memory request_memory;
+ void *user;
+};
+
+struct exynos_camera {
+ int v4l2_fds[EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT];
+
+ struct exynox_camera_config *config;
+ struct exynos_param *params;
+
+ struct exynos_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_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 exynos_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 exynos_v4l2_ext_control {
+ __u32 id;
+ __u32 size;
+ __u32 reserved2[1];
+ union {
+ __s32 value;
+ __s64 value64;
+ char *string;
+ } data;
+} __attribute__ ((packed));
+
+/*
+ * Camera
+ */
+
+int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id);
+int exynos_camera_params_apply(struct exynos_camera *exynos_camera);
+
+int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera);
+void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera);
+
+int exynos_camera_picture(struct exynos_camera *exynos_camera);
+int exynos_camera_picture_start(struct exynos_camera *exynos_camera);
+
+int exynos_camera_preview(struct exynos_camera *exynos_camera);
+int exynos_camera_preview_start(struct exynos_camera *exynos_camera);
+void exynos_camera_preview_stop(struct exynos_camera *exynos_camera);
+
+/*
+ * EXIF
+ */
+
+int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera,
+ exif_attribute_t *exif_attributes);
+int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera,
+ exif_attribute_t *exif_attributes);
+
+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);
+
+/*
+ * Param
+ */
+
+int exynos_param_int_get(struct exynos_camera *exynos_camera,
+ char *key);
+float exynos_param_float_get(struct exynos_camera *exynos_camera,
+ char *key);
+char *exynos_param_string_get(struct exynos_camera *exynos_camera,
+ char *key);
+
+int exynos_param_int_set(struct exynos_camera *exynos_camera,
+ char *key, int integer);
+int exynos_param_float_set(struct exynos_camera *exynos_camera,
+ char *key, float floating);
+int exynos_param_string_set(struct exynos_camera *exynos_camera,
+ char *key, char *string);
+
+char *exynos_params_string_get(struct exynos_camera *exynos_camera);
+int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string);
+
+/*
+ * V4L2
+ */
+
+// Utils
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// File ops
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int id);
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int id);
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int id, int request, void *data);
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// VIDIOC
+int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int index);
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index);
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index);
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory);
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int count);
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int count);
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int count);
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int index);
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index);
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index);
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int flags);
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type);
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type);
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int *width, int *height, int *fmt);
+int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height);
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int fmt);
+int exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int fmt);
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int fmt);
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id);
+int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id);
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_ext_control *control, int count);
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id, int *value);
+int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id, int value);
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_crop(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int left, int top, int width, int height);
+int exynos_v4l2_s_crop_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height);
+int exynos_v4l2_s_crop_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height);
+int exynos_v4l2_g_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ void **base, int *width, int *height, int *fmt);
+int exynos_v4l2_s_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ void *base, int width, int height, int fmt);
+
+#endif
diff --git a/camera/exynos_exif.c b/camera/exynos_exif.c
new file mode 100644
index 0000000..0f6c4f1
--- /dev/null
+++ b/camera/exynos_exif.c
@@ -0,0 +1,797 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <Exif.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include "exynos_camera.h"
+
+/*
+ * FIXME: This EXIF implementation doesn't work very well, it needs to be fixed.
+ */
+
+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_DEF_APEX_DEN;
+ exif_attributes->aperture.den = EXIF_DEF_APEX_DEN;
+ exif_attributes->max_aperture.num = av * EXIF_DEF_APEX_DEN;
+ 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 * 10000) / 1;
+ gps_longitude = (long) (gps_longitude_float * 10000) / 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 / 10000.0);
+ gps_longitude_abs = fabs(gps_longitude / 10000.0);
+ gps_altitude_abs = fabs(gps_altitude / 100.0);
+
+ exif_attributes->gps_latitude[0].num = (uint32_t) gps_latitude_abs;
+ exif_attributes->gps_latitude[0].den = 1;
+ 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 = 1;
+ 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 = 1;
+
+ 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 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 = 1;
+ exif_attributes->shutter_speed.den = shutter_speed;
+
+ exposure_time = shutter_speed;
+ rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EXPTIME,
+ &exposure_time);
+ if (rc < 0)
+ ALOGE("%s: g ctrl failed!", __func__);
+
+ exif_attributes->exposure_time.num = 1;
+ exif_attributes->exposure_time.den = exposure_time;
+
+ rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO,
+ &iso_speed);
+ if (rc < 0)
+ ALOGE("%s: g ctrl failed!", __func__);
+
+ exif_attributes->iso_speed_rating = iso_speed;
+
+ 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_DEF_APEX_DEN;
+ 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->flash_mode == FLASH_MODE_BASE)
+ exif_attributes->flash = EXIF_DEF_FLASH;
+ else
+ exif_attributes->flash = exynos_camera->flash_mode;
+
+ 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 += count * length;
+ }
+
+ 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[] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 };
+ 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, 1, NULL, NULL, &exif_attributes->exif_version, sizeof(exif_attributes->exif_version));
+ 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->shutter_speed));
+ 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_LONG, 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_LONG, 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_LONG, 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_LONG, 4, NULL, NULL, &exif_attributes->gps_version_id, 1);
+ pointer += count;
+
+ count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE_REF,
+ EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_latitude_ref, 1);
+ 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, 1);
+ 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]));
+
+ count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE_REF,
+ EXIF_TYPE_BYTE, 1, NULL, NULL, &exif_attributes->gps_altitude_ref, 1);
+ 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, 1);
+ 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_LONG, 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
new file mode 100644
index 0000000..0c4ecfd
--- /dev/null
+++ b/camera/exynos_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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#define LOG_TAG "exynos_param"
+#include <utils/Log.h>
+
+#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, &param->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/exynos_v4l2.c b/camera/exynos_v4l2.c
new file mode 100644
index 0000000..449e151
--- /dev/null
+++ b/camera/exynos_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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+
+#define LOG_TAG "exynos_v4l2"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+/*
+ * Utils
+ */
+
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ int index;
+ int i;
+
+ if (exynos_camera == NULL || exynos_camera->config == NULL ||
+ exynos_camera->config->v4l2_nodes == NULL)
+ return -EINVAL;
+
+ if (exynos_v4l2_id > exynos_camera->config->v4l2_nodes_count)
+ return -1;
+
+ index = -1;
+ for (i=0 ; i < exynos_camera->config->v4l2_nodes_count ; i++) {
+ if (exynos_camera->config->v4l2_nodes[i].id == exynos_v4l2_id &&
+ exynos_camera->config->v4l2_nodes[i].node != NULL) {
+ index = i;
+ }
+ }
+
+ return index;
+}
+
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ int index;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+ if (index < 0)
+ return -1;
+
+ return exynos_camera->v4l2_fds[index];
+}
+
+/*
+ * File ops
+ */
+
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ char *node;
+ int index;
+ int fd;
+
+ if (exynos_camera == NULL || exynos_camera->config == NULL ||
+ exynos_camera->config->v4l2_nodes == NULL)
+ return -EINVAL;
+
+ index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+ if (index < 0) {
+ ALOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+ return -1;
+ }
+
+ node = exynos_camera->config->v4l2_nodes[index].node;
+ fd = open(node, O_RDWR);
+ if (fd < 0) {
+ ALOGE("%s: Unable to open v4l2 node #%d", __func__, exynos_v4l2_id);
+ return -1;
+ }
+
+ exynos_camera->v4l2_fds[index] = fd;
+
+ return 0;
+}
+
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ int index;
+
+ if (exynos_camera == NULL || exynos_camera->config == NULL ||
+ exynos_camera->config->v4l2_nodes == NULL)
+ return;
+
+ index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+ if (index < 0) {
+ ALOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+ return;
+ }
+
+ if (exynos_camera->v4l2_fds[index] > 0)
+ close(exynos_camera->v4l2_fds[index]);
+
+ exynos_camera->v4l2_fds[index] = -1;
+}
+
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int request, void *data)
+{
+ int fd;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+ if (fd < 0) {
+ ALOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_v4l2_id);
+ return -1;
+ }
+
+ return ioctl(fd, request, data);
+}
+
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ struct pollfd events;
+ int fd;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+ if (fd < 0) {
+ ALOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_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 exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int index)
+{
+ struct v4l2_buffer buffer;
+ int rc;
+
+ if (exynos_camera == NULL || index < 0)
+ return -EINVAL;
+
+ buffer.type = type;
+ buffer.memory = memory;
+ buffer.index = index;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QBUF, &buffer);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index)
+{
+ return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_MEMORY_MMAP, index);
+}
+
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index)
+{
+ return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_MEMORY_USERPTR, index);
+}
+
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory)
+{
+ struct v4l2_buffer buffer;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ memset(&buffer, 0, sizeof(buffer));
+ buffer.type = type;
+ buffer.memory = memory;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_DQBUF, &buffer);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return buffer.index;
+}
+
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_MEMORY_MMAP);
+}
+
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_MEMORY_USERPTR);
+}
+
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int count)
+{
+ struct v4l2_requestbuffers requestbuffers;
+ int rc;
+
+ if (exynos_camera == NULL || count < 0)
+ return -EINVAL;
+
+ requestbuffers.type = type;
+ requestbuffers.count = count;
+ requestbuffers.memory = memory;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_REQBUFS, &requestbuffers);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return requestbuffers.count;
+}
+
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int count)
+{
+ return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_MEMORY_MMAP, count);
+}
+
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int count)
+{
+ return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_MEMORY_USERPTR, count);
+}
+
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int memory, int index)
+{
+ struct v4l2_buffer buffer;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ memset(&buffer, 0, sizeof(buffer));
+ buffer.type = type;
+ buffer.memory = memory;
+ buffer.index = index;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYBUF, &buffer);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return buffer.length;
+}
+
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index)
+{
+ return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_MEMORY_MMAP, index);
+}
+
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int index)
+{
+ return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_MEMORY_USERPTR, index);
+}
+
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int flags)
+{
+ struct v4l2_capability cap;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYCAP, &cap);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ if (!(cap.capabilities & flags))
+ return -1;
+
+ return 0;
+}
+
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type)
+{
+ enum v4l2_buf_type buf_type;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ buf_type = type;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMON, &buf_type);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type)
+{
+ enum v4l2_buf_type buf_type;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ buf_type = type;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMOFF, &buf_type);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+ return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int *width, int *height, int *fmt)
+{
+ struct v4l2_format format;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ format.type = type;
+ format.fmt.pix.field = V4L2_FIELD_NONE;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_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 exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int *width, int *height, int *fmt)
+{
+ return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ width, height, fmt);
+}
+
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int *width, int *height, int *fmt)
+{
+ return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ width, height, fmt);
+}
+
+int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int width, int height, int fmt, int priv)
+{
+ struct v4l2_format format;
+ int rc;
+
+ if (exynos_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 = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int width, int height, int fmt, int priv)
+{
+ return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ width, height, fmt, priv);
+}
+
+int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int width, int height, int fmt, int priv)
+{
+ return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ width, height, fmt, priv);
+}
+
+int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height)
+{
+ struct v4l2_format format;
+ int rc;
+
+ if (exynos_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 = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int fmt)
+{
+ struct v4l2_fmtdesc fmtdesc;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ fmtdesc.type = type;
+ fmtdesc.index = 0;
+
+ do {
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_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 exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int fmt)
+{
+ return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ fmt);
+}
+
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int fmt)
+{
+ return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ fmt);
+}
+
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id)
+{
+ struct v4l2_input input;
+ int rc;
+
+ if (exynos_camera == NULL || id < 0)
+ return -EINVAL;
+
+ input.index = id;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_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 exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id)
+{
+ struct v4l2_input input;
+ int rc;
+
+ if (exynos_camera == NULL || id < 0)
+ return -EINVAL;
+
+ input.index = id;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_INPUT, &input);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_ext_control *control, int count)
+{
+ struct v4l2_ext_controls controls;
+ int rc;
+
+ if (exynos_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 = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_EXT_CTRLS, &controls);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id, int *value)
+{
+ struct v4l2_control control;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ control.id = id;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_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 exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int id, int value)
+{
+ struct v4l2_control control;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ control.id = id;
+ control.value = value;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_CTRL, &control);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return control.value;
+}
+
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, struct v4l2_streamparm *streamparm)
+{
+ int rc;
+
+ if (exynos_camera == NULL || streamparm == NULL)
+ return -EINVAL;
+
+ streamparm->type = type;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_PARM, streamparm);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_streamparm *streamparm)
+{
+ return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ streamparm);
+}
+
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ struct v4l2_streamparm *streamparm)
+{
+ return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ streamparm);
+}
+
+int exynos_v4l2_s_crop(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int type, int left, int top, int width, int height)
+{
+ struct v4l2_crop crop;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ crop.type = type;
+ crop.c.left = left;
+ crop.c.top = top;
+ crop.c.width = width;
+ crop.c.height = height;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_CROP, &crop);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int exynos_v4l2_s_crop_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height)
+{
+ return exynos_v4l2_s_crop(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ left, top, width, height);
+}
+
+int exynos_v4l2_s_crop_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ int left, int top, int width, int height)
+{
+ return exynos_v4l2_s_crop(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ left, top, width, height);
+}
+
+int exynos_v4l2_g_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ void **base, int *width, int *height, int *fmt)
+{
+ struct v4l2_framebuffer framebuffer;
+ int rc;
+
+ if (exynos_camera == NULL)
+ return -EINVAL;
+
+ rc = exynos_v4l2_ioctl(exynos_camera, exynos_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 exynos_v4l2_s_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+ void *base, int width, int height, int fmt)
+{
+ struct v4l2_framebuffer framebuffer;
+ int rc;
+
+ if (exynos_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 = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FBUF, &framebuffer);
+ if (rc < 0) {
+ ALOGE("%s: ioctl failed", __func__);
+ return -1;
+ }
+
+ return 0;
+}