diff options
author | Jiyoung Shin <idon.shin@samsung.com> | 2012-04-02 16:22:36 -0700 |
---|---|---|
committer | Dima Zavin <dima@android.com> | 2012-05-07 11:26:48 -0700 |
commit | 9426c428f0ffede2ee24d397912f7db84c56c3f7 (patch) | |
tree | c34d90c78163ec171df4f2c52a2a6e7e3922f1e6 /libcamera | |
parent | 564463a90717018a0094466d704b75bccf8d6b1d (diff) | |
download | exynos5-9426c428f0ffede2ee24d397912f7db84c56c3f7.tar.gz |
hardware: exynos5: add initial libcamera directory
Change-Id: I29abd427ac0554019ce9f66a272ec214779cf87b
Signed-off-by: Jiyoung Shin <idon.shin@samsung.com>
Diffstat (limited to 'libcamera')
-rw-r--r-- | libcamera/Android.mk | 28 | ||||
-rw-r--r-- | libcamera/ExynosCamera.cpp | 4743 | ||||
-rw-r--r-- | libcamera/ExynosCameraHWInterface.cpp | 4501 | ||||
-rw-r--r-- | libcamera/ExynosCameraHWInterface.h | 328 | ||||
-rw-r--r-- | libcamera/ExynosExif.h | 231 | ||||
-rw-r--r-- | libcamera/ExynosJpegEncoderForCamera.cpp | 1047 | ||||
-rw-r--r-- | libcamera/ExynosJpegEncoderForCamera.h | 159 | ||||
-rw-r--r-- | libcamera/NOTICE | 190 |
8 files changed, 11227 insertions, 0 deletions
diff --git a/libcamera/Android.mk b/libcamera/Android.mk new file mode 100644 index 0000000..2729a2f --- /dev/null +++ b/libcamera/Android.mk @@ -0,0 +1,28 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# HAL module implemenation stored in +# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.product.board>.so +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../libexynosutils \ + $(LOCAL_PATH)/../libcsc + +LOCAL_SRC_FILES:= \ + ExynosCamera.cpp \ + ExynosJpegEncoderForCamera.cpp \ + ExynosCameraHWInterface.cpp + +LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder liblog libcamera_client libhardware + +LOCAL_CFLAGS += -DGAIA_FW_BETA + +LOCAL_SHARED_LIBRARIES += libexynosutils libhwjpeg libexynosv4l2 libcsc libion + +LOCAL_MODULE := camera.$(TARGET_DEVICE) + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/libcamera/ExynosCamera.cpp b/libcamera/ExynosCamera.cpp new file mode 100644 index 0000000..383c902 --- /dev/null +++ b/libcamera/ExynosCamera.cpp @@ -0,0 +1,4743 @@ +/* + * Copyright 2008, The Android Open Source Project + * Copyright 2010, Samsung Electronics Co. LTD + * + * 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 toggle 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 ExynosCamera.cpp + * \brief source file for CAMERA HAL MODULE + * \author thun.hwang(thun.hwang@samsung.com) + * \date 2010/06/03 + * + * <b>Revision History: </b> + * - 2011/12/31 : thun.hwang(thun.hwang@samsung.com) \n + * Initial version + * + * - 2012/01/18 : Sangwoo, Park(sw5771.park@samsung.com) \n + * Adjust Doxygen Document + * + * - 2012/02/01 : Sangwoo, Park(sw5771.park@samsung.com) \n + * Adjust libv4l2 + * Adjust struct ExynosCameraInfo + * External ISP feature + * + * - 2012/03/14 : sangwoo.park(sw5771.park@samsung.com) \n + * Change file, class name to ExynosXXX. + */ + +/** + * @page ExynosCamera + * + * @section Introduction + * ExynosCamera is for camera preview,takePicture and recording. + * (Currently libseccamera is included in Android Camera HAL(libcamera.so). + * + * @section Copyright + * Copyright (c) 2008-2011 Samsung Electronics Co., Ltd.All rights reserved. \n + * Proprietary and Confidential + * + * @image html samsung.png + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ExynosCamera" + +/* FIXME: This define will be removed when functions are stable */ +//#define USE_DIS +//#define USE_3DNR +//#define USE_ODC + +#include <utils/Log.h> + +#include "ExynosCamera.h" +#include "exynos_format.h" + +using namespace android; + +namespace android { + +ExynosCameraInfo::ExynosCameraInfo() +{ + previewW = 2560; + previewH = 1920; + previewColorFormat = V4L2_PIX_FMT_NV21; + videoW = 1920; + videoH = 1080; + prefVideoPreviewW = 640; + prefVideoPreviewH = 360; + videoColorFormat = V4L2_PIX_FMT_NV12M; + pictureW = 2560; + pictureH = 1920; + pictureColorFormat = V4L2_PIX_FMT_YUYV; + thumbnailW = 320; + thumbnailH = 240; + + antiBandingList = + ExynosCamera::ANTIBANDING_OFF + | ExynosCamera::ANTIBANDING_50HZ + | ExynosCamera::ANTIBANDING_60HZ + | ExynosCamera::ANTIBANDING_OFF; + antiBanding = ExynosCamera::ANTIBANDING_OFF; + + effectList = + ExynosCamera::EFFECT_NONE + | ExynosCamera::EFFECT_MONO + | ExynosCamera::EFFECT_NEGATIVE + | ExynosCamera::EFFECT_SOLARIZE + | ExynosCamera::EFFECT_SEPIA + | ExynosCamera::EFFECT_POSTERIZE + | ExynosCamera::EFFECT_WHITEBOARD + | ExynosCamera::EFFECT_BLACKBOARD + | ExynosCamera::EFFECT_AQUA; + effect = ExynosCamera::EFFECT_NONE; + + flashModeList = + ExynosCamera::FLASH_MODE_OFF + | ExynosCamera::FLASH_MODE_AUTO + | ExynosCamera::FLASH_MODE_ON + | ExynosCamera::FLASH_MODE_RED_EYE + | ExynosCamera::FLASH_MODE_TORCH; + flashMode = ExynosCamera::FLASH_MODE_OFF; + + focusModeList = + ExynosCamera::FOCUS_MODE_AUTO + | ExynosCamera::FOCUS_MODE_INFINITY + | ExynosCamera::FOCUS_MODE_MACRO + | ExynosCamera::FOCUS_MODE_FIXED + | ExynosCamera::FOCUS_MODE_EDOF + | ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO + | ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE + | ExynosCamera::FOCUS_MODE_TOUCH; + focusMode = ExynosCamera::FOCUS_MODE_AUTO; + + sceneModeList = + ExynosCamera::SCENE_MODE_AUTO + | ExynosCamera::SCENE_MODE_ACTION + | ExynosCamera::SCENE_MODE_PORTRAIT + | ExynosCamera::SCENE_MODE_LANDSCAPE + | ExynosCamera::SCENE_MODE_NIGHT + | ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT + | ExynosCamera::SCENE_MODE_THEATRE + | ExynosCamera::SCENE_MODE_BEACH + | ExynosCamera::SCENE_MODE_SNOW + | ExynosCamera::SCENE_MODE_SUNSET + | ExynosCamera::SCENE_MODE_STEADYPHOTO + | ExynosCamera::SCENE_MODE_FIREWORKS + | ExynosCamera::SCENE_MODE_SPORTS + | ExynosCamera::SCENE_MODE_PARTY + | ExynosCamera::SCENE_MODE_CANDLELIGHT; + sceneMode = ExynosCamera::SCENE_MODE_AUTO; + + whiteBalanceList = + ExynosCamera::WHITE_BALANCE_AUTO + | ExynosCamera::WHITE_BALANCE_INCANDESCENT + | ExynosCamera::WHITE_BALANCE_FLUORESCENT + | ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT + | ExynosCamera::WHITE_BALANCE_DAYLIGHT + | ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT + | ExynosCamera::WHITE_BALANCE_TWILIGHT + | ExynosCamera::WHITE_BALANCE_SHADE; + whiteBalance = ExynosCamera::WHITE_BALANCE_AUTO; + + autoWhiteBalanceLockSupported = false; + autoWhiteBalanceLock = false; + + rotation = 0; + minExposure = -2; + maxExposure = 2; + exposure = 0; + + autoExposureLockSupported = false; + autoExposureLock = false; + + fps = 30; + focalLengthNum = 9; + focalLengthDen = 10; + supportVideoStabilization = false; + applyVideoStabilization = false; + videoStabilization = false; + maxNumMeteringAreas = 0; + maxNumDetectedFaces = 0; + maxNumFocusAreas = 0; + maxZoom = ZOOM_LEVEL_MAX; + hwZoomSupported = false; + zoom = 0; + gpsAltitude = 0; + gpsLatitude = 0; + gpsLongitude = 0; + gpsTimestamp = 0; + + // Additional API default Value. + angle = 0; + antiShake = false; + beautyShot = false; + brightness = 0; + contrast = ExynosCamera::CONTRAST_DEFAULT; + gamma = false; + hue = 2; // 2 is default; + iso = 0; + metering = ExynosCamera::METERING_MODE_CENTER; + objectTracking = false; + objectTrackingStart = false; + saturation = 0; + sharpness = 0; + shotMode = ExynosCamera::SHOT_MODE_SINGLE; + slowAE = false; + smartAuto = false; + touchAfStart = false; + wdr = false; + tdnr = false; + odc = false; +} + +ExynosCameraInfoM5M0::ExynosCameraInfoM5M0() +{ + previewW = 1280; + previewH = 720; + previewColorFormat = V4L2_PIX_FMT_YVU420M; + videoW = 1280; + videoH = 720; + prefVideoPreviewW = 640; + prefVideoPreviewH = 360; + videoColorFormat = V4L2_PIX_FMT_NV12M; + pictureW = 1280; + pictureH = 720; + pictureColorFormat = V4L2_PIX_FMT_YUYV; + thumbnailW = 320; + thumbnailH = 240; + + antiBandingList = ExynosCamera::ANTIBANDING_OFF; + antiBanding = ExynosCamera::ANTIBANDING_OFF; + + effectList = + ExynosCamera::EFFECT_NONE + | ExynosCamera::EFFECT_MONO + | ExynosCamera::EFFECT_NEGATIVE + //| ExynosCamera::EFFECT_SOLARIZE + | ExynosCamera::EFFECT_SEPIA + //| ExynosCamera::EFFECT_POSTERIZE + //| ExynosCamera::EFFECT_WHITEBOARD + //| ExynosCamera::EFFECT_BLACKBOARD + | ExynosCamera::EFFECT_AQUA; + effect = ExynosCamera::EFFECT_NONE; + + flashModeList = + ExynosCamera::FLASH_MODE_OFF + | ExynosCamera::FLASH_MODE_AUTO + | ExynosCamera::FLASH_MODE_ON + | ExynosCamera::FLASH_MODE_RED_EYE + | ExynosCamera::FLASH_MODE_TORCH; + flashMode = ExynosCamera::FLASH_MODE_OFF; + + focusModeList = + ExynosCamera::FOCUS_MODE_AUTO + | ExynosCamera::FOCUS_MODE_INFINITY + | ExynosCamera::FOCUS_MODE_MACRO + //| ExynosCamera::FOCUS_MODE_FIXED + //| ExynosCamera::FOCUS_MODE_EDOF + //| ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO + //| ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE + //| ExynosCamera::FOCUS_MODE_TOUCH + ; + focusMode = ExynosCamera::FOCUS_MODE_AUTO; + + sceneModeList = + ExynosCamera::SCENE_MODE_AUTO + //| ExynosCamera::SCENE_MODE_ACTION + | ExynosCamera::SCENE_MODE_PORTRAIT + | ExynosCamera::SCENE_MODE_LANDSCAPE + | ExynosCamera::SCENE_MODE_NIGHT + //| ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT + //| ExynosCamera::SCENE_MODE_THEATRE + | ExynosCamera::SCENE_MODE_BEACH + | ExynosCamera::SCENE_MODE_SNOW + | ExynosCamera::SCENE_MODE_SUNSET + //| ExynosCamera::SCENE_MODE_STEADYPHOTO + | ExynosCamera::SCENE_MODE_FIREWORKS + | ExynosCamera::SCENE_MODE_SPORTS + | ExynosCamera::SCENE_MODE_PARTY + | ExynosCamera::SCENE_MODE_CANDLELIGHT; + sceneMode = ExynosCamera::SCENE_MODE_AUTO; + + whiteBalanceList = + ExynosCamera::WHITE_BALANCE_AUTO + | ExynosCamera::WHITE_BALANCE_INCANDESCENT + | ExynosCamera::WHITE_BALANCE_FLUORESCENT + //| ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT + | ExynosCamera::WHITE_BALANCE_DAYLIGHT + | ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT + //| ExynosCamera::WHITE_BALANCE_TWILIGHT + //| ExynosCamera::WHITE_BALANCE_SHADE + ; + whiteBalance = ExynosCamera::WHITE_BALANCE_AUTO; + + autoWhiteBalanceLockSupported = false; + autoWhiteBalanceLock = false; + + rotation = 0; + minExposure = -2; + maxExposure = 2; + exposure = 0; + + autoExposureLockSupported = false; + autoExposureLock = false; + + fps = 30; + focalLengthNum = 343; + focalLengthDen = 100; + supportVideoStabilization = false; + applyVideoStabilization = false; + videoStabilization = false; + maxNumMeteringAreas = 64; + maxNumDetectedFaces = 16; + maxNumFocusAreas = 2; + maxZoom = ZOOM_LEVEL_MAX; + hwZoomSupported = false; + zoom = 0; + gpsAltitude = 0; + gpsLatitude = 0; + gpsLongitude = 0; + gpsTimestamp = 0; +} + +ExynosCameraInfoS5K6A3::ExynosCameraInfoS5K6A3() +{ + previewW = 1280; + previewH = 720; + previewColorFormat = V4L2_PIX_FMT_YVU420M; + videoW = 1280; + videoH = 720; + prefVideoPreviewW = 640; + prefVideoPreviewH = 360; + videoColorFormat = V4L2_PIX_FMT_NV12M; + pictureW = 1280; + pictureH = 720; + pictureColorFormat = V4L2_PIX_FMT_YUYV; + thumbnailW = 320; + thumbnailH = 240; + + antiBandingList = + ExynosCamera::ANTIBANDING_OFF + | ExynosCamera::ANTIBANDING_50HZ + | ExynosCamera::ANTIBANDING_60HZ + | ExynosCamera::ANTIBANDING_OFF; + antiBanding = ExynosCamera::ANTIBANDING_OFF; + + effectList = + ExynosCamera::EFFECT_NONE + | ExynosCamera::EFFECT_MONO + | ExynosCamera::EFFECT_NEGATIVE + //| ExynosCamera::EFFECT_SOLARIZE + | ExynosCamera::EFFECT_SEPIA + //| ExynosCamera::EFFECT_POSTERIZE + //| ExynosCamera::EFFECT_WHITEBOARD + //| ExynosCamera::EFFECT_BLACKBOARD + //| ExynosCamera::EFFECT_AQUA + ; + effect = ExynosCamera::EFFECT_NONE; + + flashModeList = + ExynosCamera::FLASH_MODE_OFF + //| ExynosCamera::FLASH_MODE_AUTO + //| ExynosCamera::FLASH_MODE_ON + //| ExynosCamera::FLASH_MODE_RED_EYE + //| ExynosCamera::FLASH_MODE_TORCH + ; + flashMode = ExynosCamera::FLASH_MODE_OFF; + + focusModeList = + // ExynosCamera::FOCUS_MODE_AUTO + //| ExynosCamera::FOCUS_MODE_INFINITY + //| ExynosCamera::FOCUS_MODE_MACRO + //| + ExynosCamera::FOCUS_MODE_FIXED + //| ExynosCamera::FOCUS_MODE_EDOF + //| ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO + //| ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE + //| ExynosCamera::FOCUS_MODE_TOUCH + ; + focusMode = ExynosCamera::FOCUS_MODE_FIXED; + + sceneModeList = + ExynosCamera::SCENE_MODE_AUTO + //| ExynosCamera::SCENE_MODE_ACTION + | ExynosCamera::SCENE_MODE_PORTRAIT + | ExynosCamera::SCENE_MODE_LANDSCAPE + | ExynosCamera::SCENE_MODE_NIGHT + //| ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT + //| ExynosCamera::SCENE_MODE_THEATRE + | ExynosCamera::SCENE_MODE_BEACH + | ExynosCamera::SCENE_MODE_SNOW + | ExynosCamera::SCENE_MODE_SUNSET + | ExynosCamera::SCENE_MODE_STEADYPHOTO + | ExynosCamera::SCENE_MODE_FIREWORKS + | ExynosCamera::SCENE_MODE_SPORTS + | ExynosCamera::SCENE_MODE_PARTY + | ExynosCamera::SCENE_MODE_CANDLELIGHT; + sceneMode = ExynosCamera::SCENE_MODE_AUTO; + + whiteBalanceList = + ExynosCamera::WHITE_BALANCE_AUTO + | ExynosCamera::WHITE_BALANCE_INCANDESCENT + | ExynosCamera::WHITE_BALANCE_FLUORESCENT + //| ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT + | ExynosCamera::WHITE_BALANCE_DAYLIGHT + | ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT + //| ExynosCamera::WHITE_BALANCE_TWILIGHT + //| ExynosCamera::WHITE_BALANCE_SHADE + ; + whiteBalance = ExynosCamera::WHITE_BALANCE_AUTO; + + autoWhiteBalanceLockSupported = true; + autoWhiteBalanceLock = false; + + rotation = 0; + minExposure = -2; + maxExposure = 2; + exposure = 0; + + autoExposureLockSupported = true; + autoExposureLock = false; + + fps = 30; + focalLengthNum = 9; + focalLengthDen = 10; + supportVideoStabilization = false; + applyVideoStabilization = false; + videoStabilization = false; + maxNumMeteringAreas = 64; + maxNumDetectedFaces = 16; + maxNumFocusAreas = 0; + maxZoom = ZOOM_LEVEL_MAX; + hwZoomSupported = false; + zoom = 0; + gpsAltitude = 0; + gpsLatitude = 0; + gpsLongitude = 0; + gpsTimestamp = 0; +} + +ExynosCameraInfoS5K4E5::ExynosCameraInfoS5K4E5() +{ + previewW = 1920; + previewH = 1080; + previewColorFormat = V4L2_PIX_FMT_YVU420M; + videoW = 1920; + videoH = 1080; + prefVideoPreviewW = 640; + prefVideoPreviewH = 360; + videoColorFormat = V4L2_PIX_FMT_NV12M; + pictureW = 2560; + pictureH = 1920; + pictureColorFormat = V4L2_PIX_FMT_YUYV; + thumbnailW = 320; + thumbnailH = 240; + + antiBandingList = + ExynosCamera::ANTIBANDING_OFF + | ExynosCamera::ANTIBANDING_50HZ + | ExynosCamera::ANTIBANDING_60HZ + | ExynosCamera::ANTIBANDING_OFF; + antiBanding = ExynosCamera::ANTIBANDING_OFF; + + effectList = + ExynosCamera::EFFECT_NONE + | ExynosCamera::EFFECT_MONO + | ExynosCamera::EFFECT_NEGATIVE + //| ExynosCamera::EFFECT_SOLARIZE + | ExynosCamera::EFFECT_SEPIA + //| ExynosCamera::EFFECT_POSTERIZE + //| ExynosCamera::EFFECT_WHITEBOARD + //| ExynosCamera::EFFECT_BLACKBOARD + //| ExynosCamera::EFFECT_AQUA + ; + effect = ExynosCamera::EFFECT_NONE; + + flashModeList = + ExynosCamera::FLASH_MODE_OFF + | ExynosCamera::FLASH_MODE_AUTO + | ExynosCamera::FLASH_MODE_ON + //| ExynosCamera::FLASH_MODE_RED_EYE + | ExynosCamera::FLASH_MODE_TORCH; + flashMode = ExynosCamera::FLASH_MODE_OFF; + + focusModeList = + ExynosCamera::FOCUS_MODE_AUTO + | ExynosCamera::FOCUS_MODE_INFINITY + | ExynosCamera::FOCUS_MODE_MACRO + //| ExynosCamera::FOCUS_MODE_FIXED + //| ExynosCamera::FOCUS_MODE_EDOF + | ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO + | ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE + | ExynosCamera::FOCUS_MODE_TOUCH + ; + focusMode = ExynosCamera::FOCUS_MODE_AUTO; + + sceneModeList = + ExynosCamera::SCENE_MODE_AUTO + //| ExynosCamera::SCENE_MODE_ACTION + | ExynosCamera::SCENE_MODE_PORTRAIT + | ExynosCamera::SCENE_MODE_LANDSCAPE + | ExynosCamera::SCENE_MODE_NIGHT + //| ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT + //| ExynosCamera::SCENE_MODE_THEATRE + | ExynosCamera::SCENE_MODE_BEACH + | ExynosCamera::SCENE_MODE_SNOW + | ExynosCamera::SCENE_MODE_SUNSET + | ExynosCamera::SCENE_MODE_STEADYPHOTO + | ExynosCamera::SCENE_MODE_FIREWORKS + | ExynosCamera::SCENE_MODE_SPORTS + | ExynosCamera::SCENE_MODE_PARTY + | ExynosCamera::SCENE_MODE_CANDLELIGHT; + sceneMode = ExynosCamera::SCENE_MODE_AUTO; + + whiteBalanceList = + ExynosCamera::WHITE_BALANCE_AUTO + | ExynosCamera::WHITE_BALANCE_INCANDESCENT + | ExynosCamera::WHITE_BALANCE_FLUORESCENT + //| ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT + | ExynosCamera::WHITE_BALANCE_DAYLIGHT + | ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT + //| ExynosCamera::WHITE_BALANCE_TWILIGHT + //| ExynosCamera::WHITE_BALANCE_SHADE + ; + whiteBalance = ExynosCamera::WHITE_BALANCE_AUTO; + + autoWhiteBalanceLockSupported = true; + autoWhiteBalanceLock = false; + + rotation = 0; + minExposure = -2; + maxExposure = 2; + exposure = 0; + + autoExposureLockSupported = true; + autoExposureLock = false; + + fps = 30; + focalLengthNum = 9; + focalLengthDen = 10; + supportVideoStabilization = true; + applyVideoStabilization = false; + videoStabilization = false; + maxNumMeteringAreas = 64; + maxNumDetectedFaces = 16; + maxNumFocusAreas = 2; + maxZoom = ZOOM_LEVEL_MAX; + hwZoomSupported = false; + zoom = 0; + gpsAltitude = 0; + gpsLatitude = 0; + gpsLongitude = 0; + gpsTimestamp = 0; +} + +////////////////////////////////////////////////// + +#define PFX_NODE "/dev/video" + +#define M5MOLS_ENTITY_NAME "M5MOLS 5-001f" +#define PFX_SUBDEV_ENTITY_MIPI_CSIS "s5p-mipi-csis" +#define PFX_SUBDEV_ENTITY_FLITE "flite-subdev" +#define PFX_SUBDEV_ENTITY_GSC_CAP "gsc-cap-subdev" +#define PFX_VIDEODEV_ENTITY_FLITE "exynos-fimc-lite" +#define PFX_VIDEODEV_ENTITY_GSC_CAP "exynos-gsc" + +#define MEDIA_DEV_INTERNAL_ISP "/dev/media2" +#define MEDIA_DEV_EXTERNAL_ISP "/dev/media1" +#define ISP_VD_NODE_OFFSET (40) //INTERNAL_ISP +#define FLITE_VD_NODE_OFFSET (36) //External ISP + +#define VIDEO_NODE_PREVIEW_ID (3) +#define VIDEO_NODE_RECODING_ID (2) +#define VIDEO_NODE_SNAPSHOT_ID (1) + +#define ISP_SENSOR_MAX_ENTITIES 1 +#define ISP_SENSOR_PAD_SOURCE_FRONT 0 +#define ISP_SENSOR_PADS_NUM 1 + +#define ISP_FRONT_MAX_ENTITIES 1 +#define ISP_FRONT_PAD_SINK 0 +#define ISP_FRONT_PAD_SOURCE_BACK 1 +#define ISP_FRONT_PAD_SOURCE_BAYER 2 +#define ISP_FRONT_PAD_SOURCE_SCALERC 3 +#define ISP_FRONT_PADS_NUM 4 + +#define ISP_BACK_MAX_ENTITIES 1 +#define ISP_BACK_PAD_SINK 0 +#define ISP_BACK_PAD_SOURCE_3DNR 1 +#define ISP_BACK_PAD_SOURCE_SCALERP 2 +#define ISP_BACK_PADS_NUM 3 + +#define ISP_MODULE_NAME "exynos5-fimc-is" +#define ISP_SENSOR_ENTITY_NAME "exynos5-fimc-is-sensor" +#define ISP_FRONT_ENTITY_NAME "exynos5-fimc-is-front" +#define ISP_BACK_ENTITY_NAME "exynos5-fimc-is-back" +#define ISP_VIDEO_BAYER_NAME "exynos5-fimc-is-bayer" +#define ISP_VIDEO_SCALERC_NAME "exynos5-fimc-is-scalerc" +#define ISP_VIDEO_3DNR_NAME "exynos5-fimc-is-3dnr" +#define ISP_VIDEO_SCALERP_NAME "exynos5-fimc-is-scalerp" + +#define MIPI_NUM 1 +#define FLITE_NUM 1 +#define GSC_NUM 0 + +#define PFX_SUBDEV_NODE "/dev/v4l-subdev" + +/* + * V 4 L 2 F I M C E X T E N S I O N S + * + */ +#define V4L2_CID_ROTATION (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PADDR_Y (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PADDR_CB (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PADDR_CR (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PADDR_CBCR (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_STREAM_PAUSE (V4L2_CID_PRIVATE_BASE + 53) + +#define V4L2_CID_CAM_JPEG_MAIN_SIZE (V4L2_CID_PRIVATE_BASE + 32) +#define V4L2_CID_CAM_JPEG_MAIN_OFFSET (V4L2_CID_PRIVATE_BASE + 33) +#define V4L2_CID_CAM_JPEG_THUMB_SIZE (V4L2_CID_PRIVATE_BASE + 34) +#define V4L2_CID_CAM_JPEG_THUMB_OFFSET (V4L2_CID_PRIVATE_BASE + 35) +#define V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET (V4L2_CID_PRIVATE_BASE + 36) +#define V4L2_CID_CAM_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE + 37) + +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') + +/* FOURCC for FIMC specific */ +#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') +#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') +#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') +#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2') + +/////////////////////////////////////////////////// +// Google Official API : Camera.Parameters +// http://developer.android.com/reference/android/hardware/Camera.Parameters.html +/////////////////////////////////////////////////// + +ExynosCamera::ExynosCamera() : + m_flagCreate(false), + m_cameraId(CAMERA_ID_BACK), + m_defaultCameraInfo(NULL), + m_curCameraInfo(NULL), + m_jpegQuality(100), + m_jpegThumbnailQuality(100), + m_currentZoom(-1) +{ + memset(&m_sensorDev, 0, sizeof(struct devInfo)); + memset(&m_mipiDev, 0, sizeof(struct devInfo)); + memset(&m_fliteDev, 0, sizeof(struct devInfo)); + memset(&m_gscPreviewDev, 0, sizeof(struct devInfo)); + memset(&m_gscVideoDev, 0, sizeof(struct devInfo)); + memset(&m_gscPictureDev, 0, sizeof(struct devInfo)); + + m_previewDev = NULL; + m_videoDev = NULL; + m_pictureDev = NULL; + + m_tryPreviewStop = true; + m_tryVideoStop = true; + m_tryPictureStop = true; + + m_flagStartFaceDetection = false; + m_flagAutoFocusRunning = false; + + m_sensorEntity = NULL; + m_mipiEntity = NULL; + m_fliteSdEntity = NULL; + m_fliteVdEntity = NULL; + m_gscSdEntity = NULL; + m_gscVdEntity = NULL; + m_ispSensorEntity = NULL; + m_ispFrontEntity = NULL; + m_ispBackEntity = NULL; + m_ispScalercEntity = NULL; + m_ispScalerpEntity = NULL; + m_isp3dnrEntity = NULL; + + + for (int i = 0; i < VIDEO_MAX_FRAME; i++) { + m_validPreviewBuf[i] = false; + m_validVideoBuf [i] = false; + m_validPictureBuf[i] = false; + } + + memset((void *)m_cameraName, 0, 32); + + m_internalISP = true; + m_media = NULL; + + memset(&mExifInfo, 0, sizeof(mExifInfo)); +} + +ExynosCamera::~ExynosCamera() +{ + if (m_flagCreate == true) + destroy(); +} + +bool ExynosCamera::create(int cameraId) +{ + int ret = 0; + unsigned int i; + int devNum; + char node[30]; + + struct media_link *links = NULL; + + if (m_flagCreate == true) { + LOGE("ERR(%s):Already created", __func__); + return false; + } + + m_cameraId = cameraId; + + ExynosBuffer nullBuf; + + for (int i = 0; i < VIDEO_MAX_FRAME; i++) { + m_validPreviewBuf[i] = false; + m_validVideoBuf [i] = false; + m_validPictureBuf[i] = false; + + m_previewBuf[i] = nullBuf; + m_videoBuf[i] = nullBuf; + m_pictureBuf[i] = nullBuf; + } + + if (m_cameraId == CAMERA_ID_BACK) + m_internalISP = true; + // m_internalISP = false; // external ISP. + else + m_internalISP = true; + + if (m_internalISP == true) { + ////////////////////////////// + // internal ISP + ////////////////////////////// + // media device open + m_media = exynos_media_open(MEDIA_DEV_INTERNAL_ISP); + if (m_media == NULL) { + LOGE("ERR(%s):Cannot open media device (error : %s)", __func__, strerror(errno)); + goto err; + } + + ////////////////// + // GET ENTITIES + ////////////////// + // ISP sensor subdev + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_SENSOR_ENTITY_NAME); + m_ispSensorEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + // ISP front subdev + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_FRONT_ENTITY_NAME); + m_ispFrontEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + // ISP back subdev + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_BACK_ENTITY_NAME); + m_ispBackEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + // ISP ScalerC video node + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_VIDEO_SCALERC_NAME); + m_ispScalercEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + // ISP ScalerP video node + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_VIDEO_SCALERP_NAME); + m_ispScalerpEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + // ISP 3DNR video node + memset(&node, 0x00, sizeof(node)); + strcpy(node, ISP_VIDEO_3DNR_NAME); + m_isp3dnrEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + + LOGV("DEBUG(%s):m_ispSensorEntity : numlink : %d", __func__, m_ispSensorEntity->num_links); + LOGV("DEBUG(%s):m_ispFrontEntity : numlink : %d", __func__, m_ispFrontEntity->num_links); + LOGV("DEBUG(%s):m_ispBackEntity : numlink : %d", __func__, m_ispBackEntity->num_links); + LOGV("DEBUG(%s):m_ispScalercEntity : numlink : %d", __func__, m_ispScalercEntity->num_links); + LOGV("DEBUG(%s):m_ispScalerpEntity : numlink : %d", __func__, m_ispScalerpEntity->num_links); + LOGV("DEBUG(%s):m_isp3dnrEntity : numlink : %d", __func__, m_isp3dnrEntity->num_links); + + ////////////////// + // SETUP LINKS + ////////////////// + // SENSOR TO FRONT + links = m_ispSensorEntity->links; + if (links == NULL || + links->source->entity != m_ispSensorEntity || + links->sink->entity != m_ispFrontEntity) { + LOGE("ERR(%s):Can not make link isp_sensor to isp_front", __func__); + goto err; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Can not make setup isp_sensor to isp_front", __func__); + goto err; + } + LOGV("DEBUG(%s):[LINK SUCCESS] Sensor to front", __func__); + + // FRONT TO BACK + for (i = 0; i < m_ispFrontEntity->num_links; i++) { + links = &m_ispFrontEntity->links[i]; + if (links == NULL || + links->source->entity != m_ispFrontEntity || + links->sink->entity != m_ispBackEntity) { + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_ispFrontEntity : %p", __func__, i, + links->source->entity, m_ispFrontEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_ispBackEntity : %p", __func__, i, + links->sink->entity, m_ispBackEntity); + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Can not make setup isp_front to isp_back", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] front to back", __func__); + + // BACK TO ScalerP Video + for (i = 0; i < m_ispBackEntity->num_links; i++) { + links = &m_ispBackEntity->links[i]; + if (links == NULL || + links->source->entity != m_ispBackEntity || + links->sink->entity != m_ispScalerpEntity) { + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_ispBackEntity : %p", __func__, i, + links->source->entity, m_ispBackEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_ispScalerpEntity : %p", __func__, i, + links->sink->entity, m_ispScalerpEntity); + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Can not make setup isp_back to scalerP", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] back to scalerP", __func__); + + sprintf(node, "%s%d", PFX_NODE, (ISP_VD_NODE_OFFSET + VIDEO_NODE_PREVIEW_ID)); + m_gscPreviewDev.fd = exynos_v4l2_open(node, O_RDWR, 0); + if (m_gscPreviewDev.fd <= 0) { + LOGE("ERR(%s):exynos_v4l2_open(%s) fail (error : %s)", __func__, node, strerror(errno)); + goto err; + } + m_previewDev = &m_gscPreviewDev; + + sprintf(node, "%s%d", PFX_NODE, (ISP_VD_NODE_OFFSET + VIDEO_NODE_RECODING_ID)); + m_gscVideoDev.fd = exynos_v4l2_open(node, O_RDWR, 0); + if (m_gscVideoDev.fd <= 0) { + LOGE("ERR(%s):exynos_v4l2_open(%s) fail (error : %s)", __func__, node, strerror(errno)); + goto err; + } + m_videoDev = &m_gscVideoDev; + + sprintf(node, "%s%d", PFX_NODE, (ISP_VD_NODE_OFFSET + VIDEO_NODE_SNAPSHOT_ID)); + m_gscPictureDev.fd = exynos_v4l2_open(node, O_RDWR, 0); + if (m_gscPictureDev.fd <= 0) { + LOGE("ERR(%s):exynos_v4l2_open(%s) fail (error : %s)", __func__, node, strerror(errno)); + goto err; + } + m_pictureDev = &m_gscPictureDev; + + } else { + ////////////////////////////// + // external ISP + ////////////////////////////// + // media device open + m_media = exynos_media_open(MEDIA_DEV_EXTERNAL_ISP); + if (m_media == NULL) { + LOGE("ERR(%s):Cannot open media device (error : %s)", __func__, strerror(errno)); + goto err; + } + + ////////////////// + // GET ENTITIES + ////////////////// + // camera subdev + strcpy(node, M5MOLS_ENTITY_NAME); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_sensorEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_sensorEntity : 0x%p", __func__, m_sensorEntity); + + // mipi subdev + sprintf(node, "%s.%d", PFX_SUBDEV_ENTITY_MIPI_CSIS, MIPI_NUM); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_mipiEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_mipiEntity : 0x%p", __func__, m_mipiEntity); + + // fimc-lite subdev + sprintf(node, "%s.%d", PFX_SUBDEV_ENTITY_FLITE, FLITE_NUM); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_fliteSdEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_fliteSdEntity : 0x%p", __func__, m_fliteSdEntity); + + // fimc-lite videodev + sprintf(node, "%s.%d", PFX_VIDEODEV_ENTITY_FLITE, FLITE_NUM); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_fliteVdEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_fliteVdEntity : 0x%p", __func__, m_fliteVdEntity); + + // gscaler subdev + sprintf(node, "%s.%d", PFX_SUBDEV_ENTITY_GSC_CAP, GSC_NUM); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_gscSdEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_gscSdEntity : 0x%p", __func__, m_gscSdEntity); + + // gscaler videodev + sprintf(node, "%s.%d", PFX_VIDEODEV_ENTITY_GSC_CAP, GSC_NUM); + LOGV("DEBUG(%s):node : %s", __func__, node); + m_gscVdEntity = exynos_media_get_entity_by_name(m_media, node, strlen(node)); + LOGV("DEBUG(%s):m_gscVdEntity : 0x%p", __func__, m_gscVdEntity); + + LOGV("DEBUG(%s):sensor_sd : numlink : %d", __func__, m_sensorEntity->num_links); + LOGV("DEBUG(%s):mipi_sd : numlink : %d", __func__, m_mipiEntity->num_links); + LOGV("DEBUG(%s):flite_sd : numlink : %d", __func__, m_fliteSdEntity->num_links); + LOGV("DEBUG(%s):flite_vd : numlink : %d", __func__, m_fliteVdEntity->num_links); + LOGV("DEBUG(%s):gsc_sd : numlink : %d", __func__, m_gscSdEntity->num_links); + LOGV("DEBUG(%s):gsc_vd : numlink : %d", __func__, m_gscVdEntity->num_links); + + ////////////////// + // SETUP LINKS + ////////////////// + // sensor subdev to mipi subdev + links = m_sensorEntity->links; + if (links == NULL || + links->source->entity != m_sensorEntity || + links->sink->entity != m_mipiEntity) { + LOGE("ERR(%s):Cannot make link camera sensor to mipi", __func__); + goto err; + } + + if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Cannot make setup camera sensor to mipi", __func__); + goto err; + } + LOGV("DEBUG(%s):[LINK SUCCESS] sensor subdev to mipi subdev", __func__); + + // mipi subdev to fimc-lite subdev + for (i = 0; i < m_mipiEntity->num_links; i++) { + links = &m_mipiEntity->links[i]; + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_mipiEntity : %p", __func__, i, + links->source->entity, m_mipiEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_fliteSdEntity : %p", __func__, i, + links->sink->entity, m_fliteSdEntity); + if (links == NULL || + links->source->entity != m_mipiEntity || + links->sink->entity != m_fliteSdEntity) { + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Cannot make setup mipi subdev to fimc-lite subdev", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] mipi subdev to fimc-lite subdev", __func__); + + // fimc-lite subdev TO fimc-lite video dev + for (i = 0; i < m_fliteSdEntity->num_links; i++) { + links = &m_fliteSdEntity->links[i]; + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_fliteSdEntity : %p", __func__, i, + links->source->entity, m_fliteSdEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_fliteVdEntity : %p", __func__, i, + links->sink->entity, m_fliteVdEntity); + if (links == NULL || + links->source->entity != m_fliteSdEntity || + links->sink->entity != m_fliteVdEntity) { + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Cannot make setup fimc-lite subdev to fimc-lite video dev", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] fimc-lite subdev to fimc-lite video dev", __func__); + + // fimc-lite subdev to gscaler subdev + for (i = 0; i < m_gscSdEntity->num_links; i++) { + links = &m_gscSdEntity->links[i]; + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_fliteSdEntity : %p", __func__, i, + links->source->entity, m_fliteSdEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_gscSdEntity : %p", __func__, i, + links->sink->entity, m_gscSdEntity); + if (links == NULL || + links->source->entity != m_fliteSdEntity || + links->sink->entity != m_gscSdEntity) { + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Cannot make setup fimc-lite subdev to gscaler subdev", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] fimc-lite subdev to gscaler subdev", __func__); + + // gscaler subdev to gscaler video dev + for (i = 0; i < m_gscVdEntity->num_links; i++) { + links = &m_gscVdEntity->links[i]; + LOGV("DEBUG(%s):i=%d: links->source->entity : %p, m_gscSdEntity : %p", __func__, i, + links->source->entity, m_gscSdEntity); + LOGV("DEBUG(%s):i=%d: links->sink->entity : %p, m_gscVdEntity : %p", __func__, i, + links->sink->entity, m_gscVdEntity); + if (links == NULL || + links->source->entity != m_gscSdEntity || + links->sink->entity != m_gscVdEntity) { + continue; + } else if (exynos_media_setup_link(m_media, links->source, links->sink, MEDIA_LNK_FL_ENABLED) < 0) { + LOGE("ERR(%s):Cannot make setup gscaler subdev to gscaler video dev", __func__); + goto err; + } + } + LOGV("DEBUG(%s):[LINK SUCCESS] gscaler subdev to gscaler video dev", __func__); + + sprintf(node, "%s%d", PFX_NODE, (FLITE_VD_NODE_OFFSET + VIDEO_NODE_PREVIEW_ID)); + m_fliteDev.fd = exynos_v4l2_open(node, O_RDWR, 0); + if (m_fliteDev.fd <= 0) { + LOGE("ERR(%s):exynos_v4l2_open(%s) fail (error : %s)", __func__, node, strerror(errno)); + goto err; + } + m_previewDev = &m_fliteDev; + m_videoDev = &m_fliteDev; + m_pictureDev = &m_fliteDev; + } + + m_previewDev->flagStart = false; + m_videoDev->flagStart = false; + m_pictureDev->flagStart = false; + + m_tryPreviewStop = true; + m_tryVideoStop = true; + m_tryPictureStop = true; + + m_flagStartFaceDetection = false; + m_flagAutoFocusRunning = false; + + if (exynos_v4l2_enuminput(m_previewDev->fd, m_cameraId, m_cameraName) == false) { + LOGE("ERR(%s):exynos_v4l2_enuminput(%d, %s) fail", __func__, m_cameraId, m_cameraName); + goto err; + } + + // HACK + if (m_cameraId == CAMERA_ID_BACK) + strcpy(m_cameraName, "S5K4E5"); + else + strcpy(m_cameraName, "S5K6A3"); + + if (exynos_v4l2_s_input(m_previewDev->fd, m_cameraId) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_input() fail", __func__); + goto err; + } + + if (strcmp((const char*)m_cameraName, "S5K4E5") == 0) { + m_defaultCameraInfo = new ExynosCameraInfoS5K4E5; + m_curCameraInfo = new ExynosCameraInfoS5K4E5; + } else if (strcmp((const char*)m_cameraName, "S5K6A3") == 0) { + m_defaultCameraInfo = new ExynosCameraInfoS5K6A3; + m_curCameraInfo = new ExynosCameraInfoS5K6A3; + } else if (strcmp((const char*)m_cameraName, "M5M0") == 0) { + m_defaultCameraInfo = new ExynosCameraInfoM5M0; + m_curCameraInfo = new ExynosCameraInfoM5M0; + } else { + LOGE("ERR(%s):invalid camera Name (%s) fail", __func__, m_cameraName); + goto err; + } + + m_setExifFixedAttribute(); + + m_flagCreate = true; + return true; + +err: + if (m_defaultCameraInfo) + delete m_defaultCameraInfo; + m_defaultCameraInfo = NULL; + + if (m_curCameraInfo) + delete m_curCameraInfo; + m_curCameraInfo = NULL; + + if (0 < m_videoDev->fd) + exynos_v4l2_close(m_videoDev->fd); + m_videoDev->fd = 0; + + if (0 < m_pictureDev->fd) + exynos_v4l2_close(m_pictureDev->fd); + m_pictureDev->fd = 0; + + if (0 < m_previewDev->fd) + exynos_v4l2_close(m_previewDev->fd); + m_previewDev->fd = 0; + + if (m_media) + exynos_media_close(m_media); + m_media = NULL; + + return false; +} + +bool ExynosCamera::destroy(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created", __func__); + return false; + } + + if (m_pictureDev->flagStart == true) + stopPicture(); + + if (m_videoDev->flagStart == true) + stopVideo(); + + if (m_previewDev->flagStart == true) + stopPreview(); + + if (m_defaultCameraInfo) + delete m_defaultCameraInfo; + m_defaultCameraInfo = NULL; + + if (m_curCameraInfo) + delete m_curCameraInfo; + m_curCameraInfo = NULL; + + // close m_previewDev->fd after stopVideo() because stopVideo() + // uses m_previewDev->fd to change frame rate + if (0 < m_videoDev->fd) + exynos_v4l2_close(m_videoDev->fd); + m_videoDev->fd = 0; + + if (0 < m_pictureDev->fd) + exynos_v4l2_close(m_pictureDev->fd); + m_pictureDev->fd = 0; + + if (0 < m_previewDev->fd) + exynos_v4l2_close(m_previewDev->fd); + m_previewDev->fd = 0; + + if (m_media) + exynos_media_close(m_media); + m_media = NULL; + + m_flagCreate = false; + + return true; +} + +bool ExynosCamera::flagCreate(void) +{ + return m_flagCreate; +} + +int ExynosCamera::getCameraId(void) +{ + return m_cameraId; +} + +char *ExynosCamera::getCameraName(void) +{ + return m_cameraName; +} + +int ExynosCamera::getPreviewFd(void) +{ + return m_previewDev->fd; +} + +int ExynosCamera::getPictureFd(void) +{ + return m_pictureDev->fd; +} + +int ExynosCamera::getVideoFd(void) +{ + return m_videoDev->fd; +} + +bool ExynosCamera::startPreview(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + + if (m_previewDev->flagStart == false) { + if (m_setWidthHeight(PREVIEW_MODE, + m_previewDev->fd, + &m_previewDev->events, + m_curCameraInfo->previewW, + m_curCameraInfo->previewH, + m_curCameraInfo->previewColorFormat, + m_previewBuf, + m_validPreviewBuf) == false) { + LOGE("ERR(%s):m_setWidthHeight() fail", __func__); + return false; + } + + if (setPreviewFrameRate(m_curCameraInfo->fps) == false) + LOGE("ERR(%s):Fail toggle setPreviewFrameRate(%d)", + __func__, m_curCameraInfo->fps); + + if (exynos_v4l2_streamon(m_previewDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamon() fail", __func__); + return false; + } + + if (m_curCameraInfo->focusMode == FOCUS_MODE_CONTINUOUS_VIDEO + || m_curCameraInfo->focusMode == FOCUS_MODE_CONTINUOUS_PICTURE) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_CAF_START_STOP, CAF_START) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + + m_tryPreviewStop = false; + m_previewDev->flagStart = true; + +/* TODO */ +/* DIS is only supported BACK camera(4E5) currently. */ +#ifdef USE_DIS + bool toggle = getVideoStabilization(); + + if (setVideoStabilization(toggle) == false) + LOGE("ERR(%s):setVideoStabilization() fail", __func__); +#endif + +#ifdef USE_3DNR + if (m_recordingHint == true && getCameraId() == CAMERA_ID_BACK) { + if (set3DNR(true) == false) + LOGE("ERR(%s):set3DNR() fail", __func__); + } +#endif + +#ifdef USE_ODC + if (setODC(true) == false) + LOGE("ERR(%s):setODC() fail", __func__); +#endif + } + + return true; +} + +bool ExynosCamera::stopPreview(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + + if (m_previewDev->flagStart == true) { + + if (m_curCameraInfo->flashMode == FLASH_MODE_TORCH) + setFlashMode(FLASH_MODE_OFF); + + m_tryPreviewStop = true; + + // skip stopPreview + if ( (m_previewDev == m_videoDev && m_tryVideoStop == false) + || (m_previewDev == m_pictureDev && m_tryPictureStop == false)) + return true; + +/* TODO */ +/* Can not use 3DNR, ODC and DIS function because HW problem at exynos5250 EVT0 */ +#ifdef USE_3DNR + if (set3DNR(false) == false) + LOGE("ERR(%s):set3DNR() fail", __func__); +#endif + +#ifdef USE_ODC + if (setODC(false) == false) + LOGE("ERR(%s):setODC() fail", __func__); +#endif + + if (exynos_v4l2_streamoff(m_previewDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamoff() fail", __func__); + return false; + } + + struct v4l2_requestbuffers req; + req.count = 0; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.memory = V4L2_MEMORY_USERPTR; + + if (exynos_v4l2_reqbufs(m_previewDev->fd, &req) < 0) { + LOGE("ERR(%s):exynos_v4l2_reqbufs() fail", __func__); + return false; + } + + m_previewDev->flagStart = false; + + m_flagStartFaceDetection = false; + } + + return true; +} + +bool ExynosCamera::flagStartPreview(void) +{ + return m_previewDev->flagStart; +} + +int ExynosCamera::getPreviewMaxBuf(void) +{ + return VIDEO_MAX_FRAME; +} + +bool ExynosCamera::setPreviewBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= buf->reserved.p) { + LOGE("ERR(%s):index(%d) must smaller than %d", __func__, buf->reserved.p, VIDEO_MAX_FRAME); + return false; + } + + m_previewBuf[buf->reserved.p] = *buf; + + // HACK : Driver not yet support cb,cr of YV12 + m_previewBuf[buf->reserved.p].virt.extP[1] = buf->virt.extP[2]; + m_previewBuf[buf->reserved.p].virt.extP[2] = buf->virt.extP[1]; + + return true; +} + +bool ExynosCamera::getPreviewBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_previewDev->flagStart == false) { + LOGE("ERR(%s):Not yet preview started fail", __func__); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + if (m_previewBuf[0].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_dqbuf(m_previewDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_dqbuf() fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= v4l2_buf.index) { + LOGE("ERR(%s):wrong index = %d", __func__, v4l2_buf.index); + return false; + } + + *buf = m_previewBuf[v4l2_buf.index]; + + return true; +} + +bool ExynosCamera::putPreviewBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_validPreviewBuf[buf->reserved.p] == false) { + LOGE("ERR(%s):Invalid index(%d)", __func__, buf->reserved.p); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.index = buf->reserved.p; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + v4l2_buf.m.planes[i].m.userptr = (unsigned long)m_previewBuf[buf->reserved.p].virt.extP[i]; + v4l2_buf.m.planes[i].length = m_previewBuf[buf->reserved.p].size.extS[i]; + + if (m_previewBuf[buf->reserved.p].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_qbuf(m_previewDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_qbuf() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::setVideoSize(int w, int h) +{ + m_curCameraInfo->videoW = w; + m_curCameraInfo->videoH = h; + +#ifdef USE_3DNR_DMAOUT + // HACK : Video 3dnr port support resize. So, we must make max size video w, h + m_curCameraInfo->videoW = m_defaultCameraInfo->videoW; + m_curCameraInfo->videoH = m_defaultCameraInfo->videoH; +#endif + return true; +} + +bool ExynosCamera::getVideoSize(int *w, int *h) +{ + *w = m_curCameraInfo->videoW; + *h = m_curCameraInfo->videoH; + return true; +} + +bool ExynosCamera::setVideoFormat(int colorFormat) +{ + m_curCameraInfo->videoColorFormat = colorFormat; + return true; +} + +int ExynosCamera::getVideoFormat(void) +{ + return m_curCameraInfo->videoColorFormat; +} + +bool ExynosCamera::startVideo(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + +#ifdef USE_3DNR_DMAOUT + if (m_videoDev->flagStart == false) { + if (m_setWidthHeight(VIDEO_MODE, + m_videoDev->fd, + &m_videoDev->events, + m_curCameraInfo->videoW, + m_curCameraInfo->videoH, + m_curCameraInfo->videoColorFormat, + m_videoBuf, + m_validVideoBuf) == false) { + LOGE("ERR(%s):m_setWidthHeight() fail", __func__); + return false; + } + + if (exynos_v4l2_streamon(m_videoDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamon() fail", __func__); + return false; + } + + m_tryVideoStop = false; + m_videoDev->flagStart = true; + } +#endif + + return true; +} + +bool ExynosCamera::stopVideo(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + + if (m_videoDev->flagStart == true) { + + m_tryVideoStop = true; + + // skip stopVideo + if ( (m_videoDev == m_previewDev && m_tryPreviewStop == false) + || (m_videoDev == m_pictureDev && m_tryPictureStop == false)) + return true; + + if (exynos_v4l2_streamoff(m_videoDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamoff() fail", __func__); + return false; + } + struct v4l2_requestbuffers req; + req.count = 0; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.memory = V4L2_MEMORY_USERPTR; + + if (exynos_v4l2_reqbufs(m_videoDev->fd, &req) < 0) { + LOGE("ERR(%s):exynos_v4l2_reqbufs() fail", __func__); + return false; + } + + m_videoDev->flagStart = false; + } + + return true; +} + +bool ExynosCamera::flagStartVideo(void) +{ + return m_videoDev->flagStart; +} + +int ExynosCamera::getVideoMaxBuf(void) +{ + return VIDEO_MAX_FRAME; +} + +bool ExynosCamera::setVideoBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= buf->reserved.p) { + LOGE("ERR(%s):index(%d) must smaller than %d", __func__, buf->reserved.p, VIDEO_MAX_FRAME); + return false; + } + + m_videoBuf[buf->reserved.p] = *buf; + return true; +} + +bool ExynosCamera::getVideoBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_videoDev->flagStart == false) { + LOGE("ERR(%s):Not yet video started fail", __func__); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + if (m_videoBuf[0].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_dqbuf(m_videoDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_dqbuf() fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= v4l2_buf.index) { + LOGE("ERR(%s):wrong index = %d", __func__, v4l2_buf.index); + return false; + } + + *buf = m_videoBuf[v4l2_buf.index]; + + return true; +} + +bool ExynosCamera::putVideoBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_videoDev->flagStart == false) { + /* this can happen when recording frames are returned after + * the recording is stopped at the driver level. we don't + * need to return the buffers in this case and we've seen + * cases where fimc could crash if we called qbuf and it + * wasn't expecting it. + */ + LOGV("DEBUG(%s):recording not in progress, ignoring", __func__); + return true; + } + + if (m_validVideoBuf[buf->reserved.p] == false) { + LOGE("ERR(%s):Invalid index(%d)", __func__, buf->reserved.p); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.index = buf->reserved.p; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + v4l2_buf.m.planes[i].m.userptr = (unsigned long)m_videoBuf[buf->reserved.p].virt.extP[i]; + v4l2_buf.m.planes[i].length = m_videoBuf[buf->reserved.p].size.extS[i]; + + if (m_videoBuf[buf->reserved.p].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_qbuf(m_videoDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_qbuf() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::startPicture(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + + if (m_pictureDev->flagStart == false) { + if (m_setWidthHeight(PICTURE_MODE, + m_pictureDev->fd, + &m_pictureDev->events, + m_curCameraInfo->pictureW, + m_curCameraInfo->pictureH, + m_curCameraInfo->pictureColorFormat, + m_pictureBuf, + m_validPictureBuf) == false) { + LOGE("ERR(%s):m_setWidthHeight() fail", __func__); + return false; + } + + if (exynos_v4l2_streamon(m_pictureDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamon() fail", __func__); + return false; + } + + m_tryPictureStop = false; + m_pictureDev->flagStart = true; + } + + return true; +} + +bool ExynosCamera::stopPicture(void) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet Created", __func__); + return false; + } + + if (m_pictureDev->flagStart == true) { + + m_tryPictureStop = true; + + // skip stopPicture + if ( (m_pictureDev == m_previewDev && m_tryPreviewStop == false) + || (m_pictureDev == m_videoDev && m_tryVideoStop == false)) + return true; + + if (exynos_v4l2_streamoff(m_pictureDev->fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + LOGE("ERR(%s):exynos_v4l2_streamoff() fail", __func__); + return false; + } + + struct v4l2_requestbuffers req; + req.count = 0; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.memory = V4L2_MEMORY_USERPTR; + + if (exynos_v4l2_reqbufs(m_pictureDev->fd, &req) < 0) { + LOGE("ERR(%s):exynos_v4l2_reqbufs() fail", __func__); + return false; + } + + m_pictureDev->flagStart = false; + } + + return true; +} + +bool ExynosCamera::flagStartPicture(void) +{ + return m_pictureDev->flagStart; +} + +int ExynosCamera::getPictureMaxBuf(void) +{ + return VIDEO_MAX_FRAME; +} + +bool ExynosCamera::setPictureBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= buf->reserved.p) { + LOGE("ERR(%s):index(%d) must smaller than %d", __func__, buf->reserved.p, VIDEO_MAX_FRAME); + return false; + } + + m_pictureBuf[buf->reserved.p] = *buf; + return true; +} + +bool ExynosCamera::getPictureBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_pictureDev->flagStart == false) { + LOGE("ERR(%s):Not yet picture started fail", __func__); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + if (m_pictureBuf[0].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_dqbuf(m_pictureDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_dqbuf() fail", __func__); + return false; + } + + if (VIDEO_MAX_FRAME <= v4l2_buf.index) { + LOGE("ERR(%s):wrong index = %d", __func__, v4l2_buf.index); + return false; + } + + *buf = m_pictureBuf[v4l2_buf.index]; + + return true; +} + +bool ExynosCamera::putPictureBuf(ExynosBuffer *buf) +{ + if (m_flagCreate == false) { + LOGE("ERR(%s):Not yet created fail", __func__); + return false; + } + + if (m_pictureDev->flagStart == false) { + LOGE("ERR(%s):Not yet picture started fail", __func__); + return false; + } + + if (m_validPictureBuf[buf->reserved.p] == false) { + LOGE("ERR(%s):Invalid index(%d)", __func__, buf->reserved.p); + return false; + } + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.index = buf->reserved.p; + v4l2_buf.length = 0; + + for (int i = 0; i < 3; i++) { + v4l2_buf.m.planes[i].m.userptr = (unsigned long)m_pictureBuf[buf->reserved.p].virt.extP[i]; + v4l2_buf.m.planes[i].length = m_pictureBuf[buf->reserved.p].size.extS[i]; + + if (m_pictureBuf[buf->reserved.p].size.extS[i] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_qbuf(m_pictureDev->fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_qbuf() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::yuv2Jpeg(ExynosBuffer *yuvBuf, + ExynosBuffer *jpegBuf, + ExynosRect *rect) +{ + unsigned char *addr; + + ExynosJpegEncoderForCamera jpegEnc; + bool ret = false; + + unsigned int *yuvSize = yuvBuf->size.extS; + + if (jpegEnc.create()) { + LOGE("ERR(%s):jpegEnc.create() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.setQuality(m_jpegQuality)) { + LOGE("ERR(%s):jpegEnc.setQuality() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.setSize(rect->w, rect->h)) { + LOGE("ERR(%s):jpegEnc.setSize() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.setColorFormat(rect->colorFormat)) { + LOGE("ERR(%s):jpegEnc.setColorFormat() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.setJpegFormat(V4L2_PIX_FMT_JPEG_422)) { + LOGE("ERR(%s):jpegEnc.setJpegFormat() fail", __func__); + goto jpeg_encode_done; + } + + if (m_curCameraInfo->thumbnailW != 0 && m_curCameraInfo->thumbnailH != 0) { + mExifInfo.enableThumb = true; + if (jpegEnc.setThumbnailSize(m_curCameraInfo->thumbnailW, m_curCameraInfo->thumbnailH)) { + LOGE("ERR(%s):jpegEnc.setThumbnailSize(%d, %d) fail", __func__, m_curCameraInfo->thumbnailW, m_curCameraInfo->thumbnailH); + goto jpeg_encode_done; + } + + if (0 < m_jpegThumbnailQuality && m_jpegThumbnailQuality <= 100) { + if (jpegEnc.setThumbnailQuality(m_jpegThumbnailQuality)) { + LOGE("ERR(%s):jpegEnc.setThumbnailSize(%d, %d) fail", __func__, m_curCameraInfo->thumbnailW, m_curCameraInfo->thumbnailH); + goto jpeg_encode_done; + } + } + + m_setExifChangedAttribute(&mExifInfo, rect); + } else { + mExifInfo.enableThumb = false; + } + + if (jpegEnc.setInBuf((char **)&(yuvBuf->virt.p), (int *)yuvSize)) { + LOGE("ERR(%s):jpegEnc.setInBuf() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.setOutBuf(jpegBuf->virt.p, jpegBuf->size.extS[0] + jpegBuf->size.extS[1] + jpegBuf->size.extS[2])) { + LOGE("ERR(%s):jpegEnc.setOutBuf() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.updateConfig()) { + LOGE("ERR(%s):jpegEnc.updateConfig() fail", __func__); + goto jpeg_encode_done; + } + + if (jpegEnc.encode((int *)&jpegBuf->size.s, &mExifInfo)) { + LOGE("ERR(%s):jpegEnc.encode() fail", __func__); + goto jpeg_encode_done; + } + + ret = true; + +jpeg_encode_done: + + if (jpegEnc.flagCreate() == true) + jpegEnc.destroy(); + + return ret; +} + +bool ExynosCamera::autoFocus(void) +{ + if (m_previewDev->fd <= 0) { + LOGE("ERR(%s):Camera was closed", __func__); + return false; + } + + if (m_flagAutoFocusRunning == true) { + LOGD("DEBUG(%s):m_flagAutoFocusRunning == true", __func__); + return true; + } + + switch (m_curCameraInfo->focusMode) { + case FOCUS_MODE_AUTO: + case FOCUS_MODE_INFINITY: + case FOCUS_MODE_MACRO: + if (m_touchAFMode == true) { + if (setFocusMode(FOCUS_MODE_TOUCH) == false) { + LOGE("ERR(%s): %d: setFocusMode(FOCUS_MODE_TOUCH) fail", __func__, __LINE__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_ON) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + break; + case FOCUS_MODE_CONTINUOUS_VIDEO: + case FOCUS_MODE_CONTINUOUS_PICTURE: + /* Doing nothing. Because we assume that continuous focus mode is + always focused on. */ + break; + case FOCUS_MODE_TOUCH: + if (setFocusMode(FOCUS_MODE_TOUCH) == false) { + LOGE("ERR(%s): %d: setFocusMode(FOCUS_MODE_TOUCH) fail", __func__, __LINE__); + return false; + } + break; + case FOCUS_MODE_FIXED: + break; + case FOCUS_MODE_EDOF: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, m_curCameraInfo->focusMode); + return false; + break; + } + + m_flagAutoFocusRunning = true; + + return true; +} + +bool ExynosCamera::cancelAutoFocus(void) +{ + if (m_previewDev->fd <= 0) { + LOGE("ERR(%s):Camera was closed", __func__); + return false; + } + + if (m_flagAutoFocusRunning == false) { + LOGV("DEBUG(%s):m_flagAutoFocusRunning == false", __func__); + return true; + } + + switch (m_curCameraInfo->focusMode) { + case FOCUS_MODE_AUTO: + case FOCUS_MODE_INFINITY: + case FOCUS_MODE_MACRO: + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + break; + case FOCUS_MODE_CONTINUOUS_VIDEO: + case FOCUS_MODE_CONTINUOUS_PICTURE: + /* Doing nothing. Because we assume that continuous focus mode is + always focused on. */ + break; + case FOCUS_MODE_TOUCH: + if (setFocusMode(FOCUS_MODE_TOUCH) == false) { + LOGE("ERR(%s): %d: setFocusMode(FOCUS_MODE_TOUCH) fail", __func__, __LINE__); + return false; + } + m_touchAFMode = false; + break; + case FOCUS_MODE_FIXED: + break; + case FOCUS_MODE_EDOF: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, m_curCameraInfo->focusMode); + return false; + break; + } + + m_flagAutoFocusRunning = false; + + return true; +} + +int ExynosCamera::getFucusModeResult(void) +{ + int ret = 0; + +#define AF_WATING_TIME (100000) // 100msec +#define TOTAL_AF_WATING_TIME (2000000) // 2000msec + + for (unsigned int i = 0; i < TOTAL_AF_WATING_TIME; i += AF_WATING_TIME) { + + if (m_flagAutoFocusRunning == false) + return -1; + + if (exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT, &ret) < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ctrl() fail", __func__); + return -1; + } + + if (strcmp((const char*)m_cameraName, "S5K4E5") == 0) { + switch(ret) { + case 0x00: // AF Running + ret = 0; + break; + case 0x02: // AF succeed + ret = 1; + break; + case 0x01: + default : // AF fail + ret = -1; + break; + } + + if (ret != 0) + break; + + } else if (strcmp((const char*)m_cameraName, "M5M0") == 0) { + switch(ret) { + case 0x00: // AF Running + ret = 0; + break; + case 0x01: // AF succeed + ret = 1; + break; + case 0x02: // AF cancel + ret = 0; + break; + default: // AF fail + ret = -1; + break; + } + + if (ret != 0) + break; + } else { + ret = -1; + break; + } + + usleep(AF_WATING_TIME); + } + + return ret; +} + +bool ExynosCamera::startFaceDetection(void) +{ + if (m_flagStartFaceDetection == true) { + LOGD("DEBUG(%s):Face detection already started..", __func__); + return true; + } + + if (m_previewDev->flagStart == true) { + //if (this->setFocusMode(FOCUS_MODE_AUTO) == false) + // LOGE("ERR(%s):Fail setFocusMode", __func__); + + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_FD_SET_MAX_FACE_NUMBER, m_defaultCameraInfo->maxNumDetectedFaces) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CMD_FD, IS_FD_COMMAND_START) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FACE_DETECTION, FACE_DETECTION_ON) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + m_flagStartFaceDetection = true; + } + return true; +} + +bool ExynosCamera::stopFaceDetection(void) +{ + if (m_flagStartFaceDetection == false) { + LOGD("DEBUG(%s):Face detection already stopped..", __func__); + return true; + } + + if (m_previewDev->flagStart == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CMD_FD, IS_FD_COMMAND_STOP) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FACE_DETECTION, FACE_DETECTION_OFF) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + m_flagStartFaceDetection = false; + } + return true; +} + +bool ExynosCamera::flagStartFaceDetection(void) +{ + return m_flagStartFaceDetection; +} + +bool ExynosCamera::setFaceDetectLock(bool toggle) +{ + int lock = (toggle == true) ? 1 : 0; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FACEDETECT_LOCKUNLOCK, lock) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + return true; +} + +bool ExynosCamera::startSmoothZoom(int value) +{ + if (m_defaultCameraInfo->hwZoomSupported == false) { + LOGE("ERR(%s):m_defaultCameraInfo->hwZoomSupported == false", __func__); + return false; + } + + return this->setZoom(value); +} + +bool ExynosCamera::stopSmoothZoom(void) +{ + // TODO + return true; +} + +int ExynosCamera::getAntibanding(void) +{ + return m_curCameraInfo->antiBanding; +} + +bool ExynosCamera::getAutoExposureLock(void) +{ + return m_curCameraInfo->autoExposureLock; +} + +bool ExynosCamera::getAutoWhiteBalanceLock(void) +{ + return m_curCameraInfo->autoWhiteBalanceLock; +} + +int ExynosCamera::getColorEffect(void) +{ + return m_curCameraInfo->effect; +} + +int ExynosCamera::getDetectedFacesAreas(int num, + int *id, + int *score, + ExynosRect *face, + ExynosRect *leftEye, + ExynosRect *rightEye, + ExynosRect *mouth) +{ + if (m_defaultCameraInfo->maxNumDetectedFaces == 0) { + LOGE("ERR(%s):maxNumDetectedFaces == 0 fail", __func__); + return -1; + } + + if (m_flagStartFaceDetection == false) { + LOGD("DEBUG(%s):m_flagStartFaceDetection == false", __func__); + return 0; + } + + if (m_defaultCameraInfo->maxNumDetectedFaces < num) + num = m_defaultCameraInfo->maxNumDetectedFaces; + + // width : 0 ~ previewW + // height : 0 ~ previewH + // if eye, mouth is not detectable : -1, -1 + ExynosRect2 *face2 = new ExynosRect2[num]; + ExynosRect2 *leftEye2 = new ExynosRect2[num]; + ExynosRect2 *rightEye2 = new ExynosRect2[num]; + ExynosRect2 *mouth2 = new ExynosRect2[num]; + + num = getDetectedFacesAreas(num, id, score, face2, leftEye2, rightEye2, mouth2); + + for (int i = 0; i < num; i++) { + + m_secRect22SecRect(&face2[i], &face[i]); + face[i].fullW = m_curCameraInfo->previewW; + face[i].fullH = m_curCameraInfo->previewH; + + m_secRect22SecRect(&leftEye2[i], &leftEye[i]); + leftEye[i].fullW = m_curCameraInfo->previewW; + leftEye[i].fullH = m_curCameraInfo->previewH; + + m_secRect22SecRect(&rightEye2[i], &rightEye[i]); + rightEye[i].fullW = m_curCameraInfo->previewW; + rightEye[i].fullH = m_curCameraInfo->previewH; + + m_secRect22SecRect(&mouth2[i], &mouth[i]); + mouth[i].fullW = m_curCameraInfo->previewW; + mouth[i].fullH = m_curCameraInfo->previewH; + } + + delete [] face2; + delete [] leftEye2; + delete [] rightEye2; + delete [] mouth2; + + return num; +} + +int ExynosCamera::getDetectedFacesAreas(int num, + int *id, + int *score, + ExynosRect2 *face, + ExynosRect2 *leftEye, + ExynosRect2 *rightEye, + ExynosRect2 *mouth) +{ + if (m_defaultCameraInfo->maxNumDetectedFaces == 0) { + LOGE("ERR(%s):maxNumDetectedFaces == 0 fail", __func__); + return -1; + } + + if (m_flagStartFaceDetection == false) { + LOGD("DEBUG(%s):m_flagStartFaceDetection == false", __func__); + return 0; + } + + int i = 0; + + if (m_defaultCameraInfo->maxNumDetectedFaces < num) + num = m_defaultCameraInfo->maxNumDetectedFaces; + + const unsigned int numOfFDEntity = 1 + ((V4L2_CID_IS_FD_GET_NEXT - V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER) * num); + + // width : 0 ~ previewW + // height : 0 ~ previewH + // if eye, mouth is not detectable : -1, -1 + struct v4l2_ext_controls fd_ctrls; + struct v4l2_ext_control *fd_ctrl = new struct v4l2_ext_control[numOfFDEntity]; + struct v4l2_ext_control *cur_ctrl; + + cur_ctrl = &fd_ctrl[0]; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_COUNT; + cur_ctrl++; + + for (i = 0; i < num; i++) { + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_CONFIDENCE; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_TOPLEFT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_TOPLEFT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_X; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_Y; + cur_ctrl++; + cur_ctrl->id = V4L2_CID_IS_FD_GET_NEXT; + cur_ctrl++; + } + + fd_ctrls.ctrl_class = V4L2_CTRL_CLASS_CAMERA; + fd_ctrls.count = i + 1; + fd_ctrls.controls = fd_ctrl; + + if (exynos_v4l2_g_ext_ctrl(m_previewDev->fd, &fd_ctrls) < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ext_ctrl() fail", __func__); + num = -1; + goto done; + } + + cur_ctrl = &fd_ctrl[0]; + num = cur_ctrl->value; + cur_ctrl++; + + for (i = 0; i < num; i++) { + id[i] = cur_ctrl->value; + cur_ctrl++; + score[i] = cur_ctrl->value; + cur_ctrl++; + + face[i].x1 = cur_ctrl->value; + cur_ctrl++; + face[i].y1 = cur_ctrl->value; + cur_ctrl++; + face[i].x2 = cur_ctrl->value; + cur_ctrl++; + face[i].y2 = cur_ctrl->value; + cur_ctrl++; + + leftEye[i].x1 = cur_ctrl->value; + cur_ctrl++; + leftEye[i].y1 = cur_ctrl->value; + cur_ctrl++; + leftEye[i].x2 = cur_ctrl->value; + cur_ctrl++; + leftEye[i].y2 = cur_ctrl->value; + cur_ctrl++; + + rightEye[i].x1 = cur_ctrl->value; + cur_ctrl++; + rightEye[i].y1 = cur_ctrl->value; + cur_ctrl++; + rightEye[i].x2 = cur_ctrl->value; + cur_ctrl++; + rightEye[i].y2 = cur_ctrl->value; + cur_ctrl++; + + mouth[i].x1 = cur_ctrl->value; + cur_ctrl++; + mouth[i].y1 = cur_ctrl->value; + cur_ctrl++; + mouth[i].x2 = cur_ctrl->value; + cur_ctrl++; + mouth[i].y2 = cur_ctrl->value; + cur_ctrl++; + } + +done: + delete [] fd_ctrl; + + return num; +} + +int ExynosCamera::getExposureCompensation(void) +{ + return m_curCameraInfo->exposure; +} + +float ExynosCamera::getExposureCompensationStep(void) +{ + // CameraParameters.h + // The exposure compensation step. Exposure compensation index multiply by + // step eqals to EV. Ex: if exposure compensation index is 6 and step is + // 0.3333, EV is -2. + // Example value: "0.333333333" or "0.5". Read only. + // -> But, this formula doesn't works in apps. + return 1.0f; +} + +int ExynosCamera::getFlashMode(void) +{ + return m_curCameraInfo->flashMode; +} + +bool ExynosCamera::getFocalLength(int *num, int *den) +{ + *num = m_defaultCameraInfo->focalLengthNum; + *num = m_defaultCameraInfo->focalLengthDen; + return true; +} + +int ExynosCamera::getFocusAreas(ExynosRect *rects) +{ + // TODO + return 0; +} + +int ExynosCamera::getFocusDistances(float *output) +{ + // TODO + return 0; +} + +int ExynosCamera::getFocusMode(void) +{ + return m_curCameraInfo->focusMode; +} + +float ExynosCamera::getHorizontalViewAngle(void) +{ + //TODO + return 51.2f; +} + +int ExynosCamera::getJpegQuality(void) +{ + return m_jpegQuality; +} + +int ExynosCamera::getJpegThumbnailQuality(void) +{ + return m_jpegThumbnailQuality; +} + +bool ExynosCamera::getJpegThumbnailSize(int *w, int *h) +{ + *w = m_curCameraInfo->thumbnailW; + *h = m_curCameraInfo->thumbnailH; + return true; +} + +int ExynosCamera::getMaxExposureCompensation(void) +{ + return m_defaultCameraInfo->maxExposure; +} + +int ExynosCamera::getMaxNumDetectedFaces(void) +{ + return m_defaultCameraInfo->maxNumDetectedFaces; +} + +int ExynosCamera::getMaxNumFocusAreas(void) +{ + return m_defaultCameraInfo->maxNumFocusAreas; +} + +int ExynosCamera::getMaxNumMeteringAreas(void) +{ + return m_defaultCameraInfo->maxNumMeteringAreas; +} + +int ExynosCamera::getMaxZoom(void) +{ + return m_defaultCameraInfo->maxZoom; +} + +int ExynosCamera::getMeteringAreas(ExynosRect *rects) +{ + // TODO + return 0; +} + +int ExynosCamera::getMinExposureCompensation(void) +{ + return m_defaultCameraInfo->minExposure; +} + +int ExynosCamera::getPictureFormat(void) +{ + return m_curCameraInfo->pictureColorFormat; +} + +bool ExynosCamera::getPictureSize(int *w, int *h) +{ + *w = m_curCameraInfo->pictureW; + *h = m_curCameraInfo->pictureH; + return true; +} + +int ExynosCamera::getPreviewFormat(void) +{ + return m_curCameraInfo->previewColorFormat; +} + +bool ExynosCamera::getPreviewFpsRange(int *min, int *max) +{ + *min = 1; + *max = m_defaultCameraInfo->fps; + return true; +} + +int ExynosCamera::getPreviewFrameRate(void) +{ + return m_curCameraInfo->fps; +} + +bool ExynosCamera::getPreviewSize(int *w, int *h) +{ + *w = m_curCameraInfo->previewW; + *h = m_curCameraInfo->previewH; + return true; +} + +int ExynosCamera::getSceneMode(void) +{ + return m_curCameraInfo->sceneMode; +} + +int ExynosCamera::getSupportedAntibanding(void) +{ + return m_defaultCameraInfo->antiBandingList; +} + +int ExynosCamera::getSupportedColorEffects(void) +{ + return m_defaultCameraInfo->effectList; +} + +int ExynosCamera::getSupportedFlashModes(void) +{ + return m_defaultCameraInfo->flashModeList; +} + +int ExynosCamera::getSupportedFocusModes(void) +{ + return m_defaultCameraInfo->focusModeList; +} + +bool ExynosCamera::getSupportedJpegThumbnailSizes(int *w, int *h) +{ + *w = m_defaultCameraInfo->thumbnailW; + *h = m_defaultCameraInfo->thumbnailH; + return true; +} + +bool ExynosCamera::getSupportedPictureSizes(int *w, int *h) +{ + *w = m_defaultCameraInfo->pictureW; + *h = m_defaultCameraInfo->pictureH; + return true; +} + +bool ExynosCamera::getSupportedPreviewSizes(int *w, int *h) +{ + *w = m_defaultCameraInfo->previewW; + *h = m_defaultCameraInfo->previewH; + return true; +} + +int ExynosCamera::getSupportedSceneModes(void) +{ + return m_defaultCameraInfo->sceneModeList; +} + +bool ExynosCamera::getSupportedVideoSizes(int *w, int *h) +{ + *w = m_defaultCameraInfo->videoW; + *h = m_defaultCameraInfo->videoH; + return true; +} + +bool ExynosCamera::getPreferredPreivewSizeForVideo(int *w, int *h) +{ + *w = m_defaultCameraInfo->prefVideoPreviewW; + *h = m_defaultCameraInfo->prefVideoPreviewH; + return true; +} + +int ExynosCamera::getSupportedWhiteBalance(void) +{ + return m_defaultCameraInfo->whiteBalanceList; +} + +float ExynosCamera::getVerticalViewAngle(void) +{ + // TODO + return 39.4f; +} + +bool ExynosCamera::getVideoStabilization(void) +{ + return m_curCameraInfo->videoStabilization; +} + +int ExynosCamera::getWhiteBalance(void) +{ + return m_curCameraInfo->whiteBalance; +} + +int ExynosCamera::getZoom(void) +{ + return m_curCameraInfo->zoom; +} + +int ExynosCamera::getMaxZoomRatio(void) +{ + return 400; +} + +bool ExynosCamera::isAutoExposureLockSupported(void) +{ + return m_defaultCameraInfo->autoExposureLockSupported; +} + +bool ExynosCamera::isAutoWhiteBalanceLockSupported(void) +{ + return m_defaultCameraInfo->autoWhiteBalanceLockSupported; +} + +bool ExynosCamera::isSmoothZoomSupported(void) +{ + if (m_defaultCameraInfo->hwZoomSupported == true) + return true; + else + return false; +} + +bool ExynosCamera::isVideoSnapshotSupported(void) +{ + return true; +} + +bool ExynosCamera::isVideoStabilizationSupported(void) +{ + return m_defaultCameraInfo->supportVideoStabilization; +} + +bool ExynosCamera::isZoomSupported(void) +{ + return true; +} + +bool ExynosCamera::setAntibanding(int value) +{ + int internalValue = -1; + + switch (value) { + case ANTIBANDING_AUTO: + internalValue = ::ANTI_BANDING_AUTO; + break; + case ANTIBANDING_50HZ: + internalValue = ::ANTI_BANDING_50HZ; + break; + case ANTIBANDING_60HZ: + internalValue = ::ANTI_BANDING_60HZ; + break; + case ANTIBANDING_OFF: + internalValue = ::ANTI_BANDING_OFF; + break; + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (m_internalISP == true) { + if (internalValue < ::IS_AFC_DISABLE || ::IS_AFC_MAX <= internalValue) { + LOGE("ERR(%s):Invalid value (%d)", __func__, value); + return false; + } + } else { + if (internalValue < ::ANTI_BANDING_AUTO || ::ANTI_BANDING_OFF < internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->antiBanding != value) { + m_curCameraInfo->antiBanding = value; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_AFC_MODE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setAutoExposureLock(bool toggle) +{ + int internalValue = -1; + + if (m_curCameraInfo->autoExposureLock == toggle) + return true; + + m_curCameraInfo->autoExposureLock = toggle; + + if (m_curCameraInfo->autoExposureLock == true && m_curCameraInfo->autoWhiteBalanceLock == true) + internalValue = AE_LOCK_AWB_LOCK; + else if (m_curCameraInfo->autoExposureLock == true && m_curCameraInfo->autoWhiteBalanceLock == false) + internalValue = AE_LOCK_AWB_UNLOCK; + else if (m_curCameraInfo->autoExposureLock == false && m_curCameraInfo->autoWhiteBalanceLock == true) + internalValue = AE_UNLOCK_AWB_LOCK; + else // if (m_curCameraInfo->autoExposureLock == false && m_curCameraInfo->autoWhiteBalanceLock == false) + internalValue = AE_UNLOCK_AWB_UNLOCK; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + return true; +} + +bool ExynosCamera::setAutoWhiteBalanceLock(bool toggle) +{ + int internalValue = -1; + + if (m_curCameraInfo->autoWhiteBalanceLock == toggle) + return true; + + m_curCameraInfo->autoWhiteBalanceLock = toggle; + + if (m_curCameraInfo->autoExposureLock == true && m_curCameraInfo->autoWhiteBalanceLock == true) + internalValue = AE_LOCK_AWB_LOCK; + else if (m_curCameraInfo->autoExposureLock == true && m_curCameraInfo->autoWhiteBalanceLock == false) + internalValue = AE_LOCK_AWB_UNLOCK; + else if (m_curCameraInfo->autoExposureLock == false && m_curCameraInfo->autoWhiteBalanceLock == true) + internalValue = AE_UNLOCK_AWB_LOCK; + else // if (m_curCameraInfo->autoExposureLock == false && m_curCameraInfo->autoWhiteBalanceLock == false) + internalValue = AE_UNLOCK_AWB_UNLOCK; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + return true; +} + +bool ExynosCamera::setColorEffect(int value) +{ + int internalValue = -1; + + switch (value) { + case EFFECT_NONE: + if (m_internalISP == true) + internalValue = ::IS_IMAGE_EFFECT_DISABLE; + else + internalValue = ::IMAGE_EFFECT_NONE; + break; + case EFFECT_MONO: + if (m_internalISP == true) + internalValue = ::IS_IMAGE_EFFECT_MONOCHROME; + else + internalValue = ::IMAGE_EFFECT_BNW; + break; + case EFFECT_NEGATIVE: + internalValue = IS_IMAGE_EFFECT_NEGATIVE_MONO; + break; + case EFFECT_SEPIA: + if (m_internalISP == true) + internalValue = ::IS_IMAGE_EFFECT_SEPIA; + else + internalValue = ::IMAGE_EFFECT_SEPIA; + break; + case EFFECT_AQUA: + case EFFECT_SOLARIZE: + case EFFECT_POSTERIZE: + case EFFECT_WHITEBOARD: + case EFFECT_BLACKBOARD: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (m_internalISP == true) { + if (internalValue < ::IS_IMAGE_EFFECT_DISABLE || ::IS_IMAGE_EFFECT_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } else { + if (internalValue <= ::IMAGE_EFFECT_BASE || ::IMAGE_EFFECT_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->effect != value) { + m_curCameraInfo->effect = value; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_IMAGE_EFFECT, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_EFFECT, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +bool ExynosCamera::setExposureCompensation(int value) +{ + int internalValue = value; + + if (m_internalISP == true) { + internalValue += IS_EXPOSURE_DEFAULT; + if (internalValue < IS_EXPOSURE_MINUS_2 || IS_EXPOSURE_PLUS_2 < internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } else { + internalValue += EV_DEFAULT; + if (internalValue < EV_MINUS_4 || EV_PLUS_4 < internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->exposure != value) { + m_curCameraInfo->exposure = value; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_EXPOSURE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (this->setBrightness(value) == false) { + LOGE("ERR(%s):setBrightness() fail", __func__); + return false; + } + } + } + } + + return true; +} + +bool ExynosCamera::setFlashMode(int value) +{ + int internalValue = -1; + + switch (value) { + case FLASH_MODE_OFF: + internalValue = ::FLASH_MODE_OFF; + break; + case FLASH_MODE_AUTO: + internalValue = ::FLASH_MODE_AUTO; + break; + case FLASH_MODE_ON: + internalValue = ::FLASH_MODE_ON; + break; + case FLASH_MODE_TORCH: + internalValue = ::FLASH_MODE_TORCH; + break; + case FLASH_MODE_RED_EYE: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (internalValue <= ::FLASH_MODE_BASE || ::FLASH_MODE_MAX <= internalValue) { + LOGE("ERR(%s):Invalid value (%d)", __func__, value); + return false; + } + + if (m_curCameraInfo->flashMode != value) { + m_curCameraInfo->flashMode = value; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FLASH_MODE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setFocusAreas(int num, ExynosRect* rects, int *weights) +{ + if (m_defaultCameraInfo->maxNumFocusAreas == 0) { + LOGV("DEBUG(%s):maxNumFocusAreas is 0. so, ignored", __func__); + return true; + } + + bool ret = true; + + ExynosRect2 *rect2s = new ExynosRect2[num]; + for (int i = 0; i < num; i++) + m_secRect2SecRect2(&rects[i], &rect2s[i]); + + ret = setFocusAreas(num, rect2s, weights); + + delete [] rect2s; + + return ret; +} + +bool ExynosCamera::setFocusAreas(int num, ExynosRect2* rect2s, int *weights) +{ + if (m_defaultCameraInfo->maxNumFocusAreas == 0) { + LOGV("DEBUG(%s):maxNumFocusAreas is 0. so, ignored", __func__); + return true; + } + + int new_x = 0; + int new_y = 0; + + if (m_defaultCameraInfo->maxNumFocusAreas < num) + num = m_defaultCameraInfo->maxNumFocusAreas; + + if (m_flagCreate == true) { + for (int i = 0; i < num; i++) { + if ( num == 1 + && rect2s[0].x1 == 0 + && rect2s[0].y1 == 0 + && rect2s[0].x2 == m_curCameraInfo->previewW + && rect2s[0].y2 == m_curCameraInfo->previewH) { + // TODO : driver decide focus areas -> focus center. + new_x = (m_curCameraInfo->previewW) / 2; + new_y = (m_curCameraInfo->previewH) / 2; + } else { + new_x = (rect2s[i].x1 + rect2s[i].x2) / 2; + new_y = (rect2s[i].y1 + rect2s[i].y2) / 2; + } + + m_touchAFMode = true; + if ( exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_OBJECT_POSITION_X, new_x) < 0 + && exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_OBJECT_POSITION_Y, new_y) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setFocusMode(int value) +{ + int internalValue = -1; + + switch (value) { + case FOCUS_MODE_AUTO: + internalValue = ::FOCUS_MODE_AUTO; + m_touchAFMode = false; + break; + case FOCUS_MODE_INFINITY: + internalValue = ::FOCUS_MODE_INFINITY; + m_touchAFMode = false; + break; + case FOCUS_MODE_MACRO: + internalValue = ::FOCUS_MODE_MACRO; + m_touchAFMode = false; + break; + case FOCUS_MODE_CONTINUOUS_VIDEO: + case FOCUS_MODE_CONTINUOUS_PICTURE: + internalValue = ::FOCUS_MODE_CONTINOUS; + m_touchAFMode = false; + break; + case FOCUS_MODE_TOUCH: + internalValue = ::FOCUS_MODE_TOUCH; + m_touchAFMode = true; + break; + case FOCUS_MODE_FIXED: + internalValue = ::FOCUS_MODE_FIXED; + m_touchAFMode = false; + break; + case FOCUS_MODE_EDOF: + default: + m_touchAFMode = false; + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (::FOCUS_MODE_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + + if (m_curCameraInfo->focusMode != value) { + m_curCameraInfo->focusMode = value; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FOCUS_MODE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setGpsAltitude(const char *gpsAltitude) +{ + double conveted_altitude = 0; + + if (gpsAltitude == NULL) + m_curCameraInfo->gpsAltitude = 0; + else { + conveted_altitude = atof(gpsAltitude); + m_curCameraInfo->gpsAltitude = (long)(conveted_altitude * 100 / 1); + } + + return true; +} + +bool ExynosCamera::setGpsLatitude(const char *gpsLatitude) +{ + double conveted_latitude = 0; + + if (gpsLatitude == NULL) + m_curCameraInfo->gpsLatitude = 0; + else { + conveted_latitude = atof(gpsLatitude); + m_curCameraInfo->gpsLatitude = (long)(conveted_latitude * 10000 / 1); + } + + return true; +} + +bool ExynosCamera::setGpsLongitude(const char *gpsLongitude) +{ + double conveted_longitude = 0; + + if (gpsLongitude == NULL) + m_curCameraInfo->gpsLongitude = 0; + else { + conveted_longitude = atof(gpsLongitude); + m_curCameraInfo->gpsLongitude = (long)(conveted_longitude * 10000 / 1); + } + + return true; +} + +bool ExynosCamera::setGpsProcessingMethod(const char *gpsProcessingMethod) +{ + memset(mExifInfo.gps_processing_method, 0, sizeof(mExifInfo.gps_processing_method)); + + if (gpsProcessingMethod != NULL) { + size_t len = strlen(gpsProcessingMethod); + if (len > sizeof(mExifInfo.gps_processing_method)) { + len = sizeof(mExifInfo.gps_processing_method); + } + memcpy(mExifInfo.gps_processing_method, gpsProcessingMethod, len); + } + + return true; +} + +bool ExynosCamera::setGpsTimeStamp(const char *gpsTimestamp) +{ + if (gpsTimestamp == NULL) + m_curCameraInfo->gpsTimestamp = 0; + else + m_curCameraInfo->gpsTimestamp = atol(gpsTimestamp); + + return true; +} + +bool ExynosCamera::setJpegQuality(int quality) +{ + if (quality < JPEG_QUALITY_MIN || JPEG_QUALITY_MAX < quality) { + LOGE("ERR(%s):Invalid quality (%d)", __func__, quality); + return false; + } + + m_jpegQuality = quality; + + return true; +} + +bool ExynosCamera::setJpegThumbnailQuality(int quality) +{ + if (quality < JPEG_QUALITY_MIN || JPEG_QUALITY_MAX < quality) { + LOGE("ERR(%s):Invalid quality (%d)", __func__, quality); + return false; + } + + m_jpegThumbnailQuality = quality; + + return true; +} + +bool ExynosCamera::setJpegThumbnailSize(int w, int h) +{ + m_curCameraInfo->thumbnailW = w; + m_curCameraInfo->thumbnailH = h; + return true; +} + +bool ExynosCamera::setMeteringAreas(int num, ExynosRect *rects, int *weights) +{ + if (m_defaultCameraInfo->maxNumMeteringAreas == 0) { + LOGV("DEBUG(%s):maxNumMeteringAreas is 0. so, ignored", __func__); + return true; + } + + if (m_defaultCameraInfo->maxNumMeteringAreas < num) + num = m_defaultCameraInfo->maxNumMeteringAreas; + + if (m_flagCreate == true) { + for (int i = 0; i < num; i++) { + if ( exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_METERING_POSITION_X, rects[i].x) < 0 + && exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_METERING_POSITION_Y, rects[i].y) < 0 + && exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_METERING_WINDOW_X, rects[i].w) < 0 + && exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_METERING_WINDOW_Y, rects[i].h) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setMeteringAreas(int num, ExynosRect2 *rect2s, int *weights) +{ + if (m_defaultCameraInfo->maxNumMeteringAreas == 0) { + LOGV("DEBUG(%s):maxNumMeteringAreas is 0. so, ignored", __func__); + return true; + } + + bool ret = true; + + ExynosRect *rects = new ExynosRect[num]; + for (int i = 0; i < num; i++) + m_secRect22SecRect(&rect2s[i], &rects[i]); + + /* FIXME: Currnetly HW dose not support metering area */ + //ret = setMeteringAreas(num, rects, weights); + + delete [] rects; + + return ret; +} + +bool ExynosCamera::setPictureFormat(int colorFormat) +{ + m_curCameraInfo->pictureColorFormat = colorFormat; + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 + m_printFormat(m_curCameraInfo->pictureColorFormat, "PictureFormat"); +#endif + return true; +} + +bool ExynosCamera::setPictureSize(int w, int h) +{ + m_curCameraInfo->pictureW = w; + m_curCameraInfo->pictureH = h; + + // HACK : Camera cannot support zoom. So, we must make max size picture w, h + m_curCameraInfo->pictureW = m_defaultCameraInfo->pictureW; + m_curCameraInfo->pictureH = m_defaultCameraInfo->pictureH; + + return true; +} + +bool ExynosCamera::setPreviewFormat(int colorFormat) +{ + m_curCameraInfo->previewColorFormat = colorFormat; + +#if defined(LOG_NDEBUG) && LOG_NDEBUG == 0 + m_printFormat(m_curCameraInfo->previewColorFormat, "PreviewtFormat"); +#endif + + return true; +} + +bool ExynosCamera::setPreviewFrameRate(int fps) +{ + if (fps < FRAME_RATE_AUTO || FRAME_RATE_MAX < fps) + LOGE("ERR(%s):Invalid fps(%d)", __func__, fps); + + if (m_flagCreate == true) { + m_curCameraInfo->fps = fps; + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_FRAME_RATE, fps) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + + return true; +} + +bool ExynosCamera::setPreviewSize(int w, int h) +{ + m_curCameraInfo->previewW = w; + m_curCameraInfo->previewH = h; + return true; +} + +bool ExynosCamera::setRecordingHint(bool hint) +{ + // TODO : fixed fps? + /* DIS is only possible recording hint is true. */ + m_recordingHint = hint; + return true; +} + +bool ExynosCamera::setRotation(int rotation) +{ + if (rotation < 0) { + LOGE("ERR(%s):Invalid rotation (%d)", __func__, rotation); + return false; + } + m_curCameraInfo->rotation = rotation; + + return true; +} + +int ExynosCamera::getRotation(void) +{ + return m_curCameraInfo->rotation; +} + +bool ExynosCamera::setSceneMode(int value) +{ + int internalValue = -1; + + switch (value) { + case SCENE_MODE_AUTO: + internalValue = ::SCENE_MODE_NONE; + break; + case SCENE_MODE_PORTRAIT: + internalValue = ::SCENE_MODE_PORTRAIT; + break; + case SCENE_MODE_LANDSCAPE: + internalValue = ::SCENE_MODE_LANDSCAPE; + break; + case SCENE_MODE_NIGHT: + internalValue = ::SCENE_MODE_NIGHTSHOT; + break; + case SCENE_MODE_BEACH: + internalValue = ::SCENE_MODE_BEACH_SNOW; + break; + case SCENE_MODE_SNOW: + internalValue = ::SCENE_MODE_BEACH_SNOW; + break; + case SCENE_MODE_SUNSET: + internalValue = ::SCENE_MODE_SUNSET; + break; + case SCENE_MODE_FIREWORKS: + internalValue = ::SCENE_MODE_FIREWORKS; + break; + case SCENE_MODE_SPORTS: + internalValue = ::SCENE_MODE_SPORTS; + break; + case SCENE_MODE_PARTY: + internalValue = ::SCENE_MODE_PARTY_INDOOR; + break; + case SCENE_MODE_CANDLELIGHT: + internalValue = ::SCENE_MODE_CANDLE_LIGHT; + break; + case SCENE_MODE_STEADYPHOTO: + internalValue = ::SCENE_MODE_TEXT; + break; + case SCENE_MODE_ACTION: + case SCENE_MODE_NIGHT_PORTRAIT: + case SCENE_MODE_THEATRE: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (internalValue <= ::SCENE_MODE_BASE || ::SCENE_MODE_MAX <= internalValue) { + LOGE("ERR(%s):Invalid value (%d)", __func__, internalValue); + return false; + } + + if (m_curCameraInfo->sceneMode != value) { + m_curCameraInfo->sceneMode = value; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SCENE_MODE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::setVideoStabilization(bool toggle) +{ + m_curCameraInfo->videoStabilization = toggle; + + if (m_previewDev->flagStart == true) { + if (m_curCameraInfo->applyVideoStabilization != toggle) { + + int dis = (toggle == true) ? CAMERA_DIS_ON : CAMERA_DIS_OFF; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_DIS, dis) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } else { + m_curCameraInfo->applyVideoStabilization = toggle; + } + } + } + return true; +} + +bool ExynosCamera::setWhiteBalance(int value) +{ + int internalValue = -1; + + switch (value) { + case WHITE_BALANCE_AUTO: + if (m_internalISP == true) + internalValue = ::IS_AWB_AUTO; + else + internalValue = ::WHITE_BALANCE_AUTO; + break; + case WHITE_BALANCE_INCANDESCENT: + if (m_internalISP == true) + internalValue = ::IS_AWB_TUNGSTEN; + else + internalValue = ::WHITE_BALANCE_TUNGSTEN; + break; + case WHITE_BALANCE_FLUORESCENT: + if (m_internalISP == true) + internalValue = ::IS_AWB_FLUORESCENT; + else + internalValue = ::WHITE_BALANCE_FLUORESCENT; + break; + case WHITE_BALANCE_DAYLIGHT: + if (m_internalISP == true) + internalValue = ::IS_AWB_DAYLIGHT; + else + internalValue = ::WHITE_BALANCE_SUNNY; + break; + case WHITE_BALANCE_CLOUDY_DAYLIGHT: + if (m_internalISP == true) + internalValue = ::IS_AWB_CLOUDY; + else + internalValue = ::WHITE_BALANCE_CLOUDY; + break; + case WHITE_BALANCE_WARM_FLUORESCENT: + case WHITE_BALANCE_TWILIGHT: + case WHITE_BALANCE_SHADE: + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (m_internalISP == true) { + if (internalValue < ::IS_AWB_AUTO || ::IS_AWB_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } else { + if (internalValue <= ::WHITE_BALANCE_BASE || ::WHITE_BALANCE_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->whiteBalance != value) { + m_curCameraInfo->whiteBalance = value; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_AWB_MODE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_WHITE_BALANCE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +bool ExynosCamera::setZoom(int value) +{ + if (value < ZOOM_LEVEL_0 || ZOOM_LEVEL_MAX <= value) { + LOGE("ERR(%s):Invalid value (%d)", __func__, value); + return false; + } + + if (m_curCameraInfo->zoom != value) { + m_curCameraInfo->zoom = value; + if (m_defaultCameraInfo->hwZoomSupported == true) { + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_ZOOM, value) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } else { + if (m_setZoom(m_previewDev->fd, m_curCameraInfo->zoom, m_curCameraInfo->previewW, m_curCameraInfo->previewH) == false) { + LOGE("ERR(%s):m_setZoom(%d) fail", __func__, m_curCameraInfo->zoom); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::m_setWidthHeight(int mode, + int fd, + struct pollfd *event, + int w, + int h, + int colorFormat, + struct ExynosBuffer *buf, + bool *validBuf) +{ + // Get and throw away the first frame since it is often garbled. + memset(event, 0, sizeof(struct pollfd)); + event->fd = fd; + event->events = POLLIN | POLLERR; + + int numOfBuf = 0; + + for (int i = 0; i < VIDEO_MAX_FRAME; i++) { + if (buf[i].virt.p != NULL || buf[i].phys.p != 0) { + validBuf[i] = true; + numOfBuf++; + } else { + validBuf[i] = false; + } + } + + struct v4l2_format v4l2_fmt; + struct v4l2_pix_format pixfmt; + unsigned int bpp; + unsigned int planes; + + memset(&v4l2_fmt, 0, sizeof(struct v4l2_format)); + memset(&pixfmt, 0, sizeof(pixfmt)); + + switch(mode) { + case PREVIEW_MODE: + case VIDEO_MODE: + v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + V4L2_PIX_2_YUV_INFO(colorFormat, &bpp, &planes); + + v4l2_fmt.fmt.pix_mp.width = w; + v4l2_fmt.fmt.pix_mp.height = h; + v4l2_fmt.fmt.pix_mp.pixelformat = colorFormat; + v4l2_fmt.fmt.pix_mp.num_planes = planes; + + if (exynos_v4l2_s_fmt(fd, &v4l2_fmt) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_fmt() fail", __func__); + return false; + } + break; + case PICTURE_MODE: + v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + pixfmt.width = w; + pixfmt.height = h; + pixfmt.pixelformat = colorFormat; + if (pixfmt.pixelformat == V4L2_PIX_FMT_JPEG) + pixfmt.colorspace = V4L2_COLORSPACE_JPEG; + + v4l2_fmt.fmt.pix = pixfmt; + + if (exynos_v4l2_s_fmt(fd, &v4l2_fmt) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_fmt() fail", __func__); + return false; + } + break; + default: + break; + } + + struct v4l2_requestbuffers req; + req.count = numOfBuf; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + req.memory = V4L2_MEMORY_USERPTR; + + if (exynos_v4l2_reqbufs(fd, &req) < 0) { + LOGE("ERR(%s):exynos_v4l2_reqbufs(%d) fail", __func__, numOfBuf); + return false; + } + + for (int i = 0; i < VIDEO_MAX_FRAME; i++) { + if (validBuf[i] == true) { + + struct v4l2_buffer v4l2_buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + v4l2_buf.m.planes = planes; + v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + v4l2_buf.memory = V4L2_MEMORY_USERPTR; + v4l2_buf.index = buf[i].reserved.p; + v4l2_buf.length = 0; + + for (int j = 0; j < 3; j++) { + v4l2_buf.m.planes[j].m.userptr = (unsigned long)buf[i].virt.extP[j]; + v4l2_buf.m.planes[j].length = buf[i].size.extS[j]; + + if (buf[i].size.extS[j] != 0) + v4l2_buf.length++; + } + + if (exynos_v4l2_qbuf(fd, &v4l2_buf) < 0) { + LOGE("ERR(%s):exynos_v4l2_qbuf(%d) fail", __func__, i); + return false; + } + } + } + + /* + m_currentZoom = -1; + + if (m_setZoom(fd, m_curCameraInfo->zoom, w, h) == false) + LOGE("ERR(%s):m_setZoom(%d, %d) fail", __func__, mode, m_curCameraInfo->zoom); + */ + return true; +} + +bool ExynosCamera::m_setZoom(int fd, int zoom, int w, int h) +{ + int ret = true; + + if (m_currentZoom != zoom) { + m_currentZoom = zoom; + + int real_zoom = 0; + + if (m_defaultCameraInfo->hwZoomSupported == true) + real_zoom = 0; // just adjust ratio, not digital zoom. + else + real_zoom = zoom; // adjust ratio, digital zoom + + ret = m_setCrop(fd, w, h, real_zoom); + if (ret == false) + LOGE("ERR(%s):m_setCrop(%d, %d) fail", __func__, w, h); + } + + return ret; +} + +bool ExynosCamera::m_setCrop(int fd, int w, int h, int zoom) +{ + v4l2_cropcap cropcap; + v4l2_crop crop; + unsigned int crop_x = 0; + unsigned int crop_y = 0; + unsigned int crop_w = 0; + unsigned int crop_h = 0; + + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (exynos_v4l2_cropcap(fd, &cropcap) < 0) { + LOGE("ERR(%s):exynos_v4l2_cropcap() fail)", __func__); + return false; + } + + m_getCropRect(cropcap.bounds.width, cropcap.bounds.height, + w, h, + &crop_x, &crop_y, + &crop_w, &crop_h, + zoom); + + cropcap.defrect.left = crop_x; + cropcap.defrect.top = crop_y; + cropcap.defrect.width = crop_w; + cropcap.defrect.height = crop_h; + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; + + if (exynos_v4l2_s_crop(fd, &crop) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_crop() fail(%d))", __func__, zoom); + return false; + } + + /* + LOGD("## 1 w : %d", w); + LOGD("## 1 h : %d", h); + LOGD("## 1 zoom : %d", zoom); + LOGD("## 1 cropcap.bounds.w : %d", cropcap.bounds.width); + LOGD("## 1 cropcap.bounds.h : %d", cropcap.bounds.height); + LOGD("## 2 crop_x : %d", crop_x); + LOGD("## 2 crop_y : %d", crop_y); + LOGD("## 2 crop_w : %d", crop_w); + LOGD("## 2 crop_h : %d", crop_h); + LOGD("## 2 cropcap.defrect.left : %d", cropcap.defrect.left); + LOGD("## 2 cropcap.defrect.top : %d", cropcap.defrect.top); + LOGD("## 2 cropcap.defrect.width : %d", cropcap.defrect.width); + LOGD("## 2 cropcap.defrect.height: %d", cropcap.defrect.height); + */ + + return true; +} + +bool ExynosCamera::m_getCropRect(unsigned int src_w, unsigned int src_h, + unsigned int dst_w, unsigned int dst_h, + unsigned int *crop_x, unsigned int *crop_y, + unsigned int *crop_w, unsigned int *crop_h, + int zoom) +{ + #define DEFAULT_ZOOM_RATIO (4) // 4x zoom + #define DEFAULT_ZOOM_RATIO_SHIFT (2) + int max_zoom = m_defaultCameraInfo->maxZoom; + + *crop_w = src_w; + *crop_h = src_h; + + if ( src_w != dst_w + || src_h != dst_h) { + float src_ratio = 1.0f; + float dst_ratio = 1.0f; + + // ex : 1024 / 768 + src_ratio = (float)src_w / (float)src_h; + + // ex : 352 / 288 + dst_ratio = (float)dst_w / (float)dst_h; + + if (src_ratio != dst_ratio) { + if (src_ratio <= dst_ratio) { + // shrink h + *crop_w = src_w; + *crop_h = src_w / dst_ratio; + } else { //(src_ratio > dst_ratio) + // shrink w + *crop_w = src_h * dst_ratio; + *crop_h = src_h; + } + } + + if (zoom != 0) { + unsigned int zoom_w_step = + (*crop_w - (*crop_w >> DEFAULT_ZOOM_RATIO_SHIFT)) / max_zoom; + + *crop_w = *crop_w - (zoom_w_step * zoom); + + unsigned int zoom_h_step = + (*crop_h - (*crop_h >> DEFAULT_ZOOM_RATIO_SHIFT)) / max_zoom; + + *crop_h = *crop_h - (zoom_h_step * zoom); + } + } + + #define CAMERA_CROP_WIDTH_RESTRAIN_NUM (0x10) // 16 + unsigned int w_align = (*crop_w & (CAMERA_CROP_WIDTH_RESTRAIN_NUM - 1)); + if (w_align != 0) { + if ( (CAMERA_CROP_WIDTH_RESTRAIN_NUM >> 1) <= w_align + && *crop_w + (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align) <= dst_w) { + *crop_w += (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align); + } + else + *crop_w -= w_align; + } + + #define CAMERA_CROP_HEIGHT_RESTRAIN_NUM (0x2) // 2 + unsigned int h_align = (*crop_h & (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - 1)); + if (h_align != 0) { + if ( (CAMERA_CROP_HEIGHT_RESTRAIN_NUM >> 1) <= h_align + && *crop_h + (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align) <= dst_h) { + *crop_h += (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align); + } + else + *crop_h -= h_align; + } + + *crop_x = (src_w - *crop_w) >> 1; + *crop_y = (src_h - *crop_h) >> 1; + + return true; +} + +void ExynosCamera::m_setExifFixedAttribute(void) +{ + char property[PROPERTY_VALUE_MAX]; + + //2 0th IFD TIFF Tags + //3 Maker + property_get("ro.product.brand", property, EXIF_DEF_MAKER); + strncpy((char *)mExifInfo.maker, property, + sizeof(mExifInfo.maker) - 1); + mExifInfo.maker[sizeof(mExifInfo.maker) - 1] = '\0'; + //3 Model + property_get("ro.product.model", property, EXIF_DEF_MODEL); + strncpy((char *)mExifInfo.model, property, + sizeof(mExifInfo.model) - 1); + mExifInfo.model[sizeof(mExifInfo.model) - 1] = '\0'; + //3 Software + property_get("ro.build.id", property, EXIF_DEF_SOFTWARE); + strncpy((char *)mExifInfo.software, property, + sizeof(mExifInfo.software) - 1); + mExifInfo.software[sizeof(mExifInfo.software) - 1] = '\0'; + + //3 YCbCr Positioning + mExifInfo.ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING; + + //2 0th IFD Exif Private Tags + //3 F Number + mExifInfo.fnumber.num = EXIF_DEF_FNUMBER_NUM; + mExifInfo.fnumber.den = EXIF_DEF_FNUMBER_DEN; + //3 Exposure Program + mExifInfo.exposure_program = EXIF_DEF_EXPOSURE_PROGRAM; + //3 Exif Version + memcpy(mExifInfo.exif_version, EXIF_DEF_EXIF_VERSION, sizeof(mExifInfo.exif_version)); + //3 Aperture + uint32_t av = APEX_FNUM_TO_APERTURE((double)mExifInfo.fnumber.num/mExifInfo.fnumber.den); + mExifInfo.aperture.num = av*EXIF_DEF_APEX_DEN; + mExifInfo.aperture.den = EXIF_DEF_APEX_DEN; + //3 Maximum lens aperture + mExifInfo.max_aperture.num = mExifInfo.aperture.num; + mExifInfo.max_aperture.den = mExifInfo.aperture.den; + //3 Lens Focal Length + mExifInfo.focal_length.num = m_defaultCameraInfo->focalLengthNum; + mExifInfo.focal_length.den = m_defaultCameraInfo->focalLengthDen; + //3 User Comments + strcpy((char *)mExifInfo.user_comment, EXIF_DEF_USERCOMMENTS); + //3 Color Space information + mExifInfo.color_space = EXIF_DEF_COLOR_SPACE; + //3 Exposure Mode + mExifInfo.exposure_mode = EXIF_DEF_EXPOSURE_MODE; + + //2 0th IFD GPS Info Tags + unsigned char gps_version[4] = { 0x02, 0x02, 0x00, 0x00 }; + memcpy(mExifInfo.gps_version_id, gps_version, sizeof(gps_version)); + + //2 1th IFD TIFF Tags + mExifInfo.compression_scheme = EXIF_DEF_COMPRESSION; + mExifInfo.x_resolution.num = EXIF_DEF_RESOLUTION_NUM; + mExifInfo.x_resolution.den = EXIF_DEF_RESOLUTION_DEN; + mExifInfo.y_resolution.num = EXIF_DEF_RESOLUTION_NUM; + mExifInfo.y_resolution.den = EXIF_DEF_RESOLUTION_DEN; + mExifInfo.resolution_unit = EXIF_DEF_RESOLUTION_UNIT; +} + +void ExynosCamera::m_setExifChangedAttribute(exif_attribute_t *exifInfo, ExynosRect *rect) +{ + //2 0th IFD TIFF Tags + //3 Width + exifInfo->width = rect->w; + //3 Height + exifInfo->height = rect->h; + //3 Orientation + switch (m_curCameraInfo->rotation) { + case 90: + exifInfo->orientation = EXIF_ORIENTATION_90; + break; + case 180: + exifInfo->orientation = EXIF_ORIENTATION_180; + break; + case 270: + exifInfo->orientation = EXIF_ORIENTATION_270; + break; + case 0: + default: + exifInfo->orientation = EXIF_ORIENTATION_UP; + break; + } + //3 Date time + time_t rawtime; + struct tm *timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime((char *)exifInfo->date_time, 20, "%Y:%m:%d %H:%M:%S", timeinfo); + + //2 0th IFD Exif Private Tags + //3 Exposure Time + int shutterSpeed = 100; + /* TBD - front camera needs to be fixed to support this g_ctrl, + it current returns a negative err value, so avoid putting + odd value into exif for now */ + if ( exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_EXIF_SHUTTERSPEED, &shutterSpeed) < 0 + || shutterSpeed < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ctrl() fail, using 100", __func__); + shutterSpeed = 100; + } + + exifInfo->exposure_time.num = 1; + // x us -> 1/x s */ + exifInfo->exposure_time.den = (uint32_t)(1000000 / shutterSpeed); + + //3 ISO Speed Rating + int iso = m_curCameraInfo->iso; + + /* TBD - front camera needs to be fixed to support this g_ctrl, + it current returns a negative err value, so avoid putting + odd value into exif for now */ + if ( exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_EXIF_ISO, &iso) < 0 + || iso < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ctrl() fail, using ISO_100", __func__); + iso = ISO_100; + } + + switch (iso) { + case ISO_50: + exifInfo->iso_speed_rating = 50; + break; + case ISO_100: + exifInfo->iso_speed_rating = 100; + break; + case ISO_200: + exifInfo->iso_speed_rating = 200; + break; + case ISO_400: + exifInfo->iso_speed_rating = 400; + break; + case ISO_800: + exifInfo->iso_speed_rating = 800; + break; + case ISO_1600: + exifInfo->iso_speed_rating = 1600; + break; + default: + exifInfo->iso_speed_rating = 100; + break; + } + + uint32_t av, tv, bv, sv, ev; + av = APEX_FNUM_TO_APERTURE((double)exifInfo->fnumber.num / exifInfo->fnumber.den); + tv = APEX_EXPOSURE_TO_SHUTTER((double)exifInfo->exposure_time.num / exifInfo->exposure_time.den); + sv = APEX_ISO_TO_FILMSENSITIVITY(exifInfo->iso_speed_rating); + bv = av + tv - sv; + ev = av + tv; + LOGD("Shutter speed=%d us, iso=%d", shutterSpeed, exifInfo->iso_speed_rating); + LOGD("AV=%d, TV=%d, SV=%d", av, tv, sv); + + //3 Shutter Speed + exifInfo->shutter_speed.num = tv * EXIF_DEF_APEX_DEN; + exifInfo->shutter_speed.den = EXIF_DEF_APEX_DEN; + //3 Brightness + exifInfo->brightness.num = bv*EXIF_DEF_APEX_DEN; + exifInfo->brightness.den = EXIF_DEF_APEX_DEN; + //3 Exposure Bias + if (m_curCameraInfo->sceneMode == SCENE_MODE_BEACH || + m_curCameraInfo->sceneMode == SCENE_MODE_SNOW) { + exifInfo->exposure_bias.num = EXIF_DEF_APEX_DEN; + exifInfo->exposure_bias.den = EXIF_DEF_APEX_DEN; + } else { + exifInfo->exposure_bias.num = 0; + exifInfo->exposure_bias.den = 0; + } + //3 Metering Mode + switch (m_curCameraInfo->metering) { + case METERING_MODE_CENTER: + exifInfo->metering_mode = EXIF_METERING_CENTER; + break; + case METERING_MODE_MATRIX: + exifInfo->metering_mode = EXIF_METERING_MULTISPOT; + break; + case METERING_MODE_SPOT: + exifInfo->metering_mode = EXIF_METERING_SPOT; + break; + case METERING_MODE_AVERAGE: + default: + exifInfo->metering_mode = EXIF_METERING_AVERAGE; + break; + } + + //3 Flash + int flash = EXIF_DEF_FLASH; + if ( m_curCameraInfo->flashMode == FLASH_MODE_OFF + || exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_EXIF_FLASH, &flash) < 0 + || flash < 0) + exifInfo->flash = EXIF_DEF_FLASH; + else + exifInfo->flash = flash; + + //3 White Balance + if (m_curCameraInfo->whiteBalance == WHITE_BALANCE_AUTO) + exifInfo->white_balance = EXIF_WB_AUTO; + else + exifInfo->white_balance = EXIF_WB_MANUAL; + + //3 Scene Capture Type + switch (m_curCameraInfo->sceneMode) { + case SCENE_MODE_PORTRAIT: + exifInfo->scene_capture_type = EXIF_SCENE_PORTRAIT; + break; + case SCENE_MODE_LANDSCAPE: + exifInfo->scene_capture_type = EXIF_SCENE_LANDSCAPE; + break; + case SCENE_MODE_NIGHT: + exifInfo->scene_capture_type = EXIF_SCENE_NIGHT; + break; + default: + exifInfo->scene_capture_type = EXIF_SCENE_STANDARD; + break; + } + + //2 0th IFD GPS Info Tags + if (m_curCameraInfo->gpsLatitude != 0 && m_curCameraInfo->gpsLongitude != 0) { + if (m_curCameraInfo->gpsLatitude > 0) + strcpy((char *)exifInfo->gps_latitude_ref, "N"); + else + strcpy((char *)exifInfo->gps_latitude_ref, "S"); + + if (m_curCameraInfo->gpsLongitude > 0) + strcpy((char *)exifInfo->gps_longitude_ref, "E"); + else + strcpy((char *)exifInfo->gps_longitude_ref, "W"); + + if (m_curCameraInfo->gpsAltitude > 0) + exifInfo->gps_altitude_ref = 0; + else + exifInfo->gps_altitude_ref = 1; + + double latitude = fabs(m_curCameraInfo->gpsLatitude / 10000.0); + double longitude = fabs(m_curCameraInfo->gpsLongitude / 10000.0); + double altitude = fabs(m_curCameraInfo->gpsAltitude / 100.0); + + exifInfo->gps_latitude[0].num = (uint32_t)latitude; + exifInfo->gps_latitude[0].den = 1; + exifInfo->gps_latitude[1].num = (uint32_t)((latitude - exifInfo->gps_latitude[0].num) * 60); + exifInfo->gps_latitude[1].den = 1; + exifInfo->gps_latitude[2].num = (uint32_t)((((latitude - exifInfo->gps_latitude[0].num) * 60) + - exifInfo->gps_latitude[1].num) * 60); + exifInfo->gps_latitude[2].den = 1; + + exifInfo->gps_longitude[0].num = (uint32_t)longitude; + exifInfo->gps_longitude[0].den = 1; + exifInfo->gps_longitude[1].num = (uint32_t)((longitude - exifInfo->gps_longitude[0].num) * 60); + exifInfo->gps_longitude[1].den = 1; + exifInfo->gps_longitude[2].num = (uint32_t)((((longitude - exifInfo->gps_longitude[0].num) * 60) + - exifInfo->gps_longitude[1].num) * 60); + exifInfo->gps_longitude[2].den = 1; + + exifInfo->gps_altitude.num = (uint32_t)altitude; + exifInfo->gps_altitude.den = 1; + + struct tm tm_data; + gmtime_r(&m_curCameraInfo->gpsTimestamp, &tm_data); + exifInfo->gps_timestamp[0].num = tm_data.tm_hour; + exifInfo->gps_timestamp[0].den = 1; + exifInfo->gps_timestamp[1].num = tm_data.tm_min; + exifInfo->gps_timestamp[1].den = 1; + exifInfo->gps_timestamp[2].num = tm_data.tm_sec; + exifInfo->gps_timestamp[2].den = 1; + snprintf((char*)exifInfo->gps_datestamp, sizeof(exifInfo->gps_datestamp), + "%04d:%02d:%02d", tm_data.tm_year + 1900, tm_data.tm_mon + 1, tm_data.tm_mday); + + exifInfo->enableGps = true; + } else { + exifInfo->enableGps = false; + } + + //2 1th IFD TIFF Tags + exifInfo->widthThumb = m_curCameraInfo->thumbnailW; + exifInfo->heightThumb = m_curCameraInfo->thumbnailH; +} + +void ExynosCamera::m_secRect2SecRect2(ExynosRect *rect, ExynosRect2 *rect2) +{ + rect2->x1 = rect->x; + rect2->y1 = rect->y; + rect2->x2 = rect->x + rect->w; + rect2->y2 = rect->y + rect->h; +} + +void ExynosCamera::m_secRect22SecRect(ExynosRect2 *rect2, ExynosRect *rect) +{ + rect->x = rect2->x1; + rect->y = rect2->y1; + rect->w = rect2->x2 - rect2->x1; + rect->h = rect2->y2 - rect2->y1; +} + +void ExynosCamera::m_printFormat(int colorFormat, const char *arg) +{ + switch (colorFormat) { + case V4L2_PIX_FMT_YUV420: + LOGV("DEBUG(%s):V4L2_PIX_FMT_YUV420", arg); + break; + case V4L2_PIX_FMT_YVU420: + LOGV("DEBUG(%s):V4L2_PIX_FMT_YVU420", arg); + break; + case V4L2_PIX_FMT_YVU420M: + LOGV("DEBUG(%s):V4L2_PIX_FMT_YVU420M", arg); + break; + case V4L2_PIX_FMT_NV12M: + LOGV("DEBUG(%s):V4L2_PIX_FMT_NV12M", arg); + break; + case V4L2_PIX_FMT_NV12: + LOGV("DEBUG(%s):V4L2_PIX_FMT_NV12", arg); + break; + case V4L2_PIX_FMT_NV12T: + LOGV("DEBUG(%s):V4L2_PIX_FMT_NV12T", arg); + break; + case V4L2_PIX_FMT_NV21: + LOGV("DEBUG(%s):V4L2_PIX_FMT_NV21", arg); + break; + case V4L2_PIX_FMT_YUV422P: + LOGV("DEBUG(%s):V4L2_PIX_FMT_YUV422PP", arg); + break; + case V4L2_PIX_FMT_YUYV: + LOGV("DEBUG(%s):V4L2_PIX_FMT_YUYV", arg); + break; + case V4L2_PIX_FMT_UYVY: + LOGV("DEBUG(%s):V4L2_PIX_FMT_UYVYI", arg); + break; + case V4L2_PIX_FMT_RGB565: + LOGV("DEBUG(%s):V4L2_PIX_FMT_RGB565", arg); + break; + default: + LOGV("DEBUG(%s):Unknown Format", arg); + break; + } +} + +/////////////////////////////////////////////////// +// Additional API. +/////////////////////////////////////////////////// + +bool ExynosCamera::setAngle(int angle) +{ + if (m_curCameraInfo->angle != angle) { + switch (angle) { + case -360: + case 0: + case 360: + m_curCameraInfo->angle = 0; + break; + + case -270: + case 90: + m_curCameraInfo->angle = 90; + break; + + case -180: + case 180: + m_curCameraInfo->angle = 180; + break; + + case -90: + case 270: + m_curCameraInfo->angle = 270; + break; + + default: + LOGE("ERR(%s):Invalid angle(%d)", __func__, angle); + return false; + } + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_ROTATION, angle) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +int ExynosCamera::getAngle(void) +{ + return m_curCameraInfo->angle; +} + +bool ExynosCamera::setISO(int iso) +{ + int internalValue = -1; + + switch (iso) { + case 50: + internalValue = ISO_50; + break; + case 100: + internalValue = ISO_100; + break; + case 200: + internalValue = ISO_200; + break; + case 400: + internalValue = ISO_400; + break; + case 800: + internalValue = ISO_800; + break; + case 1600: + internalValue = ISO_1600; + break; + case 0: + default: + internalValue = ISO_AUTO; + break; + } + + if (internalValue < ISO_AUTO || ISO_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + + if (m_curCameraInfo->iso != iso) { + m_curCameraInfo->iso = iso; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_ISO, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_ISO, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getISO(void) +{ + return m_curCameraInfo->iso; +} + +bool ExynosCamera::setContrast(int value) +{ + int internalValue = -1; + + switch (value) { + case CONTRAST_AUTO: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_AUTO; + else + LOGW("WARN(%s):Invalid contrast value (%d)", __func__, value); + return true; + break; + case CONTRAST_MINUS_2: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_MINUS_2; + else + internalValue = ::CONTRAST_MINUS_2; + break; + case CONTRAST_MINUS_1: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_MINUS_1; + else + internalValue = ::CONTRAST_MINUS_1; + break; + case CONTRAST_DEFAULT: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_DEFAULT; + else + internalValue = ::CONTRAST_DEFAULT; + break; + case CONTRAST_PLUS_1: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_PLUS_1; + else + internalValue = ::CONTRAST_PLUS_1; + break; + case CONTRAST_PLUS_2: + if (m_internalISP == true) + internalValue = ::IS_CONTRAST_PLUS_2; + else + internalValue = ::CONTRAST_PLUS_2; + break; + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (m_internalISP == true) { + if (internalValue < ::IS_CONTRAST_AUTO || ::IS_CONTRAST_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + } else { + if (internalValue < ::CONTRAST_MINUS_2 || ::CONTRAST_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->contrast != value) { + m_curCameraInfo->contrast = value; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_CONTRAST, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_CONTRAST, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getContrast(void) +{ + return m_curCameraInfo->contrast; +} + +bool ExynosCamera::setSaturation(int saturation) +{ + int internalValue = saturation + SATURATION_DEFAULT; + if (internalValue < SATURATION_MINUS_2 || SATURATION_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + + if (m_curCameraInfo->saturation != saturation) { + m_curCameraInfo->saturation = saturation; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_SATURATION, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SATURATION, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getSaturation(void) +{ + return m_curCameraInfo->saturation; +} + +bool ExynosCamera::setSharpness(int sharpness) +{ + int internalValue = sharpness + SHARPNESS_DEFAULT; + if (internalValue < SHARPNESS_MINUS_2 || SHARPNESS_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + + if (m_curCameraInfo->sharpness != sharpness) { + m_curCameraInfo->sharpness = sharpness; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_SHARPNESS, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SHARPNESS, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getSharpness(void) +{ + return m_curCameraInfo->sharpness; +} + +bool ExynosCamera::setHue(int hue) +{ + int internalValue = hue; + + if (m_internalISP == true) { + internalValue += IS_HUE_DEFAULT; + if (internalValue < IS_HUE_MINUS_2 || IS_HUE_MAX <= internalValue) { + LOGE("ERR(%s):Invalid hue (%d)", __func__, hue); + return false; + } + } else { + LOGV("WARN(%s):Not supported hue setting", __func__); + return true; + } + + if (m_curCameraInfo->hue != hue) { + m_curCameraInfo->hue = hue; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_HUE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +int ExynosCamera::getHue(void) +{ + return m_curCameraInfo->hue; +} + +bool ExynosCamera::setWDR(bool toggle) +{ + int internalWdr; + + if (toggle == true) { + if (m_internalISP == true) + internalWdr = IS_DRC_BYPASS_ENABLE; + else + internalWdr = IS_DRC_BYPASS_DISABLE; + } else { + if (m_internalISP == true) + internalWdr = WDR_ON; + else + internalWdr = WDR_OFF; + } + + if (m_curCameraInfo->wdr != toggle) { + m_curCameraInfo->wdr = toggle; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_SET_DRC, internalWdr) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_WDR, internalWdr) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +bool ExynosCamera::getWDR(void) +{ + return m_curCameraInfo->wdr; +} + +bool ExynosCamera::setAntiShake(bool toggle) +{ + int internalValue = ANTI_SHAKE_OFF; + + if (toggle == true) + internalValue = ANTI_SHAKE_STILL_ON; + + if (m_curCameraInfo->antiShake != toggle) { + m_curCameraInfo->antiShake = toggle; + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_ANTI_SHAKE, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getAntiShake(void) +{ + return m_curCameraInfo->antiShake; +} + +bool ExynosCamera::setMeteringMode(int value) +{ + int internalValue = -1; + + switch (value) { + case METERING_MODE_AVERAGE: + if (m_internalISP == true) + internalValue = IS_METERING_AVERAGE; + else + internalValue = METERING_MATRIX; + break; + case METERING_MODE_MATRIX: + if (m_internalISP == true) + internalValue = IS_METERING_MATRIX; + else + internalValue = METERING_MATRIX; + break; + case METERING_MODE_CENTER: + if (m_internalISP == true) + internalValue = IS_METERING_CENTER; + else + internalValue = METERING_CENTER; + break; + case METERING_MODE_SPOT: + if (m_internalISP == true) + internalValue = IS_METERING_SPOT; + else + internalValue = METERING_SPOT; + break; + default: + LOGE("ERR(%s):Unsupported value(%d)", __func__, value); + return false; + break; + } + + if (m_internalISP == true) { + if (internalValue < IS_METERING_AVERAGE || IS_METERING_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + } else { + if (internalValue <= METERING_BASE || METERING_MAX <= internalValue) { + LOGE("ERR(%s):Invalid internalValue (%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->metering != value) { + m_curCameraInfo->metering = value; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_METERING, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_METERING, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getMeteringMode(void) +{ + return m_curCameraInfo->metering; +} + +bool ExynosCamera::setObjectTracking(bool toggle) +{ + m_curCameraInfo->objectTracking = toggle; + return true; +} + +bool ExynosCamera::getObjectTracking(void) +{ + return m_curCameraInfo->objectTracking; +} + +bool ExynosCamera::setObjectTrackingStart(bool toggle) +{ + if (m_curCameraInfo->objectTrackingStart != toggle) { + m_curCameraInfo->objectTrackingStart = toggle; + + int startStop = (toggle == true) ? 1 : 0; + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP, startStop) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + + return true; +} + +int ExynosCamera::getObjectTrackingStatus(void) +{ + int ret = 0; + + if (exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_OBJ_TRACKING_STATUS, &ret) < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ctrl() fail", __func__); + return -1; + } + return ret; +} + +bool ExynosCamera::setObjectPosition(int x, int y) +{ + if (m_curCameraInfo->previewW == 640) + x = x - 80; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_OBJECT_POSITION_X, x) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_OBJECT_POSITION_Y, y) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::setTouchAFStart(bool toggle) +{ + if (m_curCameraInfo->touchAfStart != toggle) { + m_curCameraInfo->touchAfStart = toggle; + int startStop = (toggle == true) ? 1 : 0; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_TOUCH_AF_START_STOP, startStop) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + + return true; +} + +bool ExynosCamera::setSmartAuto(bool toggle) +{ + if (m_curCameraInfo->smartAuto != toggle) { + m_curCameraInfo->smartAuto = toggle; + + int smartAuto = (toggle == true) ? SMART_AUTO_ON : SMART_AUTO_OFF; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SMART_AUTO, smartAuto) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getSmartAuto(void) +{ + return m_curCameraInfo->smartAuto; +} + +int ExynosCamera::getSmartAutoStatus(void) +{ + int autoscene_status = -1; + + if (m_curCameraInfo->smartAuto == true) { + if (exynos_v4l2_g_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SMART_AUTO_STATUS, &autoscene_status) < 0) { + LOGE("ERR(%s):exynos_v4l2_g_ctrl() fail", __func__); + return -1; + } + + if ((autoscene_status < SMART_AUTO_STATUS_AUTO) || (autoscene_status > SMART_AUTO_STATUS_MAX)) { + LOGE("ERR(%s):Invalid getSmartAutoStatus (%d)", __func__, autoscene_status); + return -1; + } + } + return autoscene_status; +} + +bool ExynosCamera::setBeautyShot(bool toggle) +{ + if (m_curCameraInfo->beautyShot != toggle) { + m_curCameraInfo->beautyShot = toggle; + int beautyShot = (toggle == true) ? BEAUTY_SHOT_ON : BEAUTY_SHOT_OFF; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_BEAUTY_SHOT, beautyShot) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getBeautyShot(void) +{ + return m_curCameraInfo->beautyShot; +} + +bool ExynosCamera::setTopDownMirror(void) +{ + if (m_previewDev->fd <= 0) { + LOGE("ERR(%s):Camera was closed", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_VFLIP, 1) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::setLRMirror(void) +{ + if (m_previewDev->fd <= 0) { + LOGE("ERR(%s):Camera was closed", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_HFLIP, 1) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + return true; +} + +bool ExynosCamera::setBrightness(int brightness) +{ + int internalValue = brightness; + + if (m_internalISP == true) { + internalValue += IS_BRIGHTNESS_DEFAULT; + if (internalValue < IS_BRIGHTNESS_MINUS_2 || IS_BRIGHTNESS_PLUS_2 < internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } else { + internalValue += EV_DEFAULT; + if (internalValue < EV_MINUS_4 || EV_PLUS_4 < internalValue) { + LOGE("ERR(%s):Invalid internalValue(%d)", __func__, internalValue); + return false; + } + } + + if (m_curCameraInfo->brightness != brightness) { + m_curCameraInfo->brightness = brightness; + if (m_flagCreate == true) { + if (m_internalISP == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_BRIGHTNESS, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } else { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_BRIGHTNESS, internalValue) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + } + + return true; +} + +int ExynosCamera::getBrightness(void) +{ + return m_curCameraInfo->brightness; +} + +bool ExynosCamera::setGamma(bool toggle) +{ + if (m_curCameraInfo->gamma != toggle) { + m_curCameraInfo->gamma = toggle; + + int gamma = (toggle == true) ? GAMMA_ON : GAMMA_OFF; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_GAMMA, gamma) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getGamma(void) +{ + return m_curCameraInfo->gamma; +} + +bool ExynosCamera::setODC(bool toggle) +{ + if (m_previewDev->flagStart == true) { + if (m_curCameraInfo->odc != toggle) { + m_curCameraInfo->odc = toggle; + + int odc = (toggle == true) ? CAMERA_ODC_ON : CAMERA_ODC_OFF; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_ODC, odc) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getODC(void) +{ + return m_curCameraInfo->odc; +} + +bool ExynosCamera::setSlowAE(bool toggle) +{ + if (m_curCameraInfo->slowAE != toggle) { + m_curCameraInfo->slowAE = toggle; + + int slow_ae = (toggle == true) ? SLOW_AE_ON : SLOW_AE_OFF; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_SLOW_AE, slow_ae) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::getSlowAE(void) +{ + return m_curCameraInfo->slowAE; +} + +bool ExynosCamera::setShotMode(int shotMode) +{ + if (shotMode < SHOT_MODE_SINGLE || SHOT_MODE_SELF < shotMode) { + LOGE("ERR(%s):Invalid shotMode (%d)", __func__, shotMode); + return false; + } + + if (m_curCameraInfo->shotMode != shotMode) { + m_curCameraInfo->shotMode = shotMode; + + if (m_flagCreate == true) { + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_IS_CAMERA_SHOT_MODE_NORMAL, shotMode) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +int ExynosCamera::getShotMode(void) +{ + return m_curCameraInfo->shotMode; +} + +bool ExynosCamera::set3DNR(bool toggle) +{ + if (m_previewDev->flagStart == true) { + if (m_curCameraInfo->tdnr != toggle) { + m_curCameraInfo->tdnr = toggle; + + int tdnr = (toggle == true) ? CAMERA_3DNR_ON : CAMERA_3DNR_OFF; + + if (exynos_v4l2_s_ctrl(m_previewDev->fd, V4L2_CID_CAMERA_SET_3DNR, tdnr) < 0) { + LOGE("ERR(%s):exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + } + } + + return true; +} + +bool ExynosCamera::get3DNR(void) +{ + return m_curCameraInfo->tdnr; +} + +}; // namespace android diff --git a/libcamera/ExynosCameraHWInterface.cpp b/libcamera/ExynosCameraHWInterface.cpp new file mode 100644 index 0000000..5069171 --- /dev/null +++ b/libcamera/ExynosCameraHWInterface.cpp @@ -0,0 +1,4501 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** Copyright 2010, Samsung Electronics Co. LTD +** +** 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 ExynosCameraHWInterface.h + * \brief source file for Android Camera HAL + * \author thun.hwang(thun.hwang@samsung.com) + * \date 2010/06/03 + * + * <b>Revision History: </b> + * - 2011/12/31 : thun.hwang(thun.hwang@samsung.com) \n + * Initial version + * + * - 2012/02/01 : Sangwoo, Park(sw5771.park@samsung.com) \n + * Adjust Android Standard features + * + * - 2012/03/14 : sangwoo.park(sw5771.park@samsung.com) \n + * Change file, class name to ExynosXXX. + * + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ExynosCameraHWInterface" +#include <utils/Log.h> + +#include "ExynosCameraHWInterface.h" +#include "exynos_format.h" + +#define VIDEO_COMMENT_MARKER_H (0xFFBE) +#define VIDEO_COMMENT_MARKER_L (0xFFBF) +#define VIDEO_COMMENT_MARKER_LENGTH (4) +#define JPEG_EOI_MARKER (0xFFD9) +#define HIBYTE(x) (((x) >> 8) & 0xFF) +#define LOBYTE(x) ((x) & 0xFF) + +/*TODO: This values will be changed */ +#define BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" +#define FRONT_CAMERA_FOCUS_DISTANCES_STR "0.20,0.25,Infinity" + +#define BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR "0.10,0.20,Infinity" +#define BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" + +#define BACK_CAMERA_FOCUS_DISTANCE_INFINITY "Infinity" +#define FRONT_CAMERA_FOCUS_DISTANCE_INFINITY "Infinity" + +// This hack does two things: +// -- it sets preview to NV21 (YUV420SP) +// -- it sets gralloc to YV12 +// +// The reason being: the samsung encoder understands only yuv420sp, and gralloc +// does yv12 and rgb565. So what we do is we break up the interleaved UV in +// separate V and U planes, which makes preview look good, and enabled the +// encoder as well. +// +// FIXME: Samsung needs to enable support for proper yv12 coming out of the +// camera, and to fix their video encoder to work with yv12. +// FIXME: It also seems like either Samsung's YUV420SP (NV21) or img's YV12 has +// the color planes switched. We need to figure which side is doing it +// wrong and have the respective party fix it. + +namespace android { + +static const int INITIAL_SKIP_FRAME = 8; +static const int EFFECT_SKIP_FRAME = 1; + +gralloc_module_t const* ExynosCameraHWInterface::m_grallocHal; + +ExynosCameraHWInterface::ExynosCameraHWInterface(int cameraId, camera_device_t *dev) + : + m_captureInProgress(false), + m_skipFrame(0), + m_notifyCb(0), + m_dataCb(0), + m_dataCbTimestamp(0), + m_callbackCookie(0), + m_msgEnabled(0), + m_faceDetected(false), + m_halDevice(dev), + m_numOfAvailableVideoBuf(0) +{ + LOGV("DEBUG(%s):", __func__); + int ret = 0; + + m_previewWindow = NULL; + m_secCamera = ExynosCamera::createInstance(); + + for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { + m_previewHeap[i] = NULL; + m_previewBufHandle[i] = NULL; + m_previewStride[i] = 0; + m_avaliblePreviewBufHandle[i] = false; + m_flagGrallocLocked[i] = false; + m_matchedGrallocIndex[i] = -1; + m_grallocVirtAddr[i] = NULL; + } + + m_minUndequeuedBufs = 0; +#ifndef USE_3DNR_DMAOUT + m_cntVideoBuf = 0; +#endif + + m_oldPictureBufQueueHead = NULL; + m_getMemoryCb = NULL; + m_exynosPreviewCSC = NULL; + m_exynosPictureCSC = NULL; + m_exynosVideoCSC = NULL; + m_frameMetadata.number_of_faces = 0; + m_frameMetadata.faces = m_faces; + + for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { + m_videoHeap[i] = NULL; + m_resizedVideoHeap[i] = NULL; + } + + for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) + m_pictureHeap[i] = NULL; + + m_rawHeap = NULL; + + m_exitAutoFocusThread = false; + m_exitPreviewThread = false; + m_exitVideoThread = false; + /* whether the PreviewThread is active in preview or stopped. we + * create the thread but it is initially in stopped state. + */ + m_previewRunning = false; + m_videoRunning = false; + m_pictureRunning = false; +#ifndef USE_3DNR_DMAOUT + m_videoStart = false; +#endif + + m_previewStartDeferred = false; + + m_recordingHint = false; + + if (!m_grallocHal) { + ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&m_grallocHal); + if (ret) + LOGE("ERR(%s):Fail on loading gralloc HAL", __func__); + } + + if (m_secCamera->create(cameraId) == false) { + LOGE("ERR(%s):Fail on m_secCamera->create(%d)", __func__, cameraId); + return; + } + + m_initDefaultParameters(cameraId); + + CSC_METHOD cscMethod = CSC_METHOD_HW; + + m_exynosPreviewCSC = csc_init(cscMethod); + if (m_exynosPreviewCSC == NULL) + LOGE("ERR(%s):csc_init() fail", __func__); + + m_exynosPictureCSC = csc_init(cscMethod); + if (m_exynosPictureCSC == NULL) + LOGE("ERR(%s):csc_init() fail", __func__); + + m_exynosVideoCSC = csc_init(cscMethod); + if (m_exynosVideoCSC == NULL) + LOGE("ERR(%s):csc_init() fail", __func__); + + m_previewThread = new PreviewThread(this); + m_videoThread = new VideoThread(this); + m_autoFocusThread = new AutoFocusThread(this); + m_pictureThread = new PictureThread(this); +} + +ExynosCameraHWInterface::~ExynosCameraHWInterface() +{ + this->release(); +} + +status_t ExynosCameraHWInterface::setPreviewWindow(preview_stream_ops *w) +{ + m_previewWindow = w; + LOGV("DEBUG(%s):m_previewWindow %p", __func__, m_previewWindow); + + if (m_previewWindow == NULL) { + LOGV("DEBUG(%s):preview window is NULL!", __func__); + return OK; + } + + m_previewLock.lock(); + + if (m_previewRunning == true && m_previewStartDeferred == false) { + LOGV("DEBUG(%s):stop preview (window change)", __func__); + m_stopPreviewInternal(); + } + + if (m_previewWindow->get_min_undequeued_buffer_count(m_previewWindow, &m_minUndequeuedBufs) != 0) { + LOGE("ERR(%s):could not retrieve min undequeued buffer count", __func__); + return INVALID_OPERATION; + } + + if (NUM_OF_PREVIEW_BUF <= m_minUndequeuedBufs) { + LOGE("ERR(%s):min undequeued buffer count %d is too high (expecting at most %d)", __func__, + m_minUndequeuedBufs, NUM_OF_PREVIEW_BUF - 1); + } + + if (m_previewWindow->set_buffer_count(m_previewWindow, NUM_OF_PREVIEW_BUF) != 0) { + LOGE("ERR(%s):could not set buffer count", __func__); + return INVALID_OPERATION; + } + + int previewW, previewH; + int hal_pixel_format = HAL_PIXEL_FORMAT_YV12; + + m_params.getPreviewSize(&previewW, &previewH); + const char *str_preview_format = m_params.getPreviewFormat(); + LOGV("DEBUG(%s):str preview format %s width : %d height : %d ", __func__, str_preview_format, previewW, previewH); + + if (!strcmp(str_preview_format, + CameraParameters::PIXEL_FORMAT_RGB565)) { + hal_pixel_format = HAL_PIXEL_FORMAT_RGB_565; + } else if (!strcmp(str_preview_format, + CameraParameters::PIXEL_FORMAT_RGBA8888)) { + hal_pixel_format = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (!strcmp(str_preview_format, + CameraParameters::PIXEL_FORMAT_YUV420SP)) { + hal_pixel_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; + } else if (!strcmp(str_preview_format, + CameraParameters::PIXEL_FORMAT_YUV420P)) + hal_pixel_format = HAL_PIXEL_FORMAT_YV12; + + if (m_previewWindow->set_usage(m_previewWindow, + GRALLOC_USAGE_SW_WRITE_OFTEN | +#ifdef USE_EGL +#else + GRALLOC_USAGE_HWC_HWOVERLAY | +#endif + GRALLOC_USAGE_HW_ION) != 0) { + LOGE("ERR(%s):could not set usage on gralloc buffer", __func__); + return INVALID_OPERATION; + } + + if (m_previewWindow->set_buffers_geometry(m_previewWindow, + previewW, previewH, + hal_pixel_format) != 0) { + LOGE("ERR(%s):could not set buffers geometry to %s", + __func__, str_preview_format); + return INVALID_OPERATION; + } + + if (m_previewRunning == true && m_previewStartDeferred == true) { + LOGV("DEBUG(%s):start/resume preview", __func__); + if (m_startPreviewInternal() == true) { + m_previewStartDeferred = false; + m_previewCondition.signal(); + } + } + m_previewLock.unlock(); + + return OK; +} + +void ExynosCameraHWInterface::setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + m_notifyCb = notify_cb; + m_dataCb = data_cb; + m_dataCbTimestamp = data_cb_timestamp; + m_getMemoryCb = get_memory; + m_callbackCookie = user; +} + +void ExynosCameraHWInterface::enableMsgType(int32_t msgType) +{ + LOGV("DEBUG(%s):msgType = 0x%x, m_msgEnabled before = 0x%x", + __func__, msgType, m_msgEnabled); + m_msgEnabled |= msgType; + + m_previewLock.lock(); + if ( msgType & CAMERA_MSG_PREVIEW_FRAME + && m_previewRunning == true + && m_previewStartDeferred == true) { + + LOGV("DEBUG(%s):starting deferred preview", __func__); + + if (m_startPreviewInternal() == true) { + m_previewStartDeferred = false; + m_previewCondition.signal(); + } + } + m_previewLock.unlock(); + + LOGV("DEBUG(%s):m_msgEnabled = 0x%x", __func__, m_msgEnabled); +} + +void ExynosCameraHWInterface::disableMsgType(int32_t msgType) +{ + LOGV("DEBUG(%s):msgType = 0x%x, m_msgEnabled before = 0x%x", + __func__, msgType, m_msgEnabled); + m_msgEnabled &= ~msgType; + LOGV("DEBUG(%s):m_msgEnabled = 0x%x", __func__, m_msgEnabled); +} + +bool ExynosCameraHWInterface::msgTypeEnabled(int32_t msgType) +{ + return (m_msgEnabled & msgType); +} + +status_t ExynosCameraHWInterface::startPreview() +{ + int ret = OK; + + LOGV("DEBUG(%s):", __func__); + + Mutex::Autolock lock(m_stateLock); + if (m_captureInProgress == true) { + LOGE("%s : capture in progress, not allowed", __func__); + return INVALID_OPERATION; + } + + m_previewLock.lock(); + if (m_previewRunning == true) { + LOGE("%s : preview thread already running", __func__); + m_previewLock.unlock(); + return INVALID_OPERATION; + } + + m_previewRunning = true; + m_previewStartDeferred = false; + + if (m_previewWindow == NULL) { + if (!(m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME)) { + LOGV("DEBUG(%s):deferring", __func__); + m_previewStartDeferred = true; + m_previewLock.unlock(); + return NO_ERROR; + } + LOGE("%s(%d): m_previewWindow is NULL", __func__, __LINE__); + return UNKNOWN_ERROR; + } + + if (m_startPreviewInternal() == true) { + m_previewCondition.signal(); + ret = OK; + } else { + ret = UNKNOWN_ERROR; + } + + m_previewLock.unlock(); + return ret; +} + +void ExynosCameraHWInterface::stopPreview() +{ + LOGV("DEBUG(%s):", __func__); + + /* request that the preview thread stop. */ + m_previewLock.lock(); + m_stopPreviewInternal(); + m_previewLock.unlock(); +} + +bool ExynosCameraHWInterface::previewEnabled() +{ + Mutex::Autolock lock(m_previewLock); + LOGV("DEBUG(%s):%d", __func__, m_previewRunning); + return m_previewRunning; +} + +status_t ExynosCameraHWInterface::storeMetaDataInBuffers(bool enable) +{ + if (!enable) { + LOGE("Non-m_frameMetadata buffer mode is not supported!"); + return INVALID_OPERATION; + } + return OK; +} + +status_t ExynosCameraHWInterface::startRecording() +{ + LOGV("DEBUG(%s):", __func__); + + Mutex::Autolock lock(m_videoLock); + + int videoW, videoH, videoFormat, videoFramesize; + + m_secCamera->getVideoSize(&videoW, &videoH); + videoFormat = m_secCamera->getVideoFormat(); + videoFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), videoW, videoH); + + int orgVideoFrameSize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), m_orgVideoRect.w, m_orgVideoRect.h); + + for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { + +#ifdef USE_3DNR_DMAOUT + ExynosBuffer videoBuf; + + if (m_videoHeap[i] != NULL) { + m_videoHeap[i]->release(m_videoHeap[i]); + m_videoHeap[i] = 0; + } + + m_videoHeap[i] = m_getMemoryCb(-1, videoFramesize, 1, NULL); + if (!m_videoHeap[i]) { + LOGE("ERR(%s):m_getMemoryCb(m_videoHeap[%d], size(%d) fail", __func__, i, videoFramesize); + return UNKNOWN_ERROR; + } + + m_getAlignedYUVSize(videoFormat, videoW, videoH, &videoBuf); + + videoBuf.virt.extP[0] = (char *)m_videoHeap[i]->data; + for (int j = 1; j < 3; j++) { + if (videoBuf.size.extS[j] != 0) + videoBuf.virt.extP[j] = videoBuf.virt.extP[j-1] + videoBuf.size.extS[j-1]; + else + videoBuf.virt.extP[j] = NULL; + } + + videoBuf.reserved.p = i; + + m_secCamera->setVideoBuf(&videoBuf); +#endif + + // original VideoSized heap + + if (m_resizedVideoHeap[i] != NULL) { + m_resizedVideoHeap[i]->release(m_resizedVideoHeap[i]); + m_resizedVideoHeap[i] = 0; + } + + m_resizedVideoHeap[i] = m_getMemoryCb(-1, orgVideoFrameSize, 1, NULL); + if (!m_resizedVideoHeap[i]) { + LOGE("ERR(%s):m_getMemoryCb(m_resizedVideoHeap[%d], size(%d) fail", __func__, i, orgVideoFrameSize); + return UNKNOWN_ERROR; + } + } + + if (m_videoRunning == false) { + if (m_secCamera->startVideo() == false) { + LOGE("ERR(%s):Fail on m_secCamera->startVideo()", __func__); + return UNKNOWN_ERROR; + } + + m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; + +#ifdef USE_3DNR_DMAOUT + m_videoRunning = true; + + m_videoCondition.signal(); +#else + m_videoStart = true; +#endif + } + + return NO_ERROR; +} + +void ExynosCameraHWInterface::stopRecording() +{ + LOGV("DEBUG(%s):", __func__); + +#ifndef USE_3DNR_DMAOUT + m_videoStart = false; +#endif + + if (m_videoRunning == true) { + m_videoRunning = false; + + Mutex::Autolock lock(m_videoLock); + + m_videoCondition.signal(); + /* wait until video thread is stopped */ + m_videoStoppedCondition.wait(m_videoLock); + } else + LOGV("DEBUG(%s):video not running, doing nothing", __func__); +} + +bool ExynosCameraHWInterface::recordingEnabled() +{ + return m_videoStart; +} + +void ExynosCameraHWInterface::releaseRecordingFrame(const void *opaque) +{ + // This lock makes video lock up + // Mutex::Autolock lock(m_videoLock); + + int i; + bool find = false; + + // HACK : this causes recording slow + /* + for (i = 0; i < NUM_OF_VIDEO_BUF; i++) { + if ((char *)m_videoHeap[i]->data == (char *)opaque) { + find = true; + break; + } + } + + if (find == true) { + ExynosBuffer videoBuf; + videoBuf.reserved.p = i; + + m_secCamera->putVideoBuf(&videoBuf); + + m_numOfAvailableVideoBuf++; + if (NUM_OF_VIDEO_BUF <= m_numOfAvailableVideoBuf) + m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; + } else { + LOGV("DEBUG(%s):no matched index(%p)", __func__, (char *)opaque); + } + */ +} + +status_t ExynosCameraHWInterface::autoFocus() +{ + LOGV("DEBUG(%s):", __func__); + /* signal m_autoFocusThread to run once */ + m_focusCondition.signal(); + return NO_ERROR; +} + +status_t ExynosCameraHWInterface::cancelAutoFocus() +{ + if (m_secCamera->cancelAutoFocus() == false) { + LOGE("ERR(%s):Fail on m_secCamera->cancelAutoFocus()", __func__); + return UNKNOWN_ERROR; + } + + return NO_ERROR; +} + +status_t ExynosCameraHWInterface::takePicture() +{ + Mutex::Autolock lock(m_stateLock); + if (m_captureInProgress == true) { + LOGE("%s : capture already in progress", __func__); + return INVALID_OPERATION; + } + + if (m_pictureRunning == false) { + LOGI("%s(%d): m_pictureRunning is false", __func__, __LINE__); + if (m_startPictureInternal() == false) { + LOGE("%s(%d): m_startPictureInternal() fail!!!", __func__, __LINE__); + return INVALID_OPERATION; + } + } + + m_pictureLock.lock(); + m_captureInProgress = true; + m_pictureLock.unlock(); + + if (m_pictureThread->run("CameraPictureThread", PRIORITY_DEFAULT) != NO_ERROR) { + LOGE("%s : couldn't run picture thread", __func__); + return INVALID_OPERATION; + } + + return NO_ERROR; +} + +status_t ExynosCameraHWInterface::cancelPicture() +{ + LOGV("DEBUG(%s):", __func__); + + if (m_pictureThread.get()) { + LOGV("DEBUG(%s):waiting for picture thread to exit", __func__); + m_pictureThread->requestExitAndWait(); + LOGV("DEBUG(%s):picture thread has exited", __func__); + } + + return NO_ERROR; +} + +status_t ExynosCameraHWInterface::setParameters(const CameraParameters& params) +{ + LOGV("DEBUG(%s):", __func__); + + status_t ret = NO_ERROR; + + /* if someone calls us while picture thread is running, it could screw + * up the sensor quite a bit so return error. we can't wait because + * that would cause deadlock with the callbacks + */ + m_stateLock.lock(); + if (m_captureInProgress == true) { + m_stateLock.unlock(); + m_pictureLock.lock(); + m_pictureCondition.waitRelative(m_pictureLock, (2000 * 1000000)); + m_pictureLock.unlock(); + } + m_stateLock.unlock(); + + /////////////////////////////////////////////////// + // Google Official API : Camera.Parameters + // http://developer.android.com/reference/android/hardware/Camera.Parameters.html + /////////////////////////////////////////////////// + + // recording hint + const char *newRecordingHint = params.get(CameraParameters::KEY_RECORDING_HINT); + if (newRecordingHint != NULL) { + if (strcmp(newRecordingHint, "true") == 0) + m_recordingHint = true; + else + m_recordingHint = false; + + m_secCamera->setRecordingHint(m_recordingHint); + } + + // preview size + int newPreviewW = 0; + int newPreviewH = 0; + int newCalPreviewW = 0; + int newCalPreviewH = 0; + int previewMaxW = 0; + int previewMaxH = 0; + params.getPreviewSize(&newPreviewW, &newPreviewH); + + // In general, it will show preview max size + m_secCamera->getSupportedPreviewSizes(&previewMaxW, &previewMaxH); + newCalPreviewW = previewMaxW; + newCalPreviewH = previewMaxH; + + // When recording, it will show video max size + if (m_recordingHint == true) { + m_secCamera->getSupportedVideoSizes(&newCalPreviewW, &newCalPreviewH); + if ( previewMaxW < newCalPreviewW + || previewMaxH < newCalPreviewH) { + newCalPreviewW = previewMaxW; + newCalPreviewH = previewMaxH; + } + } + + m_orgPreviewRect.w = newPreviewW; + m_orgPreviewRect.h = newPreviewH; + + // TODO : calibrate original preview ratio + //m_getRatioSize(newCalPreviewW, newCalPreviewH, newPreviewW, newPreviewH, &newPreviewW, &newPreviewH); + newPreviewW = newCalPreviewW; + newPreviewH = newCalPreviewH; + + const char *strNewPreviewFormat = params.getPreviewFormat(); + LOGV("DEBUG(%s):newPreviewW x newPreviewH = %dx%d, format = %s", + __func__, newPreviewW, newPreviewH, strNewPreviewFormat); + + if (0 < newPreviewW && + 0 < newPreviewH && + strNewPreviewFormat != NULL && + m_isSupportedPreviewSize(newPreviewW, newPreviewH) == true) { + int newPreviewFormat = 0; + + if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_RGB565)) + newPreviewFormat = V4L2_PIX_FMT_RGB565; + else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_RGBA8888)) + newPreviewFormat = V4L2_PIX_FMT_RGB32; + else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) + newPreviewFormat = V4L2_PIX_FMT_NV21; + else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) + newPreviewFormat = V4L2_PIX_FMT_YVU420M; + else if (!strcmp(strNewPreviewFormat, "yuv420sp_custom")) + newPreviewFormat = V4L2_PIX_FMT_NV12T; + else if (!strcmp(strNewPreviewFormat, "yuv422i")) + newPreviewFormat = V4L2_PIX_FMT_YUYV; + else if (!strcmp(strNewPreviewFormat, "yuv422p")) + newPreviewFormat = V4L2_PIX_FMT_YUV422P; + else + newPreviewFormat = V4L2_PIX_FMT_NV21; //for 3rd party + + m_orgPreviewRect.colorFormat = newPreviewFormat; + + int curPreviewW, curPreviewH; + m_secCamera->getPreviewSize(&curPreviewW, &curPreviewH); + int curPreviewFormat = m_secCamera->getPreviewFormat(); + + if (curPreviewW != newPreviewW || + curPreviewH != newPreviewH || + curPreviewFormat != newPreviewFormat) { + if ( m_secCamera->setPreviewSize(newPreviewW, newPreviewH) == false + || m_secCamera->setPreviewFormat(newPreviewFormat) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setPreviewSize(width(%d), height(%d), format(%d))", + __func__, newPreviewW, newPreviewH, newPreviewFormat); + ret = UNKNOWN_ERROR; + } else { + if (m_previewWindow) { + if (m_previewRunning == true && m_previewStartDeferred == false) { + LOGE("ERR(%s):preview is running, cannot change size and format!", __func__); + ret = INVALID_OPERATION; + } + + LOGV("DEBUG(%s):m_previewWindow (%p) set_buffers_geometry", __func__, m_previewWindow); + LOGV("DEBUG(%s):m_previewWindow->set_buffers_geometry (%p)", __func__, + m_previewWindow->set_buffers_geometry); + m_previewWindow->set_buffers_geometry(m_previewWindow, + newPreviewW, newPreviewH, + newPreviewFormat); + LOGV("DEBUG(%s):DONE m_previewWindow (%p) set_buffers_geometry", __func__, m_previewWindow); + } + m_params.setPreviewSize(newPreviewW, newPreviewH); + m_params.setPreviewFormat(strNewPreviewFormat); + } + } + else { + LOGV("DEBUG(%s):preview size and format has not changed", __func__); + } + } else { + LOGE("ERR(%s):Invalid preview size(%dx%d)", __func__, newPreviewW, newPreviewH); + ret = INVALID_OPERATION; + } + + int newPictureW = 0; + int newPictureH = 0; + params.getPictureSize(&newPictureW, &newPictureH); + LOGV("DEBUG(%s):newPictureW x newPictureH = %dx%d", __func__, newPictureW, newPictureH); + + if (0 < newPictureW && 0 < newPictureH) { + + int orgPictureW, orgPictureH = 0; + m_secCamera->getPictureSize(&orgPictureW, &orgPictureH); + + if (m_secCamera->setPictureSize(newPictureW, newPictureH) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setPictureSize(width(%d), height(%d))", + __func__, newPictureW, newPictureH); + ret = UNKNOWN_ERROR; + } else { + int tempW, tempH = 0; + m_secCamera->getPictureSize(&tempW, &tempH); + + if (tempW != orgPictureW || tempH != orgPictureH) { + + if (m_pictureRunning == true) { + if (m_stopPictureInternal() == false) + LOGE("ERR(%s):m_stopPictureInternal() fail", __func__); + + if (m_startPictureInternal() == false) + LOGE("ERR(%s):m_startPictureInternal() fail", __func__); + } + } + m_orgPictureRect.w = newPictureW; + m_orgPictureRect.h = newPictureH; + m_params.setPictureSize(newPictureW, newPictureH); + } + } + + // picture format + const char *newPictureFormat = params.getPictureFormat(); + LOGV("DEBUG(%s):newPictureFormat %s", __func__, newPictureFormat); + + if (newPictureFormat != NULL) { + int value = 0; + + if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_RGB565)) + value = V4L2_PIX_FMT_RGB565; + else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_RGBA8888)) + value = V4L2_PIX_FMT_RGB32; + else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) + value = V4L2_PIX_FMT_NV21; + else if (!strcmp(newPictureFormat, "yuv420sp_custom")) + value = V4L2_PIX_FMT_NV12T; + else if (!strcmp(newPictureFormat, "yuv420p")) + value = V4L2_PIX_FMT_YUV420; + else if (!strcmp(newPictureFormat, "yuv422i")) + value = V4L2_PIX_FMT_YUYV; + else if (!strcmp(newPictureFormat, "uyv422i_custom")) //Zero copy UYVY format + value = V4L2_PIX_FMT_UYVY; + else if (!strcmp(newPictureFormat, "uyv422i")) //Non-zero copy UYVY format + value = V4L2_PIX_FMT_UYVY; + else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_JPEG)) + value = V4L2_PIX_FMT_YUYV; + else if (!strcmp(newPictureFormat, "yuv422p")) + value = V4L2_PIX_FMT_YUV422P; + else + value = V4L2_PIX_FMT_NV21; //for 3rd party + + if (value != m_secCamera->getPictureFormat()) { + if (m_secCamera->setPictureFormat(value) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setPictureFormat(format(%d))", __func__, value); + ret = UNKNOWN_ERROR; + } else { + m_orgPictureRect.colorFormat = value; + m_params.setPictureFormat(newPictureFormat); + } + } + } + + // JPEG image quality + int newJpegQuality = params.getInt(CameraParameters::KEY_JPEG_QUALITY); + LOGV("DEBUG(%s):newJpegQuality %d", __func__, newJpegQuality); + // we ignore bad values + if (newJpegQuality >=1 && newJpegQuality <= 100) { + if (m_secCamera->setJpegQuality(newJpegQuality) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setJpegQuality(quality(%d))", __func__, newJpegQuality); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_JPEG_QUALITY, newJpegQuality); + } + } + + // JPEG thumbnail size + int newJpegThumbnailW = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + int newJpegThumbnailH = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + if (0 <= newJpegThumbnailW && 0 <= newJpegThumbnailH) { + if (m_secCamera->setJpegThumbnailSize(newJpegThumbnailW, newJpegThumbnailH) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setJpegThumbnailSize(width(%d), height(%d))", __func__, newJpegThumbnailW, newJpegThumbnailH); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, newJpegThumbnailW); + m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, newJpegThumbnailH); + } + } + + // JPEG thumbnail quality + int newJpegThumbnailQuality = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + LOGV("DEBUG(%s):newJpegThumbnailQuality %d", __func__, newJpegThumbnailQuality); + // we ignore bad values + if (newJpegThumbnailQuality >=1 && newJpegThumbnailQuality <= 100) { + if (m_secCamera->setJpegThumbnailQuality(newJpegThumbnailQuality) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setJpegThumbnailQuality(quality(%d))", + __func__, newJpegThumbnailQuality); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, newJpegThumbnailQuality); + } + } + + // Video size + int newVideoW = 0; + int newVideoH = 0; + params.getVideoSize(&newVideoW, &newVideoH); + LOGV("DEBUG(%s):newVideoW (%d) newVideoH (%d)", __func__, newVideoW, newVideoH); + if (0 < newVideoW && 0 < newVideoH && m_videoStart == false) { + + m_orgVideoRect.w = newVideoW; + m_orgVideoRect.h = newVideoH; + + if (m_secCamera->setVideoSize(newVideoW, newVideoH) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setVideoSize(width(%d), height(%d))", + __func__, newVideoW, newVideoH); + ret = UNKNOWN_ERROR; + } + m_params.setVideoSize(newVideoW, newVideoH); + } + + // video stablization + const char *newVideoStabilization = params.get(CameraParameters::KEY_VIDEO_STABILIZATION); + bool currVideoStabilization = m_secCamera->getVideoStabilization(); + LOGV("DEBUG(%s):newVideoStabilization %s", __func__, newVideoStabilization); + if (newVideoStabilization != NULL) { + bool toggle = false; + + if (!strcmp(newVideoStabilization, "true")) + toggle = true; + + if ( currVideoStabilization != toggle) { + if (m_secCamera->setVideoStabilization(toggle) == false) { + LOGE("ERR(%s):setVideoStabilization() fail", __func__); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_VIDEO_STABILIZATION, newVideoStabilization); + } + } + } + + // 3dnr + const char *new3dnr = params.get("3dnr"); + LOGV("DEBUG(%s):new3drn %s", __func__, new3dnr); + if (new3dnr != NULL) { + bool toggle = false; + + if (!strcmp(new3dnr, "true")) + toggle = true; + + if (m_secCamera->set3DNR(toggle) == false) { + LOGE("ERR(%s):set3DNR() fail", __func__); + ret = UNKNOWN_ERROR; + } else { + m_params.set("3dnr", new3dnr); + } + } + + // odc + const char *newOdc = params.get("odc"); + LOGV("DEBUG(%s):newOdc %s", __func__, new3dnr); + if (newOdc != NULL) { + bool toggle = false; + + if (!strcmp(newOdc, "true")) + toggle = true; + + if (m_secCamera->setODC(toggle) == false) { + LOGE("ERR(%s):setODC() fail", __func__); + ret = UNKNOWN_ERROR; + } else { + m_params.set("odc", newOdc); + } + } + + // frame rate + int newFrameRate = params.getPreviewFrameRate(); + LOGV("DEBUG(%s):newFrameRate %d", __func__, newFrameRate); + // ignore any fps request, we're determine fps automatically based + // on scene mode. don't return an error because it causes CTS failure. + if (newFrameRate != m_params.getPreviewFrameRate()) { + if (m_secCamera->setPreviewFrameRate(newFrameRate) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setPreviewFrameRate(%d)", __func__, newFrameRate); + ret = UNKNOWN_ERROR; + } else { + m_params.setPreviewFrameRate(newFrameRate); + } + } + + // zoom + int newZoom = params.getInt(CameraParameters::KEY_ZOOM); + LOGV("DEBUG(%s):newZoom %d", __func__, newZoom); + if (0 <= newZoom) { + if (m_secCamera->setZoom(newZoom) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setZoom(newZoom(%d))", __func__, newZoom); + ret = UNKNOWN_ERROR; + } + else { + m_params.set(CameraParameters::KEY_ZOOM, newZoom); + } + } + + // rotation + int newRotation = params.getInt(CameraParameters::KEY_ROTATION); + LOGV("DEBUG(%s):newRotation %d", __func__, newRotation); + if (0 <= newRotation) { + LOGV("DEBUG(%s):set orientation:%d", __func__, newRotation); + if (m_secCamera->setRotation(newRotation) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setRotation(%d)", __func__, newRotation); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_ROTATION, newRotation); + } + } + + // auto exposure lock + const char *newAutoExposureLock = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK); + if (newAutoExposureLock != NULL) { + bool toggle = false; + + if (!strcmp(newAutoExposureLock, "true")) + toggle = true; + + if (m_secCamera->setAutoExposureLock(toggle) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setAutoExposureLock()", __func__); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, newAutoExposureLock); + } + } + + // exposure + int minExposureCompensation = params.getInt(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION); + int maxExposureCompensation = params.getInt(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION); + int newExposureCompensation = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + LOGV("DEBUG(%s):newExposureCompensation %d", __func__, newExposureCompensation); + if ((minExposureCompensation <= newExposureCompensation) && + (newExposureCompensation <= maxExposureCompensation)) { + if (m_secCamera->setExposureCompensation(newExposureCompensation) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setExposureCompensation(exposure(%d))", __func__, newExposureCompensation); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, newExposureCompensation); + } + } + + // auto white balance lock + const char *newAutoWhitebalanceLock = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); + if (newAutoWhitebalanceLock != NULL) { + bool toggle = false; + + if (!strcmp(newAutoWhitebalanceLock, "true")) + toggle = true; + + if (m_secCamera->setAutoWhiteBalanceLock(toggle) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setAutoWhiteBalanceLock()", __func__); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, newAutoWhitebalanceLock); + } + } + + // white balance + const char *newWhiteBalance = params.get(CameraParameters::KEY_WHITE_BALANCE); + LOGV("DEBUG(%s):newWhiteBalance %s", __func__, newWhiteBalance); + if (newWhiteBalance != NULL) { + int value = -1; + + if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_AUTO)) + value = ExynosCamera::WHITE_BALANCE_AUTO; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_INCANDESCENT)) + value = ExynosCamera::WHITE_BALANCE_INCANDESCENT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_FLUORESCENT)) + value = ExynosCamera::WHITE_BALANCE_FLUORESCENT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT)) + value = ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_DAYLIGHT)) + value = ExynosCamera::WHITE_BALANCE_DAYLIGHT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT)) + value = ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_TWILIGHT)) + value = ExynosCamera::WHITE_BALANCE_TWILIGHT; + else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_SHADE)) + value = ExynosCamera::WHITE_BALANCE_SHADE; + else { + LOGE("ERR(%s):Invalid white balance(%s)", __func__, newWhiteBalance); //twilight, shade, warm_flourescent + ret = UNKNOWN_ERROR; + } + + if (0 <= value) { + if (m_secCamera->setWhiteBalance(value) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setWhiteBalance(white(%d))", __func__, value); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_WHITE_BALANCE, newWhiteBalance); + } + } + } + + // Metering + // This is the additional API(not Google API). + // But, This is set berfore the below KEY_METERING_AREAS. + const char *strNewMetering = params.get("metering"); + LOGV("DEBUG(%s):strNewMetering %s", __func__, strNewMetering); + if (strNewMetering != NULL) { + int newMetering = -1; + + if (!strcmp(strNewMetering, "average")) + newMetering = ExynosCamera::METERING_MODE_AVERAGE; + else if (!strcmp(strNewMetering, "center")) + newMetering = ExynosCamera::METERING_MODE_CENTER; + else if (!strcmp(strNewMetering, "matrix")) + newMetering = ExynosCamera::METERING_MODE_MATRIX; + else if (!strcmp(strNewMetering, "spot")) + newMetering = ExynosCamera::METERING_MODE_SPOT; + else { + LOGE("ERR(%s):Invalid metering newMetering(%s)", __func__, strNewMetering); + ret = UNKNOWN_ERROR; + } + + if (0 <= newMetering) { + if (m_secCamera->setMeteringMode(newMetering) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setMeteringMode(%d)", __func__, newMetering); + ret = UNKNOWN_ERROR; + } else { + m_params.set("metering", strNewMetering); + } + } + } + + // metering areas + const char *newMeteringAreas = params.get(CameraParameters::KEY_METERING_AREAS); + int maxNumMeteringAreas = m_secCamera->getMaxNumMeteringAreas(); + + if (newMeteringAreas != NULL && maxNumMeteringAreas != 0) { + // ex : (-10,-10,0,0,300),(0,0,10,10,700) + ExynosRect2 *rect2s = new ExynosRect2[maxNumMeteringAreas]; + int *weights = new int[maxNumMeteringAreas]; + + int validMeteringAreas = m_bracketsStr2Ints((char *)newMeteringAreas, maxNumMeteringAreas, rect2s, weights); + if (0 < validMeteringAreas) { + for (int i = 0; i < validMeteringAreas; i++) { + rect2s[i].x1 = m_calibratePosition(2000, newPreviewW, rect2s[i].x1 + 1000); + rect2s[i].y1 = m_calibratePosition(2000, newPreviewH, rect2s[i].y1 + 1000); + rect2s[i].x2 = m_calibratePosition(2000, newPreviewW, rect2s[i].x2 + 1000); + rect2s[i].y2 = m_calibratePosition(2000, newPreviewH, rect2s[i].y2 + 1000); + } + + if (m_secCamera->setMeteringAreas(validMeteringAreas, rect2s, weights) == false) { + LOGE("ERR(%s):setMeteringAreas(%s) fail", __func__, newMeteringAreas); + ret = UNKNOWN_ERROR; + } + else { + m_params.set(CameraParameters::KEY_METERING_AREAS, newMeteringAreas); + } + } + + delete [] rect2s; + delete [] weights; + } + + // anti banding + const char *newAntibanding = params.get(CameraParameters::KEY_ANTIBANDING); + LOGV("DEBUG(%s):newAntibanding %s", __func__, newAntibanding); + if (newAntibanding != NULL) { + int value = -1; + + if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_AUTO)) + value = ExynosCamera::ANTIBANDING_AUTO; + else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_50HZ)) + value = ExynosCamera::ANTIBANDING_50HZ; + else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_60HZ)) + value = ExynosCamera::ANTIBANDING_60HZ; + else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_OFF)) + value = ExynosCamera::ANTIBANDING_OFF; + else { + LOGE("ERR(%s):Invalid antibanding value(%s)", __func__, newAntibanding); + ret = UNKNOWN_ERROR; + } + + if (0 <= value) { + if (m_secCamera->setAntibanding(value) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setAntibanding(%d)", __func__, value); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_ANTIBANDING, newAntibanding); + } + } + } + + // scene mode + const char *strNewSceneMode = params.get(CameraParameters::KEY_SCENE_MODE); + const char *strCurSceneMode = m_params.get(CameraParameters::KEY_SCENE_MODE); + + // fps range + int newMinFps = 0; + int newMaxFps = 0; + int curMinFps = 0; + int curMaxFps = 0; + params.getPreviewFpsRange(&newMinFps, &newMaxFps); + m_params.getPreviewFpsRange(&curMinFps, &curMaxFps); + /* our fps range is determined by the sensor, reject any request + * that isn't exactly what we're already at. + * but the check is performed when requesting only changing fps range + */ + if (strNewSceneMode && strCurSceneMode) { + if (!strcmp(strNewSceneMode, strCurSceneMode)) { + if ((newMinFps != curMinFps) || (newMaxFps != curMaxFps)) { + LOGW("%s : requested newMinFps = %d, newMaxFps = %d not allowed", + __func__, newMinFps, newMaxFps); + LOGE("%s : curMinFps = %d, curMaxFps = %d", + __func__, curMinFps, curMaxFps); + ret = UNKNOWN_ERROR; + } + } + } else { + /* Check basic validation if scene mode is different */ + if ((newMaxFps < newMinFps) || + (newMinFps < 0) || (newMaxFps < 0)) + ret = UNKNOWN_ERROR; + } + + if (strNewSceneMode != NULL) { + int newSceneMode = -1; + + const char *strNewFlashMode = params.get(CameraParameters::KEY_FLASH_MODE); + const char *strNewFocusMode = params.get(CameraParameters::KEY_FOCUS_MODE); + + // fps range is (15000,30000) by default. + m_params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); + m_params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "15000,30000"); + + if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_AUTO)) { + newSceneMode = ExynosCamera::SCENE_MODE_AUTO; + } else { + // defaults for non-auto scene modes + if (m_secCamera->getSupportedFocusModes() != 0) + strNewFocusMode = CameraParameters::FOCUS_MODE_AUTO; + + strNewFlashMode = CameraParameters::FLASH_MODE_OFF; + + if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_ACTION)) { + newSceneMode = ExynosCamera::SCENE_MODE_ACTION; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_PORTRAIT)) { + newSceneMode = ExynosCamera::SCENE_MODE_PORTRAIT; + strNewFlashMode = CameraParameters::FLASH_MODE_AUTO; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_LANDSCAPE)) { + newSceneMode = ExynosCamera::SCENE_MODE_LANDSCAPE; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_NIGHT)) { + newSceneMode = ExynosCamera::SCENE_MODE_NIGHT; + m_params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(4000,30000)"); + m_params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "4000,30000"); + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT)) { + newSceneMode = ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_THEATRE)) { + newSceneMode = ExynosCamera::SCENE_MODE_THEATRE; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_BEACH)) { + newSceneMode = ExynosCamera::SCENE_MODE_BEACH; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SNOW)) { + newSceneMode = ExynosCamera::SCENE_MODE_SNOW; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SUNSET)) { + newSceneMode = ExynosCamera::SCENE_MODE_SUNSET; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO)) { + newSceneMode = ExynosCamera::SCENE_MODE_STEADYPHOTO; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_FIREWORKS)) { + newSceneMode = ExynosCamera::SCENE_MODE_FIREWORKS; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SPORTS)) { + newSceneMode = ExynosCamera::SCENE_MODE_SPORTS; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_PARTY)) { + newSceneMode = ExynosCamera::SCENE_MODE_PARTY; + strNewFlashMode = CameraParameters::FLASH_MODE_AUTO; + } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT)) { + newSceneMode = ExynosCamera::SCENE_MODE_CANDLELIGHT; + } else { + LOGE("ERR(%s):unmatched scene_mode(%s)", + __func__, strNewSceneMode); //action, night-portrait, theatre, steadyphoto + ret = UNKNOWN_ERROR; + } + } + + // focus mode + if (strNewFocusMode != NULL) { + int newFocusMode = -1; + + if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_AUTO)) { + newFocusMode = ExynosCamera::FOCUS_MODE_AUTO; + m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_INFINITY)) { + newFocusMode = ExynosCamera::FOCUS_MODE_INFINITY; + m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR); + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_MACRO)) { + newFocusMode = ExynosCamera::FOCUS_MODE_MACRO; + m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR); + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_FIXED)) { + newFocusMode = ExynosCamera::FOCUS_MODE_FIXED; + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_EDOF)) { + newFocusMode = ExynosCamera::FOCUS_MODE_EDOF; + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO)) { + newFocusMode = ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO; + } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE)) { + newFocusMode = ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE; + } else { + LOGE("ERR(%s):unmatched focus_mode(%s)", __func__, strNewFocusMode); + ret = UNKNOWN_ERROR; + } + + if (0 <= newFocusMode) { + if (m_secCamera->setFocusMode(newFocusMode) == false) { + LOGE("ERR(%s):m_secCamera->setFocusMode(%d) fail", __func__, newFocusMode); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_FOCUS_MODE, strNewFocusMode); + } + } + } + + // flash mode + if (strNewFlashMode != NULL) { + int newFlashMode = -1; + + if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_OFF)) + newFlashMode = ExynosCamera::FLASH_MODE_OFF; + else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_AUTO)) + newFlashMode = ExynosCamera::FLASH_MODE_AUTO; + else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_ON)) + newFlashMode = ExynosCamera::FLASH_MODE_ON; + else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_RED_EYE)) + newFlashMode = ExynosCamera::FLASH_MODE_RED_EYE; + else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_TORCH)) + newFlashMode = ExynosCamera::FLASH_MODE_TORCH; + else { + LOGE("ERR(%s):unmatched flash_mode(%s)", __func__, strNewFlashMode); //red-eye + ret = UNKNOWN_ERROR; + } + if (0 <= newFlashMode) { + if (m_secCamera->setFlashMode(newFlashMode) == false) { + LOGE("ERR(%s):m_secCamera->setFlashMode(%d) fail", __func__, newFlashMode); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_FLASH_MODE, strNewFlashMode); + } + } + } + + // scene mode + if (0 <= newSceneMode) { + if (m_secCamera->setSceneMode(newSceneMode) == false) { + LOGE("ERR(%s):m_secCamera->setSceneMode(%d) fail", __func__, newSceneMode); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_SCENE_MODE, strNewSceneMode); + } + } + } + + // focus areas + const char *newFocusAreas = params.get(CameraParameters::KEY_FOCUS_AREAS); + int maxNumFocusAreas = m_secCamera->getMaxNumFocusAreas(); + + if (newFocusAreas != NULL && maxNumFocusAreas != 0) { + int curFocusMode = m_secCamera->getFocusMode(); + + // In CameraParameters.h + // Focus area only has effect if the cur focus mode is FOCUS_MODE_AUTO, + // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or + // FOCUS_MODE_CONTINUOUS_PICTURE. + if ( curFocusMode & ExynosCamera::FOCUS_MODE_AUTO + || curFocusMode & ExynosCamera::FOCUS_MODE_MACRO + || curFocusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO + || curFocusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) { + + // ex : (-10,-10,0,0,300),(0,0,10,10,700) + ExynosRect2 *rect2s = new ExynosRect2[maxNumFocusAreas]; + int *weights = new int[maxNumFocusAreas]; + + int validFocusedAreas = m_bracketsStr2Ints((char *)newFocusAreas, maxNumFocusAreas, rect2s, weights); + if (0 < validFocusedAreas) { + // CameraParameters.h + // A special case of single focus area (0,0,0,0,0) means driver to decide + // the focus area. For example, the driver may use more signals to decide + // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they + // want the driver to decide focus areas. + if ( validFocusedAreas == 1 + && rect2s[0].x1 == 0 && rect2s[0].y1 == 0 && rect2s[0].x2 == 0 && rect2s[0].y2 == 0) { + rect2s[0].x1 = 0; + rect2s[0].y1 = 0; + rect2s[0].x2 = newPreviewW; + rect2s[0].y2 = newPreviewH; + } else { + for (int i = 0; i < validFocusedAreas; i++) { + rect2s[i].x1 = (rect2s[i].x1 + 1000) * 1023 / 2000; + rect2s[i].y1 = (rect2s[i].y1 + 1000) * 1023 / 2000; + rect2s[i].x2 = (rect2s[i].x2 + 1000) * 1023 / 2000; + rect2s[i].y2 = (rect2s[i].y2 + 1000) * 1023 / 2000; + } + + if (m_secCamera->setFocusAreas(validFocusedAreas, rect2s, weights) == false) { + LOGE("ERR(%s):setFocusAreas(%s) fail", __func__, newFocusAreas); + ret = UNKNOWN_ERROR; + } else { + m_params.set(CameraParameters::KEY_FOCUS_AREAS, newFocusAreas); + } + } + } + + delete [] rect2s; + delete [] weights; + } + } + + // image effect + const char *strNewEffect = params.get(CameraParameters::KEY_EFFECT); + if (strNewEffect != NULL) { + + int newEffect = -1; + + if (!strcmp(strNewEffect, CameraParameters::EFFECT_NONE)) { + newEffect = ExynosCamera::EFFECT_NONE; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_MONO)) { + newEffect = ExynosCamera::EFFECT_MONO; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_NEGATIVE)) { + newEffect = ExynosCamera::EFFECT_NEGATIVE; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_SOLARIZE)) { + newEffect = ExynosCamera::EFFECT_SOLARIZE; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_SEPIA)) { + newEffect = ExynosCamera::EFFECT_SEPIA; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_POSTERIZE)) { + newEffect = ExynosCamera::EFFECT_POSTERIZE; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_WHITEBOARD)) { + newEffect = ExynosCamera::EFFECT_WHITEBOARD; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_BLACKBOARD)) { + newEffect = ExynosCamera::EFFECT_BLACKBOARD; + } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_AQUA)) { + newEffect = ExynosCamera::EFFECT_AQUA; + } else { + LOGE("ERR(%s):Invalid effect(%s)", __func__, strNewEffect); + ret = UNKNOWN_ERROR; + } + + if (0 <= newEffect) { + if (m_secCamera->setColorEffect(newEffect) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setColorEffect(effect(%d))", __func__, newEffect); + ret = UNKNOWN_ERROR; + } else { + const char *oldStrEffect = m_params.get(CameraParameters::KEY_EFFECT); + + if (oldStrEffect) { + if (strcmp(oldStrEffect, strNewEffect)) { + m_setSkipFrame(EFFECT_SKIP_FRAME); + } + } + m_params.set(CameraParameters::KEY_EFFECT, strNewEffect); + } + } + } + + // gps altitude + const char *strNewGpsAltitude = params.get(CameraParameters::KEY_GPS_ALTITUDE); + + if (m_secCamera->setGpsAltitude(strNewGpsAltitude) == false) { + LOGE("ERR(%s):m_secCamera->setGpsAltitude(%s) fail", __func__, strNewGpsAltitude); + ret = UNKNOWN_ERROR; + } else { + if (strNewGpsAltitude) + m_params.set(CameraParameters::KEY_GPS_ALTITUDE, strNewGpsAltitude); + else + m_params.remove(CameraParameters::KEY_GPS_ALTITUDE); + } + + // gps latitude + const char *strNewGpsLatitude = params.get(CameraParameters::KEY_GPS_LATITUDE); + if (m_secCamera->setGpsLatitude(strNewGpsLatitude) == false) { + LOGE("ERR(%s):m_secCamera->setGpsLatitude(%s) fail", __func__, strNewGpsLatitude); + ret = UNKNOWN_ERROR; + } else { + if (strNewGpsLatitude) + m_params.set(CameraParameters::KEY_GPS_LATITUDE, strNewGpsLatitude); + else + m_params.remove(CameraParameters::KEY_GPS_LATITUDE); + } + + // gps longitude + const char *strNewGpsLongtitude = params.get(CameraParameters::KEY_GPS_LONGITUDE); + if (m_secCamera->setGpsLongitude(strNewGpsLongtitude) == false) { + LOGE("ERR(%s):m_secCamera->setGpsLongitude(%s) fail", __func__, strNewGpsLongtitude); + ret = UNKNOWN_ERROR; + } else { + if (strNewGpsLongtitude) + m_params.set(CameraParameters::KEY_GPS_LONGITUDE, strNewGpsLongtitude); + else + m_params.remove(CameraParameters::KEY_GPS_LONGITUDE); + } + + // gps processing method + const char *strNewGpsProcessingMethod = params.get(CameraParameters::KEY_GPS_PROCESSING_METHOD); + + if (m_secCamera->setGpsProcessingMethod(strNewGpsProcessingMethod) == false) { + LOGE("ERR(%s):m_secCamera->setGpsProcessingMethod(%s) fail", __func__, strNewGpsProcessingMethod); + ret = UNKNOWN_ERROR; + } else { + if (strNewGpsProcessingMethod) + m_params.set(CameraParameters::KEY_GPS_PROCESSING_METHOD, strNewGpsProcessingMethod); + else + m_params.remove(CameraParameters::KEY_GPS_PROCESSING_METHOD); + } + + // gps timestamp + const char *strNewGpsTimestamp = params.get(CameraParameters::KEY_GPS_TIMESTAMP); + if (m_secCamera->setGpsTimeStamp(strNewGpsTimestamp) == false) { + LOGE("ERR(%s):m_secCamera->setGpsTimeStamp(%s) fail", __func__, strNewGpsTimestamp); + ret = UNKNOWN_ERROR; + } else { + if (strNewGpsTimestamp) + m_params.set(CameraParameters::KEY_GPS_TIMESTAMP, strNewGpsTimestamp); + else + m_params.remove(CameraParameters::KEY_GPS_TIMESTAMP); + } + + /////////////////////////////////////////////////// + // Additional API. + /////////////////////////////////////////////////// + // brightness + int newBrightness = params.getInt("brightness"); + int maxBrightness = params.getInt("brightness-max"); + int minBrightness = params.getInt("brightness-min"); + LOGV("DEBUG(%s):newBrightness %d", __func__, newBrightness); + if ((minBrightness <= newBrightness) && (newBrightness <= maxBrightness)) { + if (m_secCamera->setBrightness(newBrightness) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setBrightness(%d)", __func__, newBrightness); + ret = UNKNOWN_ERROR; + } else { + m_params.set("brightness", newBrightness); + } + } + + // saturation + int newSaturation = params.getInt("saturation"); + int maxSaturation = params.getInt("saturation-max"); + int minSaturation = params.getInt("saturation-min"); + LOGV("DEBUG(%s):newSaturation %d", __func__, newSaturation); + if ((minSaturation <= newSaturation) && (newSaturation <= maxSaturation)) { + if (m_secCamera->setSaturation(newSaturation) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setSaturation(%d)", __func__, newSaturation); + ret = UNKNOWN_ERROR; + } else { + m_params.set("saturation", newSaturation); + } + } + + // sharpness + int newSharpness = params.getInt("sharpness"); + int maxSharpness = params.getInt("sharpness-max"); + int minSharpness = params.getInt("sharpness-min"); + LOGV("DEBUG(%s):newSharpness %d", __func__, newSharpness); + if ((minSharpness <= newSharpness) && (newSharpness <= maxSharpness)) { + if (m_secCamera->setSharpness(newSharpness) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setSharpness(%d)", __func__, newSharpness); + ret = UNKNOWN_ERROR; + } else { + m_params.set("sharpness", newSharpness); + } + } + + // hue + int newHue = params.getInt("hue"); + int maxHue = params.getInt("hue-max"); + int minHue = params.getInt("hue-min"); + LOGV("DEBUG(%s):newHue %d", __func__, newHue); + if ((minHue <= newHue) && (maxHue >= newHue)) { + if (m_secCamera->setHue(newHue) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setHue(hue(%d))", __func__, newHue); + ret = UNKNOWN_ERROR; + } else { + m_params.set("hue", newHue); + } + } + + // ISO + const char *strNewISO = params.get("iso"); + LOGV("DEBUG(%s):strNewISO %s", __func__, strNewISO); + if (strNewISO != NULL) { + int newISO = -1; + + if (!strcmp(strNewISO, "auto")) + newISO = 0; + else { + newISO = (int)atoi(strNewISO); + if (newISO == 0) { + LOGE("ERR(%s):Invalid iso value(%s)", __func__, strNewISO); + ret = UNKNOWN_ERROR; + } + } + + if (0 <= newISO) { + if (m_secCamera->setISO(newISO) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setISO(iso(%d))", __func__, newISO); + ret = UNKNOWN_ERROR; + } else { + m_params.set("iso", strNewISO); + } + } + } + + //contrast + const char *strNewContrast = params.get("contrast"); + LOGV("DEBUG(%s):strNewContrast %s", __func__, strNewContrast); + if (strNewContrast != NULL) { + int newContrast = -1; + + if (!strcmp(strNewContrast, "auto")) + newContrast = ExynosCamera::CONTRAST_AUTO; + else if (!strcmp(strNewContrast, "-2")) + newContrast = ExynosCamera::CONTRAST_MINUS_2; + else if (!strcmp(strNewContrast, "-1")) + newContrast = ExynosCamera::CONTRAST_MINUS_1; + else if (!strcmp(strNewContrast, "0")) + newContrast = ExynosCamera::CONTRAST_DEFAULT; + else if (!strcmp(strNewContrast, "1")) + newContrast = ExynosCamera::CONTRAST_PLUS_1; + else if (!strcmp(strNewContrast, "2")) + newContrast = ExynosCamera::CONTRAST_PLUS_2; + else { + LOGE("ERR(%s):Invalid contrast value(%s)", __func__, strNewContrast); + ret = UNKNOWN_ERROR; + } + + if (0 <= newContrast) { + if (m_secCamera->setContrast(newContrast) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setContrast(contrast(%d))", __func__, newContrast); + ret = UNKNOWN_ERROR; + } else { + m_params.set("contrast", strNewContrast); + } + } + } + + //WDR + int newWdr = params.getInt("wdr"); + LOGV("DEBUG(%s):newWdr %d", __func__, newWdr); + if (0 <= newWdr) { + if (m_secCamera->setWDR(newWdr) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setWDR(%d)", __func__, newWdr); + ret = UNKNOWN_ERROR; + } + } + + //anti shake + int newAntiShake = m_internalParams.getInt("anti-shake"); + LOGV("DEBUG(%s):newAntiShake %d", __func__, newAntiShake); + if (0 <= newAntiShake) { + bool toggle = false; + if (newAntiShake == 1) + toggle = true; + + if (m_secCamera->setAntiShake(toggle) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setAntiShake(%d)", __func__, newAntiShake); + ret = UNKNOWN_ERROR; + } + } + + //gamma + const char *strNewGamma = m_internalParams.get("video_recording_gamma"); + LOGV("DEBUG(%s):strNewGamma %s", __func__, strNewGamma); + if (strNewGamma != NULL) { + int newGamma = -1; + if (!strcmp(strNewGamma, "off")) + newGamma = 0; + else if (!strcmp(strNewGamma, "on")) + newGamma = 1; + else { + LOGE("ERR(%s):unmatched gamma(%s)", __func__, strNewGamma); + ret = UNKNOWN_ERROR; + } + + if (0 <= newGamma) { + bool toggle = false; + if (newGamma == 1) + toggle = true; + + if (m_secCamera->setGamma(toggle) == false) { + LOGE("ERR(%s):m_secCamera->setGamma(%s) fail", __func__, strNewGamma); + ret = UNKNOWN_ERROR; + } + } + } + + //slow ae + const char *strNewSlowAe = m_internalParams.get("slow_ae"); + LOGV("DEBUG(%s):strNewSlowAe %s", __func__, strNewSlowAe); + if (strNewSlowAe != NULL) { + int newSlowAe = -1; + + if (!strcmp(strNewSlowAe, "off")) + newSlowAe = 0; + else if (!strcmp(strNewSlowAe, "on")) + newSlowAe = 1; + else { + LOGE("ERR(%s):unmatched slow_ae(%s)", __func__, strNewSlowAe); + ret = UNKNOWN_ERROR; + } + + if (0 <= newSlowAe) { + bool toggle = false; + if (newSlowAe == 1) + toggle = true; + if (m_secCamera->setSlowAE(newSlowAe) == false) { + LOGE("ERR(%s):m_secCamera->setSlowAE(%d) fail", __func__, newSlowAe); + ret = UNKNOWN_ERROR; + } + } + } + + // Shot mode + int newShotMode = m_internalParams.getInt("shot_mode"); + LOGV("DEBUG(%s):newShotMode %d", __func__, newShotMode); + if (0 <= newShotMode) { + if (m_secCamera->setShotMode(newShotMode) == false) { + LOGE("ERR(%s):Fail on m_secCamera->setShotMode(%d)", __func__, newShotMode); + ret = UNKNOWN_ERROR; + } + } else { + newShotMode=0; + } + + LOGV("DEBUG(%s):return ret = %d", __func__, ret); + + return ret; +} + +CameraParameters ExynosCameraHWInterface::getParameters() const +{ + LOGV("DEBUG(%s):", __func__); + return m_params; +} + +status_t ExynosCameraHWInterface::sendCommand(int32_t command, int32_t arg1, int32_t arg2) +{ + switch (command) { + case CAMERA_CMD_START_FACE_DETECTION: + case CAMERA_CMD_STOP_FACE_DETECTION: + if (m_secCamera->getMaxNumDetectedFaces() == 0) { + LOGE("ERR(%s):getMaxNumDetectedFaces == 0", __func__); + return BAD_VALUE; + } + + if (arg1 == CAMERA_FACE_DETECTION_SW) { + LOGE("ERR(%s):only support HW face dectection", __func__); + return BAD_VALUE; + } + + if (command == CAMERA_CMD_START_FACE_DETECTION) { + if ( m_secCamera->flagStartFaceDetection() == false + && m_secCamera->startFaceDetection() == false) { + LOGE("ERR(%s):startFaceDetection() fail", __func__); + return BAD_VALUE; + } + } else { // if (command == CAMERA_CMD_STOP_FACE_DETECTION) + if ( m_secCamera->flagStartFaceDetection() == true + && m_secCamera->stopFaceDetection() == false) { + LOGE("ERR(%s):stopFaceDetection() fail", __func__); + return BAD_VALUE; + } + } + break; + default: + LOGE("ERR(%s):unexpectect command(%d) fail", __func__, command); + return BAD_VALUE; + break; + } + return NO_ERROR; +} + +void ExynosCameraHWInterface::release() +{ + LOGV("DEBUG(%s):", __func__); + + /* shut down any threads we have that might be running. do it here + * instead of the destructor. we're guaranteed to be on another thread + * than the ones below. if we used the destructor, since the threads + * have a reference to this object, we could wind up trying to wait + * for ourself to exit, which is a deadlock. + */ + if (m_videoThread != NULL) { + m_videoThread->requestExit(); + m_exitVideoThread = true; + m_videoRunning = true; // let it run so it can exit + m_videoCondition.signal(); + m_videoThread->requestExitAndWait(); + m_videoThread.clear(); + } + + if (m_previewThread != NULL) { + /* this thread is normally already in it's threadLoop but blocked + * on the condition variable or running. signal it so it wakes + * up and can exit. + */ + m_previewThread->requestExit(); + m_exitPreviewThread = true; + m_previewRunning = true; // let it run so it can exit + m_previewCondition.signal(); + m_previewThread->requestExitAndWait(); + m_previewThread.clear(); + } + + if (m_autoFocusThread != NULL) { + /* this thread is normally already in it's threadLoop but blocked + * on the condition variable. signal it so it wakes up and can exit. + */ + m_focusLock.lock(); + m_autoFocusThread->requestExit(); + m_exitAutoFocusThread = true; + m_focusCondition.signal(); + m_focusLock.unlock(); + m_autoFocusThread->requestExitAndWait(); + m_autoFocusThread.clear(); + } + + if (m_pictureThread != NULL) { + m_pictureThread->requestExitAndWait(); + m_pictureThread.clear(); + } + + for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { + if (m_videoHeap[i]) { + m_videoHeap[i]->release(m_videoHeap[i]); + m_videoHeap[i] = 0; + } + + if (m_resizedVideoHeap[i]) { + m_resizedVideoHeap[i]->release(m_resizedVideoHeap[i]); + m_resizedVideoHeap[i] = 0; + } + } + + for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { + if (m_previewHeap[i]) { + m_previewHeap[i]->release(m_previewHeap[i]); + m_previewHeap[i] = 0; + } + } + + if (m_pictureRunning == true) { + if (m_stopPictureInternal() == false) + LOGE("ERR(%s):m_stopPictureInternal() fail", __func__); + } + + if (m_exynosVideoCSC) + csc_deinit(m_exynosVideoCSC); + m_exynosVideoCSC = NULL; + + if (m_exynosPictureCSC) + csc_deinit(m_exynosPictureCSC); + m_exynosPictureCSC = NULL; + + if (m_exynosPreviewCSC) + csc_deinit(m_exynosPreviewCSC); + m_exynosPreviewCSC = NULL; + + /* close after all the heaps are cleared since those + * could have dup'd our file descriptor. + */ + if (m_secCamera->flagCreate() == true) + m_secCamera->destroy(); +} + +status_t ExynosCameraHWInterface::dump(int fd) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + const Vector<String16> args; + + if (m_secCamera != 0) { + m_params.dump(fd, args); + m_internalParams.dump(fd, args); + snprintf(buffer, 255, " preview running(%s)\n", m_previewRunning?"true": "false"); + result.append(buffer); + } else { + result.append("No camera client yet.\n"); + } + + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +int ExynosCameraHWInterface::getCameraId() const +{ + return m_secCamera->getCameraId(); +} + +void ExynosCameraHWInterface::m_initDefaultParameters(int cameraId) +{ + if (m_secCamera == NULL) { + LOGE("ERR(%s):m_secCamera object is NULL", __func__); + return; + } + + CameraParameters p; + CameraParameters ip; + + String8 parameterString; + + char * cameraName; + cameraName = m_secCamera->getCameraName(); + if (cameraName == NULL) + LOGE("ERR(%s):getCameraName() fail", __func__); + + /* + if (cameraId == ExynosCamera::CAMERA_ID_BACK) { + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + "3264x2448,2576x1948,1920x1080,1280x720,800x480,720x480,640x480,320x240,528x432,176x144"); + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + "3264x2448,1920x1080,1280x720,800x480,720x480,640x480"); + p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, + "1920x1080,1280x720,640x480,176x144"); + } else { + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + "1392x1392,1280x720,640x480,352x288,320x240,176x144"); + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, + "1392x1392,1280x960,640x480"); + p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, + "1280x720,640x480,176x144"); + } + */ + + char strBuf[256]; + String8 listString; + + // preview + int previewMaxW = 0; + int previewMaxH = 0; + m_secCamera->getSupportedPreviewSizes(&previewMaxW, &previewMaxH); + + listString.setTo(""); + if (m_getResolutionList(listString, strBuf, previewMaxW, previewMaxH) == false) { + LOGE("ERR(%s):m_getResolutionList() fail", __func__); + + previewMaxW = 640; + previewMaxH = 480; + listString = String8::format("%dx%d", previewMaxW, previewMaxH); + } + + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, listString.string()); + p.setPreviewSize(previewMaxW, previewMaxH); + p.getSupportedPreviewSizes(m_supportedPreviewSizes); + + listString.setTo(""); + listString = String8::format("%s,%s", CameraParameters::PIXEL_FORMAT_YUV420SP, CameraParameters::PIXEL_FORMAT_YUV420P); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, listString); + p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420P); + + // video + int videoMaxW = 0; + int videoMaxH = 0; + m_secCamera->getSupportedVideoSizes(&videoMaxW, &videoMaxH); + + listString.setTo(""); + if (m_getResolutionList(listString, strBuf, videoMaxW, videoMaxH) == false) { + LOGE("ERR(%s):m_getResolutionList() fail", __func__); + + videoMaxW = 640; + videoMaxH = 480; + listString = String8::format("%dx%d", videoMaxW, videoMaxH); + } + p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, listString.string()); + p.setVideoSize(videoMaxW, videoMaxH); + + int preferredPreviewW = 0; + int preferredPreviewH = 0; + m_secCamera->getPreferredPreivewSizeForVideo(&preferredPreviewW, &preferredPreviewH); + listString.setTo(""); + listString = String8::format("%dx%d", preferredPreviewW, preferredPreviewH); + p.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO, listString.string()); + p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420SP); + + if (m_secCamera->isVideoSnapshotSupported() == true) + p.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, "true"); + else + p.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, "false"); + + if (m_secCamera->isVideoStabilizationSupported() == true) + p.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED, "true"); + else + p.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED, "false"); + + // picture + int pictureMaxW = 0; + int pictureMaxH = 0; + m_secCamera->getSupportedPictureSizes(&pictureMaxW, &pictureMaxH); + + listString.setTo(""); + if (m_getResolutionList(listString, strBuf, pictureMaxW, pictureMaxH) == false) { + LOGE("ERR(%s):m_getResolutionList() fail", __func__); + + pictureMaxW = 640; + pictureMaxW = 480; + listString = String8::format("%dx%d", pictureMaxW, pictureMaxH); + } + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, listString.string()); + p.setPictureSize(pictureMaxW, pictureMaxH); + + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, + CameraParameters::PIXEL_FORMAT_JPEG); + + p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG); + + p.set(CameraParameters::KEY_JPEG_QUALITY, "100"); // maximum quality + + // thumbnail + int thumbnailMaxW = 0; + int thumbnailMaxH = 0; + + m_secCamera->getSupportedJpegThumbnailSizes(&thumbnailMaxW, &thumbnailMaxH); + listString = String8::format("%dx%d", thumbnailMaxW, thumbnailMaxH); + listString.append(",0x0"); + p.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, listString.string()); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, thumbnailMaxW); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, thumbnailMaxH); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "100"); + + // exposure + p.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, m_secCamera->getMinExposureCompensation()); + p.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, m_secCamera->getMaxExposureCompensation()); + p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, m_secCamera->getExposureCompensation()); + p.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, m_secCamera->getExposureCompensationStep()); + + if (m_secCamera->isAutoExposureLockSupported() == true) + p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, "true"); + else + p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, "false"); + + // face detection + p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, m_secCamera->getMaxNumDetectedFaces()); + p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, 0); + + // focus mode + int focusMode = m_secCamera->getSupportedFocusModes(); + parameterString.setTo(""); + if (focusMode & ExynosCamera::FOCUS_MODE_AUTO) { + parameterString.append(CameraParameters::FOCUS_MODE_AUTO); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_INFINITY) { + parameterString.append(CameraParameters::FOCUS_MODE_INFINITY); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_MACRO) { + parameterString.append(CameraParameters::FOCUS_MODE_MACRO); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_FIXED) { + parameterString.append(CameraParameters::FOCUS_MODE_FIXED); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_EDOF) { + parameterString.append(CameraParameters::FOCUS_MODE_EDOF); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO) { + parameterString.append(CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO); + parameterString.append(","); + } + if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) + parameterString.append(CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE); + + p.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, + parameterString.string()); + + if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE); + else if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO) + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO); + else if (focusMode & ExynosCamera::FOCUS_MODE_AUTO) + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_AUTO); + else + p.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_FIXED); + + // HACK + if (cameraId == ExynosCamera::CAMERA_ID_BACK) { + p.set(CameraParameters::KEY_FOCUS_DISTANCES, + BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); + p.set(CameraParameters::FOCUS_DISTANCE_INFINITY, + BACK_CAMERA_FOCUS_DISTANCE_INFINITY); + } else { + p.set(CameraParameters::KEY_FOCUS_DISTANCES, + FRONT_CAMERA_FOCUS_DISTANCES_STR); + p.set(CameraParameters::FOCUS_DISTANCE_INFINITY, + FRONT_CAMERA_FOCUS_DISTANCE_INFINITY); + } + + if (focusMode & ExynosCamera::FOCUS_MODE_TOUCH) + p.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, m_secCamera->getMaxNumFocusAreas()); + + // flash + int flashMode = m_secCamera->getSupportedFlashModes(); + parameterString.setTo(""); + if (flashMode & ExynosCamera::FLASH_MODE_OFF) { + parameterString.append(CameraParameters::FLASH_MODE_OFF); + parameterString.append(","); + } + if (flashMode & ExynosCamera::FLASH_MODE_AUTO) { + parameterString.append(CameraParameters::FLASH_MODE_AUTO); + parameterString.append(","); + } + if (flashMode & ExynosCamera::FLASH_MODE_ON) { + parameterString.append(CameraParameters::FLASH_MODE_ON); + parameterString.append(","); + } + if (flashMode & ExynosCamera::FLASH_MODE_RED_EYE) { + parameterString.append(CameraParameters::FLASH_MODE_RED_EYE); + parameterString.append(","); + } + if (flashMode & ExynosCamera::FLASH_MODE_TORCH) + parameterString.append(CameraParameters::FLASH_MODE_TORCH); + + p.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, parameterString.string()); + p.set(CameraParameters::KEY_FLASH_MODE, CameraParameters::FLASH_MODE_OFF); + + // scene mode + int sceneMode = m_secCamera->getSupportedSceneModes(); + parameterString.setTo(""); + if (sceneMode & ExynosCamera::SCENE_MODE_AUTO) { + parameterString.append(CameraParameters::SCENE_MODE_AUTO); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_ACTION) { + parameterString.append(CameraParameters::SCENE_MODE_ACTION); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_PORTRAIT) { + parameterString.append(CameraParameters::SCENE_MODE_PORTRAIT); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_LANDSCAPE) { + parameterString.append(CameraParameters::SCENE_MODE_LANDSCAPE); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_NIGHT) { + parameterString.append(CameraParameters::SCENE_MODE_NIGHT); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT) { + parameterString.append(CameraParameters::SCENE_MODE_NIGHT_PORTRAIT); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_THEATRE) { + parameterString.append(CameraParameters::SCENE_MODE_THEATRE); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_BEACH) { + parameterString.append(CameraParameters::SCENE_MODE_BEACH); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_SNOW) { + parameterString.append(CameraParameters::SCENE_MODE_SNOW); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_SUNSET) { + parameterString.append(CameraParameters::SCENE_MODE_SUNSET); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_STEADYPHOTO) { + parameterString.append(CameraParameters::SCENE_MODE_STEADYPHOTO); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_FIREWORKS) { + parameterString.append(CameraParameters::SCENE_MODE_FIREWORKS); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_SPORTS) { + parameterString.append(CameraParameters::SCENE_MODE_SPORTS); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_PARTY) { + parameterString.append(CameraParameters::SCENE_MODE_PARTY); + parameterString.append(","); + } + if (sceneMode & ExynosCamera::SCENE_MODE_CANDLELIGHT) + parameterString.append(CameraParameters::SCENE_MODE_CANDLELIGHT); + + p.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, + parameterString.string()); + p.set(CameraParameters::KEY_SCENE_MODE, + CameraParameters::SCENE_MODE_AUTO); + + // effect + int effect = m_secCamera->getSupportedColorEffects(); + parameterString.setTo(""); + if (effect & ExynosCamera::EFFECT_NONE) { + parameterString.append(CameraParameters::EFFECT_NONE); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_MONO) { + parameterString.append(CameraParameters::EFFECT_MONO); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_NEGATIVE) { + parameterString.append(CameraParameters::EFFECT_NEGATIVE); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_SOLARIZE) { + parameterString.append(CameraParameters::EFFECT_SOLARIZE); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_SEPIA) { + parameterString.append(CameraParameters::EFFECT_SEPIA); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_POSTERIZE) { + parameterString.append(CameraParameters::EFFECT_POSTERIZE); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_WHITEBOARD) { + parameterString.append(CameraParameters::EFFECT_WHITEBOARD); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_BLACKBOARD) { + parameterString.append(CameraParameters::EFFECT_BLACKBOARD); + parameterString.append(","); + } + if (effect & ExynosCamera::EFFECT_AQUA) + parameterString.append(CameraParameters::EFFECT_AQUA); + + p.set(CameraParameters::KEY_SUPPORTED_EFFECTS, parameterString.string()); + p.set(CameraParameters::KEY_EFFECT, CameraParameters::EFFECT_NONE); + + // white balance + int whiteBalance = m_secCamera->getSupportedWhiteBalance(); + parameterString.setTo(""); + if (whiteBalance & ExynosCamera::WHITE_BALANCE_AUTO) { + parameterString.append(CameraParameters::WHITE_BALANCE_AUTO); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_INCANDESCENT) { + parameterString.append(CameraParameters::WHITE_BALANCE_INCANDESCENT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_FLUORESCENT) { + parameterString.append(CameraParameters::WHITE_BALANCE_FLUORESCENT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT) { + parameterString.append(CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_DAYLIGHT) { + parameterString.append(CameraParameters::WHITE_BALANCE_DAYLIGHT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT) { + parameterString.append(CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_TWILIGHT) { + parameterString.append(CameraParameters::WHITE_BALANCE_TWILIGHT); + parameterString.append(","); + } + if (whiteBalance & ExynosCamera::WHITE_BALANCE_SHADE) + parameterString.append(CameraParameters::WHITE_BALANCE_SHADE); + + p.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, + parameterString.string()); + p.set(CameraParameters::KEY_WHITE_BALANCE, CameraParameters::WHITE_BALANCE_AUTO); + + if (m_secCamera->isAutoWhiteBalanceLockSupported() == true) + p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, "true"); + else + p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, "false"); + + // anti banding + int antiBanding = m_secCamera->getSupportedAntibanding(); + parameterString.setTo(""); + if (antiBanding & ExynosCamera::ANTIBANDING_AUTO) { + parameterString.append(CameraParameters::ANTIBANDING_AUTO); + parameterString.append(","); + } + if (antiBanding & ExynosCamera::ANTIBANDING_50HZ) { + parameterString.append(CameraParameters::ANTIBANDING_50HZ); + parameterString.append(","); + } + if (antiBanding & ExynosCamera::ANTIBANDING_60HZ) { + parameterString.append(CameraParameters::ANTIBANDING_60HZ); + parameterString.append(","); + } + if (antiBanding & ExynosCamera::ANTIBANDING_OFF) + parameterString.append(CameraParameters::ANTIBANDING_OFF); + + p.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING, + parameterString.string()); + + p.set(CameraParameters::KEY_ANTIBANDING, CameraParameters::ANTIBANDING_OFF); + + // rotation + p.set(CameraParameters::KEY_ROTATION, 0); + + // view angle + p.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, m_secCamera->getHorizontalViewAngle()); + p.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, m_secCamera->getVerticalViewAngle()); + + // metering + if (0 < m_secCamera->getMaxNumMeteringAreas()) + p.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS, m_secCamera->getMaxNumMeteringAreas()); + + // zoom + if (m_secCamera->isZoomSupported() == true) { + + int maxZoom = m_secCamera->getMaxZoom(); + if (0 < maxZoom) { + + p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "true"); + + if (m_secCamera->isSmoothZoomSupported() == true) + p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "true"); + else + p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); + + p.set(CameraParameters::KEY_MAX_ZOOM, maxZoom); + p.set(CameraParameters::KEY_ZOOM, m_secCamera->getZoom()); + + int max_zoom_ratio = m_secCamera->getMaxZoomRatio(); + + listString.setTo(""); + + if (m_getZoomRatioList(listString, strBuf, maxZoom, 100, max_zoom_ratio) == true) + p.set(CameraParameters::KEY_ZOOM_RATIOS, listString.string()); + else + p.set(CameraParameters::KEY_ZOOM_RATIOS, "100"); + } else { + p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "false"); + p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); + } + + } else { + p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "false"); + p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); + } + + // fps + int minPreviewFps, maxPreviewFps; + m_secCamera->getPreviewFpsRange(&minPreviewFps, &maxPreviewFps); + + int baseFps = ((minPreviewFps + 5) / 5) * 5; + + listString.setTo(""); + snprintf(strBuf, 256, "%d", minPreviewFps); + listString.append(strBuf); + + for (int i = baseFps; i <= maxPreviewFps; i += 5) { + int step = (i / 5) * 5; + snprintf(strBuf, 256, ",%d", step); + listString.append(strBuf); + } + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, listString.string()); + p.setPreviewFrameRate(maxPreviewFps); + + int minFpsRange = minPreviewFps * 1000; // 15 -> 15000 + int maxFpsRange = maxPreviewFps * 1000; // 30 -> 30000 + + snprintf(strBuf, 256, "(%d,%d)", minFpsRange, maxFpsRange); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, strBuf); + + snprintf(strBuf, 256, "%d,%d", minFpsRange, maxFpsRange); + p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, strBuf); + //p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); + //p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "15000,30000") + + // focal length + int num = 0; + int den = 0; + int precision = 0; + m_secCamera->getFocalLength(&num, &den); + + switch (den) { + default: + case 1000: + precision = 3; + break; + case 100: + precision = 2; + break; + case 10: + precision = 1; + break; + case 1: + precision = 0; + break; + } + + snprintf(strBuf, 256, "%.*f", precision, ((float)num / (float)den)); + p.set(CameraParameters::KEY_FOCAL_LENGTH, strBuf); + //p.set(CameraParameters::KEY_FOCAL_LENGTH, "3.43"); + //p.set(CameraParameters::KEY_FOCAL_LENGTH, "0.9"); + + // Additional params. + + p.set("contrast", "auto"); + p.set("iso", "auto"); + p.set("wdr", 0); + p.set("metering", "center"); + + p.set("brightness", 0); + p.set("brightness-max", 2); + p.set("brightness-min", -2); + + p.set("saturation", 0); + p.set("saturation-max", 2); + p.set("saturation-min", -2); + + p.set("sharpness", 0); + p.set("sharpness-max", 2); + p.set("sharpness-min", -2); + + p.set("hue", 0); + p.set("hue-max", 2); + p.set("hue-min", -2); + + m_params = p; + m_internalParams = ip; + + /* make sure m_secCamera has all the settings we do. applications + * aren't required to call setParameters themselves (only if they + * want to change something. + */ + setParameters(p); + + m_secCamera->setPreviewFrameRate(maxPreviewFps); +} + +bool ExynosCameraHWInterface::m_startPreviewInternal(void) +{ + LOGV("DEBUG(%s):", __func__); + + int i; + int previewW, previewH, previewFormat, previewFramesize; + + m_secCamera->getPreviewSize(&previewW, &previewH); + previewFormat = m_secCamera->getPreviewFormat(); + + // we will use previewFramesize for m_previewHeap[i] + previewFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(m_orgPreviewRect.colorFormat), m_orgPreviewRect.w, m_orgPreviewRect.h); + + ExynosBuffer previewBuf; + void *virtAddr[3]; + + for (i = 0; i < 3; i++) + virtAddr[i] = NULL; + + for (i = 0; i < NUM_OF_PREVIEW_BUF; i++) { + + m_avaliblePreviewBufHandle[i] = false; + + if (m_previewWindow->dequeue_buffer(m_previewWindow, &m_previewBufHandle[i], &m_previewStride[i]) != 0) { + LOGE("ERR(%s):Could not dequeue gralloc buffer[%d]!!", __func__, i); + continue; + } else { + if (m_previewWindow->lock_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) + LOGE("ERR(%s):Could not lock gralloc buffer[%d]!!", __func__, i); + } + + if (m_flagGrallocLocked[i] == false) { + if (m_grallocHal->lock(m_grallocHal, + *m_previewBufHandle[i], + GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_YUV_ADDR, + 0, 0, previewW, previewH, virtAddr) != 0) { + LOGE("ERR(%s):could not obtain gralloc buffer", __func__); + + if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) + LOGE("ERR(%s):Could not cancel_buffer gralloc buffer[%d]!!", __func__, i); + + continue; + } + + m_grallocVirtAddr[i] = virtAddr[0]; + m_matchedGrallocIndex[i] = i; + m_flagGrallocLocked[i] = true; + } + + m_getAlignedYUVSize(previewFormat, previewW, previewH, &previewBuf); + + previewBuf.reserved.p = i; + previewBuf.virt.extP[0] = (char *)virtAddr[0]; + previewBuf.virt.extP[1] = (char *)virtAddr[1]; + previewBuf.virt.extP[2] = (char *)virtAddr[2]; + + m_secCamera->setPreviewBuf(&previewBuf); + + if (m_previewHeap[i]) { + m_previewHeap[i]->release(m_previewHeap[i]); + m_previewHeap[i] = 0; + } + + m_previewHeap[i] = m_getMemoryCb(-1, previewFramesize, 1, 0); + if (!m_previewHeap[i]) { + LOGE("ERR(%s):m_getMemoryCb(m_previewHeap[%d], size(%d) fail", __func__, i, previewFramesize); + continue; + } + + m_avaliblePreviewBufHandle[i] = true; + } + + if (m_secCamera->startPreview() == false) { + LOGE("ERR(%s):Fail on m_secCamera->startPreview()", __func__); + return false; + } + + for (i = NUM_OF_PREVIEW_BUF - m_minUndequeuedBufs; i < NUM_OF_PREVIEW_BUF; i++) { + if (m_secCamera->getPreviewBuf(&previewBuf) == false) { + LOGE("ERR(%s):getPreviewBuf() fail", __func__); + return false; + } + + if (m_grallocHal && m_flagGrallocLocked[previewBuf.reserved.p] == true) { + m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[previewBuf.reserved.p]); + m_flagGrallocLocked[previewBuf.reserved.p] = false; + } + + if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[previewBuf.reserved.p]) != 0) + LOGE("ERR(%s):Could not cancel_buffer gralloc buffer[%d]!!", __func__, previewBuf.reserved.p); + + m_avaliblePreviewBufHandle[previewBuf.reserved.p] = false; + } + + m_setSkipFrame(INITIAL_SKIP_FRAME); + + if (m_pictureRunning == false + && m_startPictureInternal() == false) + LOGE("ERR(%s):m_startPictureInternal() fail", __func__); + + return true; +} + +void ExynosCameraHWInterface::m_stopPreviewInternal(void) +{ + LOGV("DEBUG(%s):", __func__); + + /* request that the preview thread stop. */ + if (m_previewRunning == true) { + m_previewRunning = false; + + if (m_previewStartDeferred == false) { + m_previewCondition.signal(); + /* wait until preview thread is stopped */ + m_previewStoppedCondition.wait(m_previewLock); + + for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { + if (m_previewBufHandle[i] != NULL) { + if (m_grallocHal && m_flagGrallocLocked[i] == true) { + m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[i]); + m_flagGrallocLocked[i] = false; + } + + if (m_avaliblePreviewBufHandle[i] == true) { + if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) { + LOGE("ERR(%s):Fail to cancel buffer(%d)", __func__, i); + } else { + m_previewBufHandle[i] = NULL; + m_previewStride[i] = NULL; + } + + m_avaliblePreviewBufHandle[i] = false; + } + } + } + } else { + LOGV("DEBUG(%s):preview running but deferred, doing nothing", __func__); + } + } else { + LOGV("DEBUG(%s):preview not running, doing nothing", __func__); + } +} + +bool ExynosCameraHWInterface::m_previewThreadFuncWrapper(void) +{ + LOGV("DEBUG(%s):starting", __func__); + while (1) { + m_previewLock.lock(); + while (m_previewRunning == false) { + if ( m_secCamera->flagStartPreview() == true + && m_secCamera->stopPreview() == false) + LOGE("ERR(%s):Fail on m_secCamera->stopPreview()", __func__); + + LOGV("DEBUG(%s):calling m_secCamera->stopPreview() and waiting", __func__); + + m_previewStoppedCondition.signal(); + m_previewCondition.wait(m_previewLock); + LOGV("DEBUG(%s):return from wait", __func__); + } + m_previewLock.unlock(); + + if (m_exitPreviewThread == true) { + if ( m_secCamera->flagStartPreview() == true + && m_secCamera->stopPreview() == false) + LOGE("ERR(%s):Fail on m_secCamera->stopPreview()", __func__); + + return true; + } + m_previewThreadFunc(); + } +} + +bool ExynosCameraHWInterface::m_previewThreadFunc(void) +{ + ExynosBuffer previewBuf, callbackBuf; + int stride; + int previewW, previewH; + bool doPutPreviewBuf = true; + + if (m_secCamera->getPreviewBuf(&previewBuf) == false) { + LOGE("ERR(%s):getPreviewBuf() fail", __func__); + return false; + } + +#ifndef USE_3DNR_DMAOUT + if (m_videoStart == true) { + copy_previewBuf = previewBuf; + m_videoRunning = true; + m_videoCondition.signal(); + } +#endif + + m_skipFrameLock.lock(); + if (0 < m_skipFrame) { + m_skipFrame--; + m_skipFrameLock.unlock(); + LOGV("DEBUG(%s):skipping %d frame", __func__, previewBuf.reserved.p); + + if ( doPutPreviewBuf == true + && m_secCamera->putPreviewBuf(&previewBuf) == false) { + LOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); + return false; + } + + return true; + } + m_skipFrameLock.unlock(); + + callbackBuf = previewBuf; + + m_secCamera->getPreviewSize(&previewW, &previewH); + + if (m_previewWindow && m_grallocHal && m_previewRunning == true) { + + bool findGrallocBuf = false; + buffer_handle_t *bufHandle = NULL; + void *virtAddr[3]; + + /* Unlock grallocHal buffer if locked */ + if (m_flagGrallocLocked[previewBuf.reserved.p] == true) { + m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[previewBuf.reserved.p]); + m_flagGrallocLocked[previewBuf.reserved.p] = false; + } else { + if (m_previewWindow->lock_buffer(m_previewWindow, bufHandle) != 0) + LOGE("ERR(%s):Could not lock gralloc buffer!!", __func__); + } + + /* Enqueue lastest buffer */ + if (m_avaliblePreviewBufHandle[previewBuf.reserved.p] == true) { + if (m_previewWindow->enqueue_buffer(m_previewWindow, + m_previewBufHandle[previewBuf.reserved.p]) != 0) { + LOGE("ERR(%s):Could not enqueue gralloc buffer[%d]!!", __func__, previewBuf.reserved.p); + goto callbacks; + } + + m_avaliblePreviewBufHandle[previewBuf.reserved.p] = false; + } + + /* Dequeue buffer from Gralloc */ + if (m_previewWindow->dequeue_buffer(m_previewWindow, + &bufHandle, + &stride) != 0) { + LOGE("ERR(%s):Could not dequeue gralloc buffer!!", __func__); + goto callbacks; + } + + /* Get virtual address from dequeued buf */ + if (m_grallocHal->lock(m_grallocHal, + *bufHandle, + GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_YUV_ADDR, + 0, 0, previewW, previewH, virtAddr) != 0) { + LOGE("ERR(%s):could not obtain gralloc buffer", __func__); + goto callbacks; + } + + for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { + if ((unsigned int)m_grallocVirtAddr[i] == (unsigned int)virtAddr[0]) { + findGrallocBuf = true; + + m_previewBufHandle[i] = bufHandle; + m_previewStride[i] = stride; + + previewBuf.reserved.p = i; + previewBuf.virt.extP[0] = (char *)virtAddr[0]; + previewBuf.virt.extP[1] = (char *)virtAddr[1]; + previewBuf.virt.extP[2] = (char *)virtAddr[2]; + + m_secCamera->setPreviewBuf(&previewBuf); + m_matchedGrallocIndex[previewBuf.reserved.p] = i; + m_avaliblePreviewBufHandle[i] = true; + break; + } + } + + if (findGrallocBuf == false) { + LOGE("%s:addr(%x) is not matched any gralloc buffer's addr", __func__, virtAddr[0]); + goto callbacks; + } + + if ( doPutPreviewBuf == true + && m_secCamera->putPreviewBuf(&previewBuf) == false) + LOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); + else + doPutPreviewBuf = false; + } + +callbacks: + + if ( m_previewRunning == true + && m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME) { + + // resize from previewBuf(max size) to m_previewHeap(user's set size) + if (m_exynosPreviewCSC) { + int previewFormat = m_secCamera->getPreviewFormat(); + + csc_set_src_format(m_exynosPreviewCSC, + previewW, previewH - 8, + 0, 0, previewW, previewH - 8, + V4L2_PIX_2_HAL_PIXEL_FORMAT(previewFormat), + 0); + + csc_set_dst_format(m_exynosPreviewCSC, + m_orgPreviewRect.w, m_orgPreviewRect.h, + 0, 0, m_orgPreviewRect.w, m_orgPreviewRect.h, + V4L2_PIX_2_HAL_PIXEL_FORMAT(m_orgPreviewRect.colorFormat), + 1); + + + csc_set_src_buffer(m_exynosPreviewCSC, + (unsigned char *)callbackBuf.virt.extP[0], + (unsigned char *)callbackBuf.virt.extP[1], + (unsigned char *)callbackBuf.virt.extP[2], + 0); + + ExynosBuffer dstBuf; + m_getAlignedYUVSize(m_orgPreviewRect.colorFormat, m_orgPreviewRect.w, m_orgPreviewRect.h, &dstBuf); + + dstBuf.virt.extP[0] = (char *)m_previewHeap[callbackBuf.reserved.p]->data; + for (int i = 1; i < 3; i++) { + if (dstBuf.size.extS[i] != 0) + dstBuf.virt.extP[i] = dstBuf.virt.extP[i-1] + dstBuf.size.extS[i-1]; + } + + csc_set_dst_buffer(m_exynosPreviewCSC, + (unsigned char *)dstBuf.virt.extP[0], + (unsigned char *)dstBuf.virt.extP[1], + (unsigned char *)dstBuf.virt.extP[2], + 0); + + if (csc_convert(m_exynosPreviewCSC) != 0) + LOGE("ERR(%s):csc_convert() fail", __func__); + } else { + LOGE("ERR(%s):m_exynosPreviewCSC == NULL", __func__); + } + } + + /* TODO: We need better error handling scheme than this scheme */ + if ( doPutPreviewBuf == true + && m_secCamera->putPreviewBuf(&previewBuf) == false) + LOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); + else + doPutPreviewBuf = false; + + if ( m_previewRunning == true + && m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME) { + m_dataCb(CAMERA_MSG_PREVIEW_FRAME, m_previewHeap[callbackBuf.reserved.p], 0, NULL, m_callbackCookie); + } + + /* Face detection */ + if ( m_previewRunning == true + && m_msgEnabled & CAMERA_MSG_PREVIEW_METADATA + && m_secCamera->flagStartFaceDetection() == true) { + + camera_frame_metadata_t *ptrMetadata = NULL; + + int id[NUM_OF_DETECTED_FACES]; + int score[NUM_OF_DETECTED_FACES]; + ExynosRect2 detectedFace[NUM_OF_DETECTED_FACES]; + ExynosRect2 detectedLeftEye[NUM_OF_DETECTED_FACES]; + ExynosRect2 detectedRightEye[NUM_OF_DETECTED_FACES]; + ExynosRect2 detectedMouth[NUM_OF_DETECTED_FACES]; + + int numOfDetectedFaces = m_secCamera->getDetectedFacesAreas(NUM_OF_DETECTED_FACES, + id, + score, + detectedFace, + detectedLeftEye, + detectedRightEye, + detectedMouth); + + if (0 < numOfDetectedFaces) { + // camera.h + // width : -1000~1000 + // height : -1000~1000 + // if eye, mouth is not detectable : -2000, -2000. + + int realNumOfDetectedFaces = 0; + m_faceDetected = true; + + for (int i = 0; i < numOfDetectedFaces; i++) { + // over 50s, we will catch + //if (score[i] < 50) + // continue; + + m_faces[realNumOfDetectedFaces].rect[0] = m_calibratePosition(previewW, 2000, detectedFace[i].x1) - 1000; + m_faces[realNumOfDetectedFaces].rect[1] = m_calibratePosition(previewH, 2000, detectedFace[i].y1) - 1000; + m_faces[realNumOfDetectedFaces].rect[2] = m_calibratePosition(previewW, 2000, detectedFace[i].x2) - 1000; + m_faces[realNumOfDetectedFaces].rect[3] = m_calibratePosition(previewH, 2000, detectedFace[i].y2) - 1000; + + m_faces[realNumOfDetectedFaces].id = id[i]; + m_faces[realNumOfDetectedFaces].score = score[i]; + + m_faces[realNumOfDetectedFaces].left_eye[0] = (detectedLeftEye[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedLeftEye[i].x1) - 1000; + m_faces[realNumOfDetectedFaces].left_eye[1] = (detectedLeftEye[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedLeftEye[i].y1) - 1000; + + m_faces[realNumOfDetectedFaces].right_eye[0] = (detectedRightEye[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedRightEye[i].x1) - 1000; + m_faces[realNumOfDetectedFaces].right_eye[1] = (detectedRightEye[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedRightEye[i].y1) - 1000; + + m_faces[realNumOfDetectedFaces].mouth[0] = (detectedMouth[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedMouth[i].x1) - 1000; + m_faces[realNumOfDetectedFaces].mouth[1] = (detectedMouth[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedMouth[i].y1) - 1000; + + realNumOfDetectedFaces++; + } + + m_frameMetadata.number_of_faces = realNumOfDetectedFaces; + m_frameMetadata.faces = m_faces; + + ptrMetadata = &m_frameMetadata; + + m_dataCb(CAMERA_MSG_PREVIEW_METADATA, m_previewHeap[callbackBuf.reserved.p], 0, ptrMetadata, m_callbackCookie); + } else if (numOfDetectedFaces == 0 && m_faceDetected == true) { + m_frameMetadata.number_of_faces = 0; + m_frameMetadata.faces = m_faces; + + ptrMetadata = &m_frameMetadata; + + m_dataCb(CAMERA_MSG_PREVIEW_METADATA, m_previewHeap[callbackBuf.reserved.p], 0, ptrMetadata, m_callbackCookie); + m_faceDetected = false; + } + } + + // zero shutter lag + if (m_pictureRunning == false + && m_startPictureInternal() == false) + LOGE("ERR(%s):m_startPictureInternal() fail", __func__); + + m_stateLock.lock(); + if (m_captureInProgress == true) { + m_stateLock.unlock(); + } else { + m_stateLock.unlock(); + + if (m_numOfAvaliblePictureBuf < NUM_OF_PICTURE_BUF) { + + ExynosBufferQueue *cur = m_oldPictureBufQueueHead; + do { + if(cur->next == NULL) { + cur->buf = m_pictureBuf; + break; + } + cur = cur->next; + } while (cur->next); + + if (m_secCamera->getPictureBuf(&m_pictureBuf) == false) + LOGE("ERR(%s):getPictureBuf() fail", __func__); + else + m_numOfAvaliblePictureBuf++; + } + + if (NUM_OF_WAITING_PUT_PICTURE_BUF < m_numOfAvaliblePictureBuf) { + ExynosBuffer nullBuf; + ExynosBuffer oldBuf; + + oldBuf = m_oldPictureBufQueueHead->buf; + + m_oldPictureBufQueueHead->buf = nullBuf; + + if (m_oldPictureBufQueueHead->next) { + ExynosBufferQueue *newQueueHead = m_oldPictureBufQueueHead->next; + m_oldPictureBufQueueHead->next = NULL; + m_oldPictureBufQueueHead = newQueueHead; + } else { + m_oldPictureBufQueueHead = &m_oldPictureBufQueue[0]; + } + + if (oldBuf != nullBuf) { + if (m_secCamera->putPictureBuf(&oldBuf) == false) + LOGE("ERR(%s):putPictureBuf(%d) fail", __func__, oldBuf.reserved.p); + else { + m_numOfAvaliblePictureBuf--; + if (m_numOfAvaliblePictureBuf < 0) + m_numOfAvaliblePictureBuf = 0; + } + + } + } + } + + return true; +} + +bool ExynosCameraHWInterface::m_videoThreadFuncWrapper(void) +{ + while (1) { + while (m_videoRunning == false) { + m_videoLock.lock(); + +#ifdef USE_3DNR_DMAOUT + if ( m_secCamera->flagStartVideo() == true + && m_secCamera->stopVideo() == false) + LOGE("ERR(%s):Fail on m_secCamera->stopVideo()", __func__); +#endif + + LOGV("DEBUG(%s):calling mExynosCamera->stopVideo() and waiting", __func__); + + m_videoStoppedCondition.signal(); + m_videoCondition.wait(m_videoLock); + LOGV("DEBUG(%s):return from wait", __func__); + + m_videoLock.unlock(); + } + + if (m_exitVideoThread == true) { + m_videoLock.lock(); + +#ifdef USE_3DNR_DMAOUT + if ( m_secCamera->flagStartVideo() == true + && m_secCamera->stopVideo() == false) + LOGE("ERR(%s):Fail on m_secCamera->stopVideo()", __func__); +#endif + + m_videoLock.unlock(); + return true; + } + + m_videoThreadFunc(); +#ifndef USE_3DNR_DMAOUT + m_videoRunning = false; +#endif + } + return true; +} + +bool ExynosCameraHWInterface::m_videoThreadFunc(void) +{ + nsecs_t timestamp; +#ifdef USE_3DNR_DMAOUT + ExynosBuffer videoBuf; +#endif + + if (m_numOfAvailableVideoBuf == 0) + usleep(1000); // sleep 1msec for other threads. + + { + if ( m_msgEnabled & CAMERA_MSG_VIDEO_FRAME + && m_videoRunning == true) { + + Mutex::Autolock lock(m_videoLock); + + if (m_numOfAvailableVideoBuf == 0) { + LOGV("DEBUG(%s):waiting releaseRecordingFrame()", __func__); + return true; + } + +#ifdef USE_3DNR_DMAOUT + if (m_secCamera->getVideoBuf(&videoBuf) == false) { + LOGE("ERR(%s):Fail on ExynosCamera->getVideoBuf()", __func__); + return false; + } +#endif + + m_numOfAvailableVideoBuf--; + if (m_numOfAvailableVideoBuf < 0) + m_numOfAvailableVideoBuf = 0; + + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + + // Notify the client of a new frame. + if ( m_msgEnabled & CAMERA_MSG_VIDEO_FRAME + && m_videoRunning == true) { + + // resize from videoBuf(max size) to m_videoHeap(user's set size) + if (m_exynosVideoCSC) { + int videoW, videoH, videoFormat = 0; + int cropX, cropY, cropW, cropH = 0; + +#ifndef USE_3DNR_DMAOUT + int previewW, previewH, previewFormat = 0; + previewFormat = m_secCamera->getPreviewFormat(); + m_secCamera->getPreviewSize(&previewW, &previewH); +#endif + videoFormat = m_secCamera->getVideoFormat(); + m_secCamera->getVideoSize(&videoW, &videoH); + + m_getRatioSize(videoW, videoH, + m_orgVideoRect.w, m_orgVideoRect.h, + &cropX, &cropY, + &cropW, &cropH, + m_secCamera->getZoom()); + + LOGV("DEBUG(%s):cropX = %d, cropY = %d, cropW = %d, cropH = %d", + __func__, cropX, cropY, cropW, cropH); + +#ifdef USE_3DNR_DMAOUT + csc_set_src_format(m_exynosVideoCSC, + videoW, videoH, + cropX, cropY, cropW, cropH, + V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), + 0); +#else + csc_set_src_format(m_exynosVideoCSC, + previewW, previewH - 8, + 0, 0, previewW, previewH - 8, + V4L2_PIX_2_HAL_PIXEL_FORMAT(previewFormat), + 0); +#endif + + csc_set_dst_format(m_exynosVideoCSC, + m_orgVideoRect.w, m_orgVideoRect.h, + 0, 0, m_orgVideoRect.w, m_orgVideoRect.h, + V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), + 1); + +#ifdef USE_3DNR_DMAOUT + csc_set_src_buffer(m_exynosVideoCSC, + (unsigned char *)videoBuf.virt.extP[0], + (unsigned char *)videoBuf.virt.extP[1], + (unsigned char *)videoBuf.virt.extP[2], + 0); +#else + csc_set_src_buffer(m_exynosVideoCSC, + (unsigned char *)copy_previewBuf.virt.extP[0], + (unsigned char *)copy_previewBuf.virt.extP[2], + (unsigned char *)copy_previewBuf.virt.extP[1], + 0); +#endif + + ExynosBuffer dstBuf; + m_getAlignedYUVSize(videoFormat, m_orgVideoRect.w, m_orgVideoRect.h, &dstBuf); + +#ifdef USE_3DNR_DMAOUT + dstBuf.virt.extP[0] = (char *)m_resizedVideoHeap[videoBuf.reserved.p]->data; +#else + dstBuf.virt.extP[0] = (char *)m_resizedVideoHeap[m_cntVideoBuf]->data; +#endif + for (int i = 1; i < 3; i++) { + if (dstBuf.size.extS[i] != 0) + dstBuf.virt.extP[i] = dstBuf.virt.extP[i-1] + dstBuf.size.extS[i-1]; + } + + csc_set_dst_buffer(m_exynosVideoCSC, + (unsigned char *)dstBuf.virt.extP[0], + (unsigned char *)dstBuf.virt.extP[1], + (unsigned char *)dstBuf.virt.extP[2], + 0); + + if (csc_convert(m_exynosVideoCSC) != 0) + LOGE("ERR(%s):csc_convert() fail", __func__); + } else { + LOGE("ERR(%s):m_exynosVideoCSC == NULL", __func__); + } +#ifdef USE_3DNR_DMAOUT + m_dataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, + m_resizedVideoHeap[videoBuf.reserved.p], 0, m_callbackCookie); +#else + m_dataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, + m_resizedVideoHeap[m_cntVideoBuf], 0, m_callbackCookie); + m_cntVideoBuf++; + if (m_cntVideoBuf == NUM_OF_VIDEO_BUF) + m_cntVideoBuf = 0; +#endif + } + + // HACK : This must can handle on releaseRecordingFrame() +#ifdef USE_3DNR_DMAOUT + m_secCamera->putVideoBuf(&videoBuf); +#endif + m_numOfAvailableVideoBuf++; + if (NUM_OF_VIDEO_BUF <= m_numOfAvailableVideoBuf) + m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; + // until here + } else + usleep(1000); // sleep 1msec for stopRecording + } + + return true; +} + +bool ExynosCameraHWInterface::m_autoFocusThreadFunc(void) +{ + int count =0; + bool afResult = false; + LOGV("DEBUG(%s):starting", __func__); + + /* block until we're told to start. we don't want to use + * a restartable thread and requestExitAndWait() in cancelAutoFocus() + * because it would cause deadlock between our callbacks and the + * caller of cancelAutoFocus() which both want to grab the same lock + * in CameraServices layer. + */ + m_focusLock.lock(); + /* check early exit request */ + if (m_exitAutoFocusThread == true) { + m_focusLock.unlock(); + LOGV("DEBUG(%s):exiting on request0", __func__); + return true; + } + + m_focusCondition.wait(m_focusLock); + /* check early exit request */ + if (m_exitAutoFocusThread == true) { + m_focusLock.unlock(); + LOGV("DEBUG(%s):exiting on request1", __func__); + return true; + } + m_focusLock.unlock(); + + if (m_secCamera->autoFocus() == false) { + LOGE("ERR(%s):Fail on m_secCamera->autoFocus()", __func__); + return false; + } + + switch (m_secCamera->getFucusModeResult()) { + case 0: + LOGV("DEBUG(%s):AF Cancelled !!", __func__); + afResult = true; + break; + case 1: + LOGV("DEBUG(%s):AF Success!!", __func__); + afResult = true; + break; + default: + LOGV("DEBUG(%s):AF Fail !!", __func__); + afResult = false; + break; + } + + // CAMERA_MSG_FOCUS only takes a bool. true for + // finished and false for failure. cancel is still + // considered a true result. + if (m_msgEnabled & CAMERA_MSG_FOCUS) + m_notifyCb(CAMERA_MSG_FOCUS, afResult, 0, m_callbackCookie); + + LOGV("DEBUG(%s):exiting with no error", __func__); + return true; +} + +bool ExynosCameraHWInterface::m_startPictureInternal(void) +{ + if (m_pictureRunning == true) { + LOGE("ERR(%s):Aready m_pictureRunning is running", __func__); + return false; + } + + int pictureW, pictureH, pictureFormat, pictureFramesize; + ExynosBuffer nullBuf; + + m_secCamera->getPictureSize(&pictureW, &pictureH); + pictureFormat = m_secCamera->getPictureFormat(); + pictureFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(V4L2_PIX_FMT_NV16), pictureW, pictureH); + + if (m_rawHeap) { + m_rawHeap->release(m_rawHeap); + m_rawHeap = 0; + } + m_rawHeap = m_getMemoryCb(-1, pictureFramesize, 1, NULL); + if (!m_rawHeap) { + LOGE("ERR(%s):m_getMemoryCb(m_rawHeap, size(%d) fail", __func__, pictureFramesize); + return false; + } + + pictureFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), pictureW, pictureH); + for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { + if (m_pictureHeap[i]) { + m_pictureHeap[i]->release(m_pictureHeap[i]); + m_pictureHeap[i] = 0; + } + + m_pictureHeap[i] = m_getMemoryCb(-1, pictureFramesize, 1, NULL); + if (!m_pictureHeap[i]) { + LOGE("ERR(%s):m_getMemoryCb(m_pictureHeap[%d], size(%d) fail", __func__, i, pictureFramesize); + return false; + } + + m_getAlignedYUVSize(pictureFormat, pictureW, pictureH, &m_pictureBuf); + + m_pictureBuf.virt.extP[0] = (char *)m_pictureHeap[i]->data; + for (int j = 1; j < 3; j++) { + if (m_pictureBuf.size.extS[j] != 0) + m_pictureBuf.virt.extP[j] = m_pictureBuf.virt.extP[j-1] + m_pictureBuf.size.extS[j-1]; + else + m_pictureBuf.virt.extP[j] = NULL; + } + + m_pictureBuf.reserved.p = i; + + m_secCamera->setPictureBuf(&m_pictureBuf); + } + + // zero shutter lag + if (m_secCamera->startPicture() == false) { + LOGE("ERR(%s):Fail on m_secCamera->startPicture()", __func__); + return false; + } + + m_numOfAvaliblePictureBuf = 0; + m_pictureBuf = nullBuf; + + for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { + m_oldPictureBufQueue[i].buf = nullBuf; + m_oldPictureBufQueue[i].next = NULL; + } + + m_oldPictureBufQueueHead = &m_oldPictureBufQueue[0]; + + m_pictureRunning = true; + + return true; + +} + +bool ExynosCameraHWInterface::m_stopPictureInternal(void) +{ + if (m_pictureRunning == false) { + LOGE("ERR(%s):Aready m_pictureRunning is stop", __func__); + return false; + } + + if (m_secCamera->flagStartPicture() == true + && m_secCamera->stopPicture() == false) + LOGE("ERR(%s):Fail on m_secCamera->stopPicture()", __func__); + + for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { + if (m_pictureHeap[i]) { + m_pictureHeap[i]->release(m_pictureHeap[i]); + m_pictureHeap[i] = 0; + } + } + + if (m_rawHeap) { + m_rawHeap->release(m_rawHeap); + m_rawHeap = 0; + } + + m_pictureRunning = false; + + return true; +} + +bool ExynosCameraHWInterface::m_pictureThreadFunc(void) +{ + bool ret = false; + int pictureW, pictureH, pictureFramesize = 0; + int pictureFormat; + int cropX, cropY, cropW, cropH = 0; + + ExynosBuffer pictureBuf; + ExynosBuffer jpegBuf; + + camera_memory_t *JpegHeap = NULL; + camera_memory_t *JpegHeapOut = NULL; + + m_secCamera->getPictureSize(&pictureW, &pictureH); + pictureFormat = m_secCamera->getPictureFormat(); + pictureFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), pictureW, pictureH); + + JpegHeap = m_getMemoryCb(-1, pictureFramesize, 1, 0); + if (!JpegHeap) { + LOGE("ERR(%s):m_getMemoryCb(JpegHeap, size(%d) fail", __func__, pictureFramesize); + return false; + } + + // resize from pictureBuf(max size) to rawHeap(user's set size) + if (m_exynosPictureCSC) { + m_getRatioSize(pictureW, pictureH, + m_orgPictureRect.w, m_orgPictureRect.h, + &cropX, &cropY, + &cropW, &cropH, + m_secCamera->getZoom()); + + LOGV("DEBUG(%s):cropX = %d, cropY = %d, cropW = %d, cropH = %d", + __func__, cropX, cropY, cropW, cropH); + + csc_set_src_format(m_exynosPictureCSC, + pictureW, pictureH, + cropX, cropY, cropW, cropH, + V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), + 1); + //0); + + csc_set_dst_format(m_exynosPictureCSC, + m_orgPictureRect.w, m_orgPictureRect.h, + 0, 0, m_orgPictureRect.w, m_orgPictureRect.h, + V4L2_PIX_2_HAL_PIXEL_FORMAT(V4L2_PIX_FMT_NV16), + 1); + //0); + + csc_set_src_buffer(m_exynosPictureCSC, + (unsigned char *)m_pictureBuf.virt.extP[0], + (unsigned char *)m_pictureBuf.virt.extP[1], + (unsigned char *)m_pictureBuf.virt.extP[2], + 0); + + pictureBuf.size.extS[0] = ALIGN(m_orgPictureRect.w, 16) * ALIGN(m_orgPictureRect.h, 16) * 2; + pictureBuf.size.extS[1] = 0; + pictureBuf.size.extS[2] = 0; + + pictureBuf.virt.extP[0] = (char *)m_rawHeap->data; + + csc_set_dst_buffer(m_exynosPictureCSC, + (unsigned char *)pictureBuf.virt.extP[0], + (unsigned char *)pictureBuf.virt.extP[1], + (unsigned char *)pictureBuf.virt.extP[2], + 0); + + if (csc_convert(m_exynosPictureCSC) != 0) + LOGE("ERR(%s):csc_convert() fail", __func__); + } else { + LOGE("ERR(%s):m_exynosPictureCSC == NULL", __func__); + } + + if (m_msgEnabled & CAMERA_MSG_SHUTTER) + m_notifyCb(CAMERA_MSG_SHUTTER, 0, 0, m_callbackCookie); + + m_getAlignedYUVSize(V4L2_PIX_FMT_NV16, m_orgPictureRect.w, m_orgPictureRect.h, &pictureBuf); + + for (int i = 1; i < 3; i++) { + if (pictureBuf.size.extS[i] != 0) + pictureBuf.virt.extP[i] = pictureBuf.virt.extP[i-1] + pictureBuf.size.extS[i-1]; + + LOGV("(%s): pictureBuf.size.extS[%d] = %d", __func__, i, pictureBuf.size.extS[i]); + } + + if (m_msgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { + jpegBuf.virt.p = (char *)JpegHeap->data; + jpegBuf.size.s = pictureFramesize; + + ExynosRect jpegRect; + jpegRect.w = m_orgPictureRect.w; + jpegRect.h = m_orgPictureRect.h; + jpegRect.colorFormat = V4L2_PIX_FMT_NV16; + + if (m_secCamera->yuv2Jpeg(&pictureBuf, &jpegBuf, &jpegRect) == false) { + LOGE("ERR(%s):yuv2Jpeg() fail", __func__); + m_stateLock.lock(); + m_captureInProgress = false; + m_pictureLock.lock(); + m_pictureCondition.signal(); + m_pictureLock.unlock(); + m_stateLock.unlock(); + goto out; + } + } + + m_stateLock.lock(); + m_captureInProgress = false; + m_pictureLock.lock(); + m_pictureCondition.signal(); + m_pictureLock.unlock(); + m_stateLock.unlock(); + + if (m_msgEnabled & CAMERA_MSG_RAW_IMAGE) + m_dataCb(CAMERA_MSG_RAW_IMAGE, m_rawHeap, 0, NULL, m_callbackCookie); + + /* TODO: Currently framework dose not support CAMERA_MSG_RAW_IMAGE_NOTIFY callback */ + /* + if (m_msgEnabled & CAMERA_MSG_RAW_IMAGE_NOTIFY) + m_dataCb(CAMERA_MSG_RAW_IMAGE_NOTIFY, m_rawHeap, 0, NULL, m_callbackCookie); + */ + + if (m_msgEnabled & CAMERA_MSG_POSTVIEW_FRAME) + m_dataCb(CAMERA_MSG_POSTVIEW_FRAME, m_rawHeap, 0, NULL, m_callbackCookie); + + if (m_msgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { + JpegHeapOut = m_getMemoryCb(-1, jpegBuf.size.s, 1, 0); + if (!JpegHeapOut) { + LOGE("ERR(%s):m_getMemoryCb(JpegHeapOut, size(%d) fail", __func__, jpegBuf.size.s); + return false; + } + + // TODO : we shall pass JpegHeap mem directly? + memcpy(JpegHeapOut->data, JpegHeap->data, jpegBuf.size.s); + + m_dataCb(CAMERA_MSG_COMPRESSED_IMAGE, JpegHeapOut, 0, NULL, m_callbackCookie); + } + + if (m_videoStart == false) + stopPreview(); + + LOGV("DEBUG(%s):m_pictureThread end", __func__); + + ret = true; + +out: + + if (JpegHeapOut) { + JpegHeapOut->release(JpegHeapOut); + JpegHeapOut = 0; + } + + if (JpegHeap) { + JpegHeap->release(JpegHeap); + JpegHeap = 0; + } + + return ret; +} + +#ifdef LOG_NDEBUG +bool ExynosCameraHWInterface::m_fileDump(char *filename, void *srcBuf, uint32_t size) +{ + FILE *yuv_fd = NULL; + char *buffer = NULL; + static int count = 0; + + yuv_fd = fopen(filename, "w+"); + + if (yuv_fd == NULL) { + LOGE("ERR file open fail: %s", filename); + return 0; + } + + buffer = (char *)malloc(size); + + if (buffer == NULL) { + LOGE("ERR malloc file"); + fclose(yuv_fd); + return 0; + } + + memcpy(buffer, srcBuf, size); + + fflush(stdout); + + fwrite(buffer, 1, size, yuv_fd); + + fflush(yuv_fd); + + if (yuv_fd) + fclose(yuv_fd); + if (buffer) + free(buffer); + + LOGV("filedump(%s) is successed!!", filename); + return true; +} +#endif + +void ExynosCameraHWInterface::m_setSkipFrame(int frame) +{ + Mutex::Autolock lock(m_skipFrameLock); + if (frame < m_skipFrame) + return; + + m_skipFrame = frame; +} + +int ExynosCameraHWInterface::m_saveJpeg( unsigned char *real_jpeg, int jpeg_size) +{ + FILE *yuv_fp = NULL; + char filename[100], *buffer = NULL; + + /* file create/open, note to "wb" */ + yuv_fp = fopen("/data/camera_dump.jpeg", "wb"); + if (yuv_fp == NULL) { + LOGE("Save jpeg file open error"); + return -1; + } + + LOGV("DEBUG(%s):[BestIQ] real_jpeg size ========> %d", __func__, jpeg_size); + buffer = (char *) malloc(jpeg_size); + if (buffer == NULL) { + LOGE("Save YUV] buffer alloc failed"); + if (yuv_fp) + fclose(yuv_fp); + + return -1; + } + + memcpy(buffer, real_jpeg, jpeg_size); + + fflush(stdout); + + fwrite(buffer, 1, jpeg_size, yuv_fp); + + fflush(yuv_fp); + + if (yuv_fp) + fclose(yuv_fp); + if (buffer) + free(buffer); + + return 0; +} + +void ExynosCameraHWInterface::m_savePostView(const char *fname, uint8_t *buf, uint32_t size) +{ + int nw; + int cnt = 0; + uint32_t written = 0; + + LOGD("opening file [%s]", fname); + int fd = open(fname, O_RDWR | O_CREAT); + if (fd < 0) { + LOGE("failed to create file [%s]: %s", fname, strerror(errno)); + return; + } + + LOGD("writing %d bytes to file [%s]", size, fname); + while (written < size) { + nw = ::write(fd, buf + written, size - written); + if (nw < 0) { + LOGE("failed to write to file %d [%s]: %s",written,fname, strerror(errno)); + break; + } + written += nw; + cnt++; + } + LOGD("done writing %d bytes to file [%s] in %d passes",size, fname, cnt); + ::close(fd); +} + +bool ExynosCameraHWInterface::m_scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHeight, + char *dstBuf, uint32_t dstWidth, uint32_t dstHeight) +{ + int32_t step_x, step_y; + int32_t iXsrc, iXdst; + int32_t x, y, src_y_start_pos, dst_pos, src_pos; + + if (dstWidth % 2 != 0 || dstHeight % 2 != 0) { + LOGE("scale_down_yuv422: invalid width, height for scaling"); + return false; + } + + step_x = srcWidth / dstWidth; + step_y = srcHeight / dstHeight; + + dst_pos = 0; + for (uint32_t y = 0; y < dstHeight; y++) { + src_y_start_pos = (y * step_y * (srcWidth * 2)); + + for (uint32_t x = 0; x < dstWidth; x += 2) { + src_pos = src_y_start_pos + (x * (step_x * 2)); + + dstBuf[dst_pos++] = srcBuf[src_pos ]; + dstBuf[dst_pos++] = srcBuf[src_pos + 1]; + dstBuf[dst_pos++] = srcBuf[src_pos + 2]; + dstBuf[dst_pos++] = srcBuf[src_pos + 3]; + } + } + + return true; +} + +bool ExynosCameraHWInterface::m_YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight) +{ + int32_t x, y, src_y_start_pos, dst_cbcr_pos, dst_pos, src_pos; + unsigned char *srcBufPointer = (unsigned char *)srcBuf; + unsigned char *dstBufPointer = (unsigned char *)dstBuf; + + dst_pos = 0; + dst_cbcr_pos = srcWidth*srcHeight; + for (uint32_t y = 0; y < srcHeight; y++) { + src_y_start_pos = (y * (srcWidth * 2)); + + for (uint32_t x = 0; x < (srcWidth * 2); x += 2) { + src_pos = src_y_start_pos + x; + + dstBufPointer[dst_pos++] = srcBufPointer[src_pos]; + } + } + for (uint32_t y = 0; y < srcHeight; y += 2) { + src_y_start_pos = (y * (srcWidth * 2)); + + for (uint32_t x = 0; x < (srcWidth * 2); x += 4) { + src_pos = src_y_start_pos + x; + + dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 3]; + dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 1]; + } + } + + return true; +} + +bool ExynosCameraHWInterface::m_checkVideoStartMarker(unsigned char *pBuf) +{ + if (!pBuf) { + LOGE("m_checkVideoStartMarker() => pBuf is NULL"); + return false; + } + + if (HIBYTE(VIDEO_COMMENT_MARKER_H) == * pBuf && LOBYTE(VIDEO_COMMENT_MARKER_H) == *(pBuf + 1) && + HIBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 2) && LOBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 3)) + return true; + + return false; +} + +bool ExynosCameraHWInterface::m_checkEOIMarker(unsigned char *pBuf) +{ + if (!pBuf) { + LOGE("m_checkEOIMarker() => pBuf is NULL"); + return false; + } + + // EOI marker [FF D9] + if (HIBYTE(JPEG_EOI_MARKER) == *pBuf && LOBYTE(JPEG_EOI_MARKER) == *(pBuf + 1)) + return true; + + return false; +} + +bool ExynosCameraHWInterface::m_findEOIMarkerInJPEG(unsigned char *pBuf, int dwBufSize, int *pnJPEGsize) +{ + if (NULL == pBuf || 0 >= dwBufSize) { + LOGE("m_findEOIMarkerInJPEG() => There is no contents."); + return false; + } + + unsigned char *pBufEnd = pBuf + dwBufSize; + + while (pBuf < pBufEnd) { + if (m_checkEOIMarker(pBuf++)) + return true; + + (*pnJPEGsize)++; + } + + return false; +} + +bool ExynosCameraHWInterface::m_splitFrame(unsigned char *pFrame, int dwSize, + int dwJPEGLineLength, int dwVideoLineLength, int dwVideoHeight, + void *pJPEG, int *pdwJPEGSize, + void *pVideo, int *pdwVideoSize) +{ + LOGV("DEBUG(%s):===========m_splitFrame Start==============", __func__); + + if (NULL == pFrame || 0 >= dwSize) { + LOGE("There is no contents (pFrame=%p, dwSize=%d", pFrame, dwSize); + return false; + } + + if (0 == dwJPEGLineLength || 0 == dwVideoLineLength) { + LOGE("There in no input information for decoding interleaved jpeg"); + return false; + } + + unsigned char *pSrc = pFrame; + unsigned char *pSrcEnd = pFrame + dwSize; + + unsigned char *pJ = (unsigned char *)pJPEG; + int dwJSize = 0; + unsigned char *pV = (unsigned char *)pVideo; + int dwVSize = 0; + + bool bRet = false; + bool isFinishJpeg = false; + + while (pSrc < pSrcEnd) { + // Check video start marker + if (m_checkVideoStartMarker(pSrc)) { + int copyLength; + + if (pSrc + dwVideoLineLength <= pSrcEnd) + copyLength = dwVideoLineLength; + else + copyLength = pSrcEnd - pSrc - VIDEO_COMMENT_MARKER_LENGTH; + + // Copy video data + if (pV) { + memcpy(pV, pSrc + VIDEO_COMMENT_MARKER_LENGTH, copyLength); + pV += copyLength; + dwVSize += copyLength; + } + + pSrc += copyLength + VIDEO_COMMENT_MARKER_LENGTH; + } else { + // Copy pure JPEG data + int size = 0; + int dwCopyBufLen = dwJPEGLineLength <= pSrcEnd-pSrc ? dwJPEGLineLength : pSrcEnd - pSrc; + + if (m_findEOIMarkerInJPEG((unsigned char *)pSrc, dwCopyBufLen, &size)) { + isFinishJpeg = true; + size += 2; // to count EOF marker size + } else { + if ((dwCopyBufLen == 1) && (pJPEG < pJ)) { + unsigned char checkBuf[2] = { *(pJ - 1), *pSrc }; + + if (m_checkEOIMarker(checkBuf)) + isFinishJpeg = true; + } + size = dwCopyBufLen; + } + + memcpy(pJ, pSrc, size); + + dwJSize += size; + + pJ += dwCopyBufLen; + pSrc += dwCopyBufLen; + } + if (isFinishJpeg) + break; + } + + if (isFinishJpeg) { + bRet = true; + if (pdwJPEGSize) + *pdwJPEGSize = dwJSize; + if (pdwVideoSize) + *pdwVideoSize = dwVSize; + } else { + LOGE("DecodeInterleaveJPEG_WithOutDT() => Can not find EOI"); + bRet = false; + if (pdwJPEGSize) + *pdwJPEGSize = 0; + if (pdwVideoSize) + *pdwVideoSize = 0; + } + LOGV("DEBUG(%s):===========m_splitFrame end==============", __func__); + + return bRet; +} + +int ExynosCameraHWInterface::m_decodeInterleaveData(unsigned char *pInterleaveData, + int interleaveDataSize, + int yuvWidth, + int yuvHeight, + int *pJpegSize, + void *pJpegData, + void *pYuvData) +{ + if (pInterleaveData == NULL) + return false; + + bool ret = true; + unsigned int *interleave_ptr = (unsigned int *)pInterleaveData; + unsigned char *jpeg_ptr = (unsigned char *)pJpegData; + unsigned char *yuv_ptr = (unsigned char *)pYuvData; + unsigned char *p; + int jpeg_size = 0; + int yuv_size = 0; + + int i = 0; + + LOGV("DEBUG(%s):m_decodeInterleaveData Start~~~", __func__); + while (i < interleaveDataSize) { + if ((*interleave_ptr == 0xFFFFFFFF) || (*interleave_ptr == 0x02FFFFFF) || + (*interleave_ptr == 0xFF02FFFF)) { + // Padding Data + interleave_ptr++; + i += 4; + } else if ((*interleave_ptr & 0xFFFF) == 0x05FF) { + // Start-code of YUV Data + p = (unsigned char *)interleave_ptr; + p += 2; + i += 2; + + // Extract YUV Data + if (pYuvData != NULL) { + memcpy(yuv_ptr, p, yuvWidth * 2); + yuv_ptr += yuvWidth * 2; + yuv_size += yuvWidth * 2; + } + p += yuvWidth * 2; + i += yuvWidth * 2; + + // Check End-code of YUV Data + if ((*p == 0xFF) && (*(p + 1) == 0x06)) { + interleave_ptr = (unsigned int *)(p + 2); + i += 2; + } else { + ret = false; + break; + } + } else { + // Extract JPEG Data + if (pJpegData != NULL) { + memcpy(jpeg_ptr, interleave_ptr, 4); + jpeg_ptr += 4; + jpeg_size += 4; + } + interleave_ptr++; + i += 4; + } + } + if (ret) { + if (pJpegData != NULL) { + // Remove Padding after EOI + for (i = 0; i < 3; i++) { + if (*(--jpeg_ptr) != 0xFF) { + break; + } + jpeg_size--; + } + *pJpegSize = jpeg_size; + + } + // Check YUV Data Size + if (pYuvData != NULL) { + if (yuv_size != (yuvWidth * yuvHeight * 2)) { + ret = false; + } + } + } + LOGV("DEBUG(%s):m_decodeInterleaveData End~~~", __func__); + return ret; +} + +bool ExynosCameraHWInterface::m_isSupportedPreviewSize(const int width, + const int height) const +{ + unsigned int i; + + for (i = 0; i < m_supportedPreviewSizes.size(); i++) { + if (m_supportedPreviewSizes[i].width == width && + m_supportedPreviewSizes[i].height == height) + return true; + } + + return false; +} + +void ExynosCameraHWInterface::m_getAlignedYUVSize(int colorFormat, int w, int h, ExynosBuffer *buf) +{ + switch (colorFormat) { + // 1p + case V4L2_PIX_FMT_RGB565 : + case V4L2_PIX_FMT_YUYV : + case V4L2_PIX_FMT_UYVY : + case V4L2_PIX_FMT_VYUY : + case V4L2_PIX_FMT_YVYU : + buf->size.extS[0] = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(colorFormat), w, h); + buf->size.extS[1] = 0; + buf->size.extS[2] = 0; + break; + // 2p + case V4L2_PIX_FMT_NV12 : + case V4L2_PIX_FMT_NV12T : + case V4L2_PIX_FMT_NV21 : + buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); + buf->size.extS[1] = ALIGN(w/2, 16) * ALIGN(h/2, 16); + buf->size.extS[2] = 0; + break; + case V4L2_PIX_FMT_NV12M : + case V4L2_PIX_FMT_NV12MT_16X16 : + buf->size.extS[0] = ALIGN(ALIGN(w, 16) * ALIGN(h, 16), 2048); + buf->size.extS[1] = ALIGN(ALIGN(w, 16) * ALIGN(h >> 1, 8), 2048); + buf->size.extS[2] = 0; + break; + case V4L2_PIX_FMT_NV16 : + case V4L2_PIX_FMT_NV61 : + buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); + buf->size.extS[1] = ALIGN(w, 16) * ALIGN(h, 16); + buf->size.extS[2] = 0; + break; + // 3p + case V4L2_PIX_FMT_YUV420 : + case V4L2_PIX_FMT_YVU420 : + buf->size.extS[0] = (w * h); + buf->size.extS[1] = (w * h) >> 2; + buf->size.extS[2] = (w * h) >> 2; + break; + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M : + case V4L2_PIX_FMT_YUV422P : + buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); + buf->size.extS[1] = ALIGN(w/2, 8) * ALIGN(h/2, 8); + buf->size.extS[2] = ALIGN(w/2, 8) * ALIGN(h/2, 8); + break; + default: + LOGE("ERR(%s):unmatched colorFormat(%d)", __func__, colorFormat); + return; + break; + } +} + +bool ExynosCameraHWInterface::m_getResolutionList(String8 & string8Buf, char * strBuf, int w, int h) +{ + bool ret = false; + bool flagFirst = true; + + // this is up to /packages/apps/Camera/res/values/arrays.xml + int RESOLUTION_LIST[][2] = + { + { 3264, 2448}, + { 2592, 1936}, + { 2576, 1948}, + { 2560, 1920}, + { 2048, 1536}, + { 1920, 1080}, + { 1600, 1200}, + { 1280, 720}, + { 1024, 768}, + { 800, 600}, + { 800, 480}, + { 720, 480}, + { 640, 480}, + { 528, 432}, + { 480, 320}, + { 352, 288}, + { 320, 240}, + { 176, 144} + }; + + int sizeOfResSize = sizeof(RESOLUTION_LIST) / (sizeof(int) * 2); + + for (int i = 0; i < sizeOfResSize; i++) { + if ( RESOLUTION_LIST[i][0] <= w + && RESOLUTION_LIST[i][1] <= h) { + if (flagFirst == true) + flagFirst = false; + else + string8Buf.append(","); + + sprintf(strBuf, "%dx%d", RESOLUTION_LIST[i][0], RESOLUTION_LIST[i][1]); + string8Buf.append(strBuf); + + ret = true; + } + } + + if (ret == false) + LOGE("ERR(%s):cannot find resolutions", __func__); + + return ret; +} + +bool ExynosCameraHWInterface::m_getZoomRatioList(String8 & string8Buf, char * strBuf, int maxZoom, int start, int end) +{ + bool flagFirst = true; + + int cur = start; + int step = (end - start) / maxZoom; + + for (int i = 0; i < maxZoom; i++) { + sprintf(strBuf, "%d", cur); + string8Buf.append(strBuf); + string8Buf.append(","); + cur += step; + } + + sprintf(strBuf, "%d", end); + string8Buf.append(strBuf); + + // ex : "100,130,160,190,220,250,280,310,340,360,400" + + return true; +} + +int ExynosCameraHWInterface::m_bracketsStr2Ints(char *str, int num, ExynosRect2 *rect2s, int *weights) +{ + char *curStr = str; + char buf[128]; + char *bracketsOpen; + char *bracketsClose; + + int tempArray[5]; + int validFocusedAreas = 0; + + for (int i = 0; i < num; i++) { + if (curStr == NULL) + break; + + bracketsOpen = strchr(curStr, '('); + if (bracketsOpen == NULL) + break; + + bracketsClose = strchr(bracketsOpen, ')'); + if (bracketsClose == NULL) + break; + + strncpy(buf, bracketsOpen, bracketsClose - bracketsOpen + 1); + buf[bracketsClose - bracketsOpen + 1] = 0; + + if (m_subBracketsStr2Ints(5, buf, tempArray) == false) { + LOGE("ERR(%s):m_subBracketsStr2Ints(%s) fail", __func__, buf); + break; + } + + rect2s[i].x1 = tempArray[0]; + rect2s[i].y1 = tempArray[1]; + rect2s[i].x2 = tempArray[2]; + rect2s[i].y2 = tempArray[3]; + weights[i] = tempArray[4]; + + validFocusedAreas++; + + curStr = bracketsClose; + } + return validFocusedAreas; +} + +bool ExynosCameraHWInterface::m_subBracketsStr2Ints(int num, char *str, int *arr) +{ + if (str == NULL || arr == NULL) { + LOGE("ERR(%s):str or arr is NULL", __func__); + return false; + } + + // ex : (-10,-10,0,0,300) + char buf[128]; + char *bracketsOpen; + char *bracketsClose; + char *tok; + + bracketsOpen = strchr(str, '('); + if (bracketsOpen == NULL) { + LOGE("ERR(%s):no '('", __func__); + return false; + } + + bracketsClose = strchr(bracketsOpen, ')'); + if (bracketsClose == NULL) { + LOGE("ERR(%s):no ')'", __func__); + return false; + } + + strncpy(buf, bracketsOpen + 1, bracketsClose - bracketsOpen + 1); + buf[bracketsClose - bracketsOpen + 1] = 0; + + tok = strtok(buf, ","); + if (tok == NULL) { + LOGE("ERR(%s):strtok(%s) fail", __func__, buf); + return false; + } + + arr[0] = atoi(tok); + + for (int i = 1; i < num; i++) { + tok = strtok(NULL, ","); + if (tok == NULL) { + if (i < num - 1) { + LOGE("ERR(%s):strtok() (index : %d, num : %d) fail", __func__, i, num); + return false; + } + break; + } + + arr[i] = atoi(tok); + } + + return true; +} + +bool ExynosCameraHWInterface::m_getRatioSize(int src_w, int src_h, + int dst_w, int dst_h, + int *crop_x, int *crop_y, + int *crop_w, int *crop_h, + int zoom) +{ + *crop_w = src_w; + *crop_h = src_h; + + if ( src_w != dst_w + || src_h != dst_h) { + float src_ratio = 1.0f; + float dst_ratio = 1.0f; + + // ex : 1024 / 768 + src_ratio = (float)src_w / (float)src_h; + + // ex : 352 / 288 + dst_ratio = (float)dst_w / (float)dst_h; + + if (src_ratio != dst_ratio) { + if (dst_w * dst_h < src_w * src_h) { + if (src_ratio <= dst_ratio) { + // shrink h + *crop_w = src_w; + *crop_h = src_w / dst_ratio; + } else { + // shrink w + *crop_w = dst_h * dst_ratio; + *crop_h = dst_h; + } + } else { + if (src_ratio <= dst_ratio) { + // shrink h + *crop_w = src_w; + *crop_h = src_w / dst_ratio; + } else { + // shrink w + *crop_w = src_h * dst_ratio; + *crop_h = src_h; + } + } + + if (zoom != 0) { + int zoomLevel = ((float)zoom + 10.0) / 10.0; + *crop_w = (int)((float)*crop_w / zoomLevel); + *crop_h = (int)((float)*crop_h / zoomLevel); + } + } + } + + #define CAMERA_CROP_WIDTH_RESTRAIN_NUM (0x2) + unsigned int w_align = (*crop_w & (CAMERA_CROP_WIDTH_RESTRAIN_NUM - 1)); + if (w_align != 0) { + if ( (CAMERA_CROP_WIDTH_RESTRAIN_NUM >> 1) <= w_align + && *crop_w + (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align) <= dst_w) { + *crop_w += (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align); + } + else + *crop_w -= w_align; + } + + #define CAMERA_CROP_HEIGHT_RESTRAIN_NUM (0x2) + unsigned int h_align = (*crop_h & (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - 1)); + if (h_align != 0) { + if ( (CAMERA_CROP_HEIGHT_RESTRAIN_NUM >> 1) <= h_align + && *crop_h + (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align) <= dst_h) { + *crop_h += (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align); + } + else + *crop_h -= h_align; + } + + *crop_x = (src_w - *crop_w) >> 1; + *crop_y = (src_h - *crop_h) >> 1; + + if (*crop_x & (CAMERA_CROP_WIDTH_RESTRAIN_NUM >> 1)) + *crop_x -= 1; + + if (*crop_y & (CAMERA_CROP_HEIGHT_RESTRAIN_NUM >> 1)) + *crop_y -= 1; + + return true; +} + +int ExynosCameraHWInterface::m_calibratePosition(int w, int new_w, int pos) +{ + return (float)(pos * new_w) / (float)w; +} + +static CameraInfo sCameraInfo[] = { + { + CAMERA_FACING_BACK, + 0, /* orientation */ + }, + { + CAMERA_FACING_FRONT, + 0, /* orientation */ + } +}; + +/** Close this device */ + +static camera_device_t *g_cam_device; + +static int HAL_camera_device_close(struct hw_device_t* device) +{ + LOGV("DEBUG(%s):", __func__); + if (device) { + camera_device_t *cam_device = (camera_device_t *)device; + delete static_cast<ExynosCameraHWInterface *>(cam_device->priv); + free(cam_device); + g_cam_device = 0; + } + return 0; +} + +static inline ExynosCameraHWInterface *obj(struct camera_device *dev) +{ + return reinterpret_cast<ExynosCameraHWInterface *>(dev->priv); +} + +/** Set the preview_stream_ops to which preview frames are sent */ +static int HAL_camera_device_set_preview_window(struct camera_device *dev, + struct preview_stream_ops *buf) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->setPreviewWindow(buf); +} + +/** Set the notification and data callbacks */ +static void HAL_camera_device_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) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->setCallbacks(notify_cb, data_cb, data_cb_timestamp, + get_memory, + user); +} + +/** + * The following three functions all take a msg_type, which is a bitmask of + * the messages defined in include/ui/Camera.h + */ + +/** + * Enable a message, or set of messages. + */ +static void HAL_camera_device_enable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->enableMsgType(msg_type); +} + +/** + * Disable a message, or a set of messages. + * + * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera + * HAL should not rely on its client to call releaseRecordingFrame() to + * release video recording frames sent out by the cameral HAL before and + * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL + * clients must not modify/access any video recording frame after calling + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). + */ +static void HAL_camera_device_disable_msg_type(struct camera_device *dev, int32_t msg_type) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->disableMsgType(msg_type); +} + +/** + * Query whether a message, or a set of messages, is enabled. Note that + * this is operates as an AND, if any of the messages queried are off, this + * will return false. + */ +static int HAL_camera_device_msg_type_enabled(struct camera_device *dev, int32_t msg_type) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->msgTypeEnabled(msg_type); +} + +/** + * Start preview mode. + */ +static int HAL_camera_device_start_preview(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->startPreview(); +} + +/** + * Stop a previously started preview. + */ +static void HAL_camera_device_stop_preview(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->stopPreview(); +} + +/** + * Returns true if preview is enabled. + */ +static int HAL_camera_device_preview_enabled(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->previewEnabled(); +} + +/** + * Request the camera HAL to store meta data or real YUV data in the video + * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If + * it is not called, the default camera HAL behavior is to store real YUV + * data in the video buffers. + * + * This method should be called before startRecording() in order to be + * effective. + * + * If meta data is stored in the video buffers, it is up to the receiver of + * the video buffers to interpret the contents and to find the actual frame + * data with the help of the meta data in the buffer. How this is done is + * outside of the scope of this method. + * + * Some camera HALs may not support storing meta data in the video buffers, + * but all camera HALs should support storing real YUV data in the video + * buffers. If the camera HAL does not support storing the meta data in the + * video buffers when it is requested to do do, INVALID_OPERATION must be + * returned. It is very useful for the camera HAL to pass meta data rather + * than the actual frame data directly to the video encoder, since the + * amount of the uncompressed frame data can be very large if video size is + * large. + * + * @param enable if true to instruct the camera HAL to store + * meta data in the video buffers; false to instruct + * the camera HAL to store real YUV data in the video + * buffers. + * + * @return OK on success. + */ +static int HAL_camera_device_store_meta_data_in_buffers(struct camera_device *dev, int enable) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->storeMetaDataInBuffers(enable); +} + +/** + * Start record mode. When a record image is available, a + * CAMERA_MSG_VIDEO_FRAME message is sent with the corresponding + * frame. Every record frame must be released by a camera HAL client via + * releaseRecordingFrame() before the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames, + * and the client must not modify/access any video recording frames. + */ +static int HAL_camera_device_start_recording(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->startRecording(); +} + +/** + * Stop a previously started recording. + */ +static void HAL_camera_device_stop_recording(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->stopRecording(); +} + +/** + * Returns true if recording is enabled. + */ +static int HAL_camera_device_recording_enabled(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->recordingEnabled(); +} + +/** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + * + * It is camera HAL client's responsibility to release video recording + * frames sent out by the camera HAL before the camera HAL receives a call + * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames. + */ +static void HAL_camera_device_release_recording_frame(struct camera_device *dev, + const void *opaque) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->releaseRecordingFrame(opaque); +} + +/** + * Start auto focus, the notification callback routine is called with + * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() will be + * called again if another auto focus is needed. + */ +static int HAL_camera_device_auto_focus(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->autoFocus(); +} + +/** + * Cancels auto-focus function. If the auto-focus is still in progress, + * this function will cancel it. Whether the auto-focus is in progress or + * not, this function will return the focus position to the default. If + * the camera does not support auto-focus, this is a no-op. + */ +static int HAL_camera_device_cancel_auto_focus(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->cancelAutoFocus(); +} + +/** + * Take a picture. + */ +static int HAL_camera_device_take_picture(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->takePicture(); +} + +/** + * Cancel a picture that was started with takePicture. Calling this method + * when no picture is being taken is a no-op. + */ +static int HAL_camera_device_cancel_picture(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->cancelPicture(); +} + +/** + * Set the camera parameters. This returns BAD_VALUE if any parameter is + * invalid or not supported. + */ +static int HAL_camera_device_set_parameters(struct camera_device *dev, + const char *parms) +{ + LOGV("DEBUG(%s):", __func__); + String8 str(parms); + CameraParameters p(str); + return obj(dev)->setParameters(p); +} + +/** Return the camera parameters. */ +char *HAL_camera_device_get_parameters(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + String8 str; + CameraParameters parms = obj(dev)->getParameters(); + str = parms.flatten(); + return strdup(str.string()); +} + +static void HAL_camera_device_put_parameters(struct camera_device *dev, char *parms) +{ + LOGV("DEBUG(%s):", __func__); + free(parms); +} + +/** + * Send command to camera driver. + */ +static int HAL_camera_device_send_command(struct camera_device *dev, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->sendCommand(cmd, arg1, arg2); +} + +/** + * Release the hardware resources owned by this object. Note that this is + * *not* done in the destructor. + */ +static void HAL_camera_device_release(struct camera_device *dev) +{ + LOGV("DEBUG(%s):", __func__); + obj(dev)->release(); +} + +/** + * Dump state of the camera hardware + */ +static int HAL_camera_device_dump(struct camera_device *dev, int fd) +{ + LOGV("DEBUG(%s):", __func__); + return obj(dev)->dump(fd); +} + +static int HAL_getNumberOfCameras() +{ + LOGV("DEBUG(%s):", __func__); + return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]); +} + +static int HAL_getCameraInfo(int cameraId, struct camera_info *cameraInfo) +{ + LOGV("DEBUG(%s):", __func__); + memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo)); + return 0; +} + +#define SET_METHOD(m) m : HAL_camera_device_##m + +static camera_device_ops_t camera_device_ops = { + SET_METHOD(set_preview_window), + SET_METHOD(set_callbacks), + SET_METHOD(enable_msg_type), + SET_METHOD(disable_msg_type), + SET_METHOD(msg_type_enabled), + SET_METHOD(start_preview), + SET_METHOD(stop_preview), + SET_METHOD(preview_enabled), + SET_METHOD(store_meta_data_in_buffers), + SET_METHOD(start_recording), + SET_METHOD(stop_recording), + SET_METHOD(recording_enabled), + SET_METHOD(release_recording_frame), + SET_METHOD(auto_focus), + SET_METHOD(cancel_auto_focus), + SET_METHOD(take_picture), + SET_METHOD(cancel_picture), + SET_METHOD(set_parameters), + SET_METHOD(get_parameters), + SET_METHOD(put_parameters), + SET_METHOD(send_command), + SET_METHOD(release), + SET_METHOD(dump), +}; + +#undef SET_METHOD + +static int HAL_camera_device_open(const struct hw_module_t* module, + const char *id, + struct hw_device_t** device) +{ + LOGV("DEBUG(%s):", __func__); + + int cameraId = atoi(id); + if (cameraId < 0 || cameraId >= HAL_getNumberOfCameras()) { + LOGE("ERR(%s):Invalid camera ID %s", __func__, id); + return -EINVAL; + } + + if (g_cam_device) { + if (obj(g_cam_device)->getCameraId() == cameraId) { + LOGV("DEBUG(%s):returning existing camera ID %s", __func__, id); + goto done; + } else { + LOGE("ERR(%s):Cannot open camera %d. camera %d is already running!", + __func__, cameraId, obj(g_cam_device)->getCameraId()); + return -ENOSYS; + } + } + + g_cam_device = (camera_device_t *)malloc(sizeof(camera_device_t)); + if (!g_cam_device) + return -ENOMEM; + + g_cam_device->common.tag = HARDWARE_DEVICE_TAG; + g_cam_device->common.version = 1; + g_cam_device->common.module = const_cast<hw_module_t *>(module); + g_cam_device->common.close = HAL_camera_device_close; + + g_cam_device->ops = &camera_device_ops; + + LOGV("DEBUG(%s):open camera %s", __func__, id); + + g_cam_device->priv = new ExynosCameraHWInterface(cameraId, g_cam_device); + +done: + *device = (hw_device_t *)g_cam_device; + LOGV("DEBUG(%s):opened camera %s (%p)", __func__, id, *device); + return 0; +} + +static hw_module_methods_t camera_module_methods = { + open : HAL_camera_device_open +}; + +extern "C" { + struct camera_module HAL_MODULE_INFO_SYM = { + common : { + tag : HARDWARE_MODULE_TAG, + version_major : 1, + version_minor : 0, + id : CAMERA_HARDWARE_MODULE_ID, + name : "orion camera HAL", + author : "Samsung Corporation", + methods : &camera_module_methods, + }, + get_number_of_cameras : HAL_getNumberOfCameras, + get_camera_info : HAL_getCameraInfo + }; +} + +}; // namespace android diff --git a/libcamera/ExynosCameraHWInterface.h b/libcamera/ExynosCameraHWInterface.h new file mode 100644 index 0000000..53ac270 --- /dev/null +++ b/libcamera/ExynosCameraHWInterface.h @@ -0,0 +1,328 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** Copyright 2010, Samsung Electronics Co. LTD +** +** 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 ExynosCameraHWInterface.h + * \brief hearder file for Android Camera HAL + * \author thun.hwang(thun.hwang@samsung.com) + * \date 2010/06/03 + * + * <b>Revision History: </b> + * - 2011/12/31 : thun.hwang(thun.hwang@samsung.com) \n + * Initial version + * + * - 2012/03/14 : sangwoo.park(sw5771.park@samsung.com) \n + * Change file, class name to ExynosXXX. + * + */ + +#ifndef EXYNOS_CAMERA_HW_INTERFACE_H + +#include <utils/threads.h> +#include <utils/RefBase.h> +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryHeapBaseIon.h> +#include <hardware/camera.h> +#include <hardware/gralloc.h> +#include <camera/Camera.h> +#include <camera/CameraParameters.h> +#include <media/stagefright/MetadataBufferType.h> + +#include "gralloc_priv.h" + +#include "exynos_format.h" +#include "csc.h" +#include "ExynosCamera.h" + +#include <fcntl.h> +#include <sys/mman.h> + +#define USE_EGL (1) + +#define NUM_OF_PREVIEW_BUF (8) +#define NUM_OF_VIDEO_BUF (8) +#define NUM_OF_PICTURE_BUF (6) +#define NUM_OF_WAITING_PUT_PICTURE_BUF (1) + +#define NUM_OF_DETECTED_FACES (32) + +namespace android { + +class ExynosCameraHWInterface : public virtual RefBase { +public: + ExynosCameraHWInterface(int cameraId, camera_device_t *dev); + virtual ~ExynosCameraHWInterface(); + + virtual status_t setPreviewWindow(preview_stream_ops *w); + virtual void setCallbacks(camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user); + + virtual void enableMsgType(int32_t msgType); + virtual void disableMsgType(int32_t msgType); + virtual bool msgTypeEnabled(int32_t msgType); + + virtual status_t startPreview(); + virtual void stopPreview(); + virtual bool previewEnabled(); + + virtual status_t storeMetaDataInBuffers(bool enable); + + virtual status_t startRecording(); + virtual void stopRecording(); + virtual bool recordingEnabled(); + virtual void releaseRecordingFrame(const void *opaque); + + virtual status_t autoFocus(); + virtual status_t cancelAutoFocus(); + + virtual status_t takePicture(); + virtual status_t cancelPicture(); + + virtual status_t setParameters(const CameraParameters& params); + virtual CameraParameters getParameters() const; + virtual status_t sendCommand(int32_t command, int32_t arg1, int32_t arg2); + + virtual void release(); + + virtual status_t dump(int fd) const; + + inline int getCameraId() const; + +private: + class PreviewThread : public Thread { + ExynosCameraHWInterface *mHardware; + public: + PreviewThread(ExynosCameraHWInterface *hw): + Thread(false), + mHardware(hw) { } + virtual void onFirstRef() { + //run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY); + run("CameraPreviewThread", PRIORITY_DEFAULT); + } + virtual bool threadLoop() { + mHardware->m_previewThreadFuncWrapper(); + return false; + } + }; + + class VideoThread : public Thread { + ExynosCameraHWInterface *mHardware; + public: + VideoThread(ExynosCameraHWInterface *hw): + Thread(false), + mHardware(hw) { } + virtual void onFirstRef() { + run("CameraVideoThread", PRIORITY_DEFAULT); + } + virtual bool threadLoop() { + mHardware->m_videoThreadFuncWrapper(); + return false; + } + }; + + class PictureThread : public Thread { + ExynosCameraHWInterface *mHardware; + public: + PictureThread(ExynosCameraHWInterface *hw): + Thread(false), + mHardware(hw) { } + virtual bool threadLoop() { + mHardware->m_pictureThreadFunc(); + return false; + } + }; + + class AutoFocusThread : public Thread { + ExynosCameraHWInterface *mHardware; + public: + AutoFocusThread(ExynosCameraHWInterface *hw): Thread(false), mHardware(hw) { } + virtual void onFirstRef() { + run("CameraAutoFocusThread", PRIORITY_DEFAULT); + } + virtual bool threadLoop() { + mHardware->m_autoFocusThreadFunc(); + return true; + } + }; + +private: + void m_initDefaultParameters(int cameraId); + + bool m_startPreviewInternal(void); + void m_stopPreviewInternal(void); + + bool m_previewThreadFuncWrapper(void); + bool m_previewThreadFunc(void); + bool m_videoThreadFuncWrapper(void); + bool m_videoThreadFunc(void); + bool m_autoFocusThreadFunc(void); + + bool m_startPictureInternal(void); + bool m_stopPictureInternal(void); + bool m_pictureThreadFunc(void); + + int m_saveJpeg(unsigned char *real_jpeg, int jpeg_size); + void m_savePostView(const char *fname, uint8_t *buf, + uint32_t size); + int m_decodeInterleaveData(unsigned char *pInterleaveData, + int interleaveDataSize, + int yuvWidth, + int yuvHeight, + int *pJpegSize, + void *pJpegData, + void *pYuvData); + bool m_YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight); + bool m_scaleDownYuv422(char *srcBuf, uint32_t srcWidth, + uint32_t srcHight, char *dstBuf, + uint32_t dstWidth, uint32_t dstHight); + + bool m_checkVideoStartMarker(unsigned char *pBuf); + bool m_checkEOIMarker(unsigned char *pBuf); + bool m_findEOIMarkerInJPEG(unsigned char *pBuf, + int dwBufSize, int *pnJPEGsize); + bool m_splitFrame(unsigned char *pFrame, int dwSize, + int dwJPEGLineLength, int dwVideoLineLength, + int dwVideoHeight, void *pJPEG, + int *pdwJPEGSize, void *pVideo, + int *pdwVideoSize); + void m_setSkipFrame(int frame); + bool m_isSupportedPreviewSize(const int width, const int height) const; + + void m_getAlignedYUVSize(int colorFormat, int w, int h, ExynosBuffer *buf); + + bool m_getResolutionList(String8 & string8Buf, char * strBuf, int w, int h); + + bool m_getZoomRatioList(String8 & string8Buf, char * strBuf, int maxZoom, int start, int end); + + int m_bracketsStr2Ints(char *str, int num, ExynosRect2 *rect2s, int *weights); + bool m_subBracketsStr2Ints(int num, char *str, int *arr); + bool m_getRatioSize(int src_w, int src_h, + int dst_w, int dst_h, + int *crop_x, int *crop_y, + int *crop_w, int *crop_h, + int zoom); + int m_calibratePosition(int w, int new_w, int x); +#ifdef LOG_NDEBUG + bool m_fileDump(char *filename, void *srcBuf, uint32_t size); +#endif + +private: + sp<PreviewThread> m_previewThread; + sp<VideoThread> m_videoThread; + sp<AutoFocusThread> m_autoFocusThread; + sp<PictureThread> m_pictureThread; + + /* used by auto focus thread to block until it's told to run */ + mutable Mutex m_focusLock; + mutable Condition m_focusCondition; + bool m_exitAutoFocusThread; + + /* used by preview thread to block until it's told to run */ + mutable Mutex m_previewLock; + mutable Condition m_previewCondition; + mutable Condition m_previewStoppedCondition; + bool m_previewRunning; + bool m_exitPreviewThread; + bool m_previewStartDeferred; + + mutable Mutex m_videoLock; + mutable Condition m_videoCondition; + mutable Condition m_videoStoppedCondition; + bool m_videoRunning; + bool m_videoStart; + bool m_exitVideoThread; + bool m_recordingHint; + + void *m_grallocVirtAddr[NUM_OF_PREVIEW_BUF]; + int m_matchedGrallocIndex[NUM_OF_PREVIEW_BUF]; + ExynosBuffer m_pictureBuf; + ExynosBuffer copy_previewBuf; + + struct ExynosBufferQueue { + ExynosBuffer buf; + ExynosBufferQueue *next; + }; + + ExynosBufferQueue *m_oldPictureBufQueueHead; + ExynosBufferQueue m_oldPictureBufQueue[NUM_OF_PICTURE_BUF]; + mutable Mutex m_pictureLock; + mutable Condition m_pictureCondition; + bool m_pictureRunning; + bool m_captureInProgress; + int m_numOfAvaliblePictureBuf; + + ExynosRect m_orgPreviewRect; + ExynosRect m_orgPictureRect; + ExynosRect m_orgVideoRect; + + void *m_exynosPreviewCSC; + void *m_exynosPictureCSC; + void *m_exynosVideoCSC; + + preview_stream_ops *m_previewWindow; + + /* used to guard threading state */ + mutable Mutex m_stateLock; + + CameraParameters m_params; + CameraParameters m_internalParams; + + camera_memory_t *m_previewHeap[NUM_OF_PREVIEW_BUF]; + buffer_handle_t *m_previewBufHandle[NUM_OF_PREVIEW_BUF]; + int m_previewStride[NUM_OF_PREVIEW_BUF]; + bool m_avaliblePreviewBufHandle[NUM_OF_PREVIEW_BUF]; + bool m_flagGrallocLocked[NUM_OF_PREVIEW_BUF]; + int m_minUndequeuedBufs; + int m_numOfAvailableVideoBuf; + int m_cntVideoBuf; + + camera_memory_t *m_videoHeap[NUM_OF_VIDEO_BUF]; + camera_memory_t *m_resizedVideoHeap[NUM_OF_VIDEO_BUF]; + camera_memory_t *m_pictureHeap[NUM_OF_PICTURE_BUF]; + camera_memory_t *m_rawHeap; + + camera_frame_metadata_t m_frameMetadata; + camera_face_t m_faces[NUM_OF_DETECTED_FACES]; + bool m_faceDetected; + + ExynosCamera *m_secCamera; + + mutable Mutex m_skipFrameLock; + int m_skipFrame; + + camera_notify_callback m_notifyCb; + camera_data_callback m_dataCb; + camera_data_timestamp_callback m_dataCbTimestamp; + camera_request_memory m_getMemoryCb; + void *m_callbackCookie; + + int32_t m_msgEnabled; + + Vector<Size> m_supportedPreviewSizes; + + camera_device_t *m_halDevice; + static gralloc_module_t const* m_grallocHal; +}; + +}; // namespace android + +#endif diff --git a/libcamera/ExynosExif.h b/libcamera/ExynosExif.h new file mode 100644 index 0000000..5437b68 --- /dev/null +++ b/libcamera/ExynosExif.h @@ -0,0 +1,231 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 The Android Open Source 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. + */ +#ifndef EXYNOS_EXIF_H_ +#define EXYNOS_EXIF_H_ + +#include <math.h> + +#define EXIF_LOG2(x) (log((double)(x)) / log(2.0)) +#define APEX_FNUM_TO_APERTURE(x) ((int)(EXIF_LOG2((double)(x)) * 2 + 0.5)) +#define APEX_EXPOSURE_TO_SHUTTER(x) ((x) >= 1 ? \ + (int)(-(EXIF_LOG2((double)(x)) + 0.5)) : \ + (int)(-(EXIF_LOG2((double)(x)) - 0.5))) +#define APEX_ISO_TO_FILMSENSITIVITY(x) ((int)(EXIF_LOG2((x) / 3.125) + 0.5)) + +#define NUM_SIZE 2 +#define IFD_SIZE 12 +#define OFFSET_SIZE 4 + +#define NUM_0TH_IFD_TIFF 10 +#define NUM_0TH_IFD_EXIF 22 +#define NUM_0TH_IFD_GPS 10 +#define NUM_1TH_IFD_TIFF 9 + +/* Type */ +#define EXIF_TYPE_BYTE 1 +#define EXIF_TYPE_ASCII 2 +#define EXIF_TYPE_SHORT 3 +#define EXIF_TYPE_LONG 4 +#define EXIF_TYPE_RATIONAL 5 +#define EXIF_TYPE_UNDEFINED 7 +#define EXIF_TYPE_SLONG 9 +#define EXIF_TYPE_SRATIONAL 10 + +#define EXIF_FILE_SIZE 28800 + +/* 0th IFD TIFF Tags */ +#define EXIF_TAG_IMAGE_WIDTH 0x0100 +#define EXIF_TAG_IMAGE_HEIGHT 0x0101 +#define EXIF_TAG_MAKE 0x010f +#define EXIF_TAG_MODEL 0x0110 +#define EXIF_TAG_ORIENTATION 0x0112 +#define EXIF_TAG_SOFTWARE 0x0131 +#define EXIF_TAG_DATE_TIME 0x0132 +#define EXIF_TAG_YCBCR_POSITIONING 0x0213 +#define EXIF_TAG_EXIF_IFD_POINTER 0x8769 +#define EXIF_TAG_GPS_IFD_POINTER 0x8825 + +/* 0th IFD Exif Private Tags */ +#define EXIF_TAG_EXPOSURE_TIME 0x829A +#define EXIF_TAG_FNUMBER 0x829D +#define EXIF_TAG_EXPOSURE_PROGRAM 0x8822 +#define EXIF_TAG_ISO_SPEED_RATING 0x8827 +#define EXIF_TAG_EXIF_VERSION 0x9000 +#define EXIF_TAG_DATE_TIME_ORG 0x9003 +#define EXIF_TAG_DATE_TIME_DIGITIZE 0x9004 +#define EXIF_TAG_SHUTTER_SPEED 0x9201 +#define EXIF_TAG_APERTURE 0x9202 +#define EXIF_TAG_BRIGHTNESS 0x9203 +#define EXIF_TAG_EXPOSURE_BIAS 0x9204 +#define EXIF_TAG_MAX_APERTURE 0x9205 +#define EXIF_TAG_METERING_MODE 0x9207 +#define EXIF_TAG_FLASH 0x9209 +#define EXIF_TAG_FOCAL_LENGTH 0x920A +#define EXIF_TAG_USER_COMMENT 0x9286 +#define EXIF_TAG_COLOR_SPACE 0xA001 +#define EXIF_TAG_PIXEL_X_DIMENSION 0xA002 +#define EXIF_TAG_PIXEL_Y_DIMENSION 0xA003 +#define EXIF_TAG_EXPOSURE_MODE 0xA402 +#define EXIF_TAG_WHITE_BALANCE 0xA403 +#define EXIF_TAG_SCENCE_CAPTURE_TYPE 0xA406 + +/* 0th IFD GPS Info Tags */ +#define EXIF_TAG_GPS_VERSION_ID 0x0000 +#define EXIF_TAG_GPS_LATITUDE_REF 0x0001 +#define EXIF_TAG_GPS_LATITUDE 0x0002 +#define EXIF_TAG_GPS_LONGITUDE_REF 0x0003 +#define EXIF_TAG_GPS_LONGITUDE 0x0004 +#define EXIF_TAG_GPS_ALTITUDE_REF 0x0005 +#define EXIF_TAG_GPS_ALTITUDE 0x0006 +#define EXIF_TAG_GPS_TIMESTAMP 0x0007 +#define EXIF_TAG_GPS_PROCESSING_METHOD 0x001B +#define EXIF_TAG_GPS_DATESTAMP 0x001D + +/* 1th IFD TIFF Tags */ +#define EXIF_TAG_COMPRESSION_SCHEME 0x0103 +#define EXIF_TAG_X_RESOLUTION 0x011A +#define EXIF_TAG_Y_RESOLUTION 0x011B +#define EXIF_TAG_RESOLUTION_UNIT 0x0128 +#define EXIF_TAG_JPEG_INTERCHANGE_FORMAT 0x0201 +#define EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN 0x0202 + +typedef enum { + EXIF_ORIENTATION_UP = 1, + EXIF_ORIENTATION_90 = 6, + EXIF_ORIENTATION_180 = 3, + EXIF_ORIENTATION_270 = 8, +} ExifOrientationType; + +typedef enum { + EXIF_SCENE_STANDARD, + EXIF_SCENE_LANDSCAPE, + EXIF_SCENE_PORTRAIT, + EXIF_SCENE_NIGHT, +} CamExifSceneCaptureType; + +typedef enum { + EXIF_METERING_UNKNOWN, + EXIF_METERING_AVERAGE, + EXIF_METERING_CENTER, + EXIF_METERING_SPOT, + EXIF_METERING_MULTISPOT, + EXIF_METERING_PATTERN, + EXIF_METERING_PARTIAL, + EXIF_METERING_OTHER = 255, +} CamExifMeteringModeType; + +typedef enum { + EXIF_EXPOSURE_AUTO, + EXIF_EXPOSURE_MANUAL, + EXIF_EXPOSURE_AUTO_BRACKET, +} CamExifExposureModeType; + +typedef enum { + EXIF_WB_AUTO, + EXIF_WB_MANUAL, +} CamExifWhiteBalanceType; + +/* Values */ +#define EXIF_DEF_MAKER "SAMSUNG" +#define EXIF_DEF_MODEL "SAMSUNG" +#define EXIF_DEF_SOFTWARE "SAMSUNG" +#define EXIF_DEF_EXIF_VERSION "0220" +#define EXIF_DEF_USERCOMMENTS "User comments" + +#define EXIF_DEF_YCBCR_POSITIONING 1 /* centered */ +#define EXIF_DEF_FNUMBER_NUM 26 /* 2.6 */ +#define EXIF_DEF_FNUMBER_DEN 10 +#define EXIF_DEF_EXPOSURE_PROGRAM 3 /* aperture priority */ +#define EXIF_DEF_FOCAL_LEN_NUM 278 /* 2.78mm */ +#define EXIF_DEF_FOCAL_LEN_DEN 100 +#define EXIF_DEF_FLASH 0 /* O: off, 1: on*/ +#define EXIF_DEF_COLOR_SPACE 1 +#define EXIF_DEF_EXPOSURE_MODE EXIF_EXPOSURE_AUTO +#define EXIF_DEF_APEX_DEN 10 + +#define EXIF_DEF_COMPRESSION 6 +#define EXIF_DEF_RESOLUTION_NUM 72 +#define EXIF_DEF_RESOLUTION_DEN 1 +#define EXIF_DEF_RESOLUTION_UNIT 2 /* inches */ + +typedef struct { + uint32_t num; + uint32_t den; +} rational_t; + +typedef struct { + int32_t num; + int32_t den; +} srational_t; + +typedef struct { + bool enableGps; + bool enableThumb; + + unsigned char maker[32]; + unsigned char model[32]; + unsigned char software[32]; + unsigned char exif_version[4]; + unsigned char date_time[20]; + unsigned char user_comment[150]; + + uint32_t width; + uint32_t height; + uint32_t widthThumb; + uint32_t heightThumb; + + uint16_t orientation; + uint16_t ycbcr_positioning; + uint16_t exposure_program; + uint16_t iso_speed_rating; + uint16_t metering_mode; + uint16_t flash; + uint16_t color_space; + uint16_t exposure_mode; + uint16_t white_balance; + uint16_t scene_capture_type; + + rational_t exposure_time; + rational_t fnumber; + rational_t aperture; + rational_t max_aperture; + rational_t focal_length; + + srational_t shutter_speed; + srational_t brightness; + srational_t exposure_bias; + + unsigned char gps_latitude_ref[2]; + unsigned char gps_longitude_ref[2]; + + uint8_t gps_version_id[4]; + uint8_t gps_altitude_ref; + + rational_t gps_latitude[3]; + rational_t gps_longitude[3]; + rational_t gps_altitude; + rational_t gps_timestamp[3]; + unsigned char gps_datestamp[11]; + unsigned char gps_processing_method[100]; + + rational_t x_resolution; + rational_t y_resolution; + uint16_t resolution_unit; + uint16_t compression_scheme; +} exif_attribute_t; + +#endif /* EXYNOS_EXIF_H_ */ diff --git a/libcamera/ExynosJpegEncoderForCamera.cpp b/libcamera/ExynosJpegEncoderForCamera.cpp new file mode 100644 index 0000000..54b8864 --- /dev/null +++ b/libcamera/ExynosJpegEncoderForCamera.cpp @@ -0,0 +1,1047 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 The Android Open Source 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. + */ + +#include <utils/Log.h> + +#include "ExynosJpegEncoderForCamera.h" + +static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + +#define JPEG_ERROR_LOG(fmt,...) + +#define THUMBNAIL_IMAGE_PIXEL_SIZE (4) +#define MAX_JPG_WIDTH (8192) +#define MAX_JPG_HEIGHT (8192) + +#define MAX_INPUT_BUFFER_PLANE_NUM (2) +#define MAX_OUTPUT_BUFFER_PLANE_NUM (2) + +ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera() +{ + m_flagCreate = false; + m_jpegMain = NULL; + m_jpegThumb = NULL; + m_thumbnailW = 0; + m_thumbnailH = 0; + m_thumbnailQuality = JPEG_THUMBNAIL_QUALITY; + m_pThumbInputBuffer = NULL; + m_pThumbOutputBuffer = NULL; +#ifdef JPEG_WA_FOR_PAGEFAULT + m_pJpegInputBuffer = 0; + m_pExtInBuf = NULL; + m_iInBufSize = 0; +#endif // JPEG_WA_FOR_PAGEFAULT + m_ionJpegClient = 0;; + m_ionThumbInBuffer = 0; + m_ionThumbOutBuffer = 0; +#ifdef JPEG_WA_FOR_PAGEFAULT + m_ionJpegInBuffer = 0;; +#endif // JPEG_WA_FOR_PAGEFAULT +} + +ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera() +{ + if (m_flagCreate == true) { + this->destroy(); + } +} + +bool ExynosJpegEncoderForCamera::flagCreate(void) +{ + return m_flagCreate; +} + +int ExynosJpegEncoderForCamera::create(void) +{ + int ret = ERROR_NONE; + if (m_flagCreate == true) { + return ERROR_ALREADY_CREATE; + } + + if (m_jpegMain == NULL) { + m_jpegMain = new ExynosJpegEncoder; + + if (m_jpegMain == NULL) { + JPEG_ERROR_LOG("ERR(%s):Cannot create ExynosJpegEncoder class\n", __func__); + return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; + } + + ret = m_jpegMain->create(); + if (ret) { + return ret; + } + + ret = m_jpegMain->setCache(JPEG_CACHE_ON); + + if (ret) { + m_jpegMain->destroy(); + return ret; + } + } + + m_flagCreate = true; + + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::destroy(void) +{ + if (m_flagCreate == false) { + return ERROR_ALREADY_DESTROY; + } + + if (m_jpegMain != NULL) { + m_jpegMain->destroy(); + delete m_jpegMain; + m_jpegMain = NULL; + } + + if (m_jpegThumb != NULL) { + int iSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4; + +#ifdef JPEG_WA_FOR_PAGEFAULT + iSize += JPEG_WA_BUFFER_SIZE; + freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, m_iInBufSize); +#endif //JPEG_WA_FOR_PAGEFAULT + + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iSize); + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iSize); + + if (m_ionJpegClient != 0) { + ion_client_destroy(m_ionJpegClient); + m_ionJpegClient = 0; + } + + m_jpegThumb->destroy(); + delete m_jpegThumb; + m_jpegThumb = NULL; + } + + m_flagCreate = false; + m_thumbnailW = 0; + m_thumbnailH = 0; + m_thumbnailQuality = JPEG_THUMBNAIL_QUALITY; + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::setSize(int w, int h) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setSize(w, h); +} + + +int ExynosJpegEncoderForCamera::setQuality(int quality) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setQuality(quality); +} + +int ExynosJpegEncoderForCamera::setColorFormat(int colorFormat) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setColorFormat(colorFormat); +} + +int ExynosJpegEncoderForCamera::setJpegFormat(int jpegFormat) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setJpegFormat(jpegFormat); +} + +int ExynosJpegEncoderForCamera::updateConfig(void) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->updateConfig(); +} + +int ExynosJpegEncoderForCamera::setInBuf(char **buf, int *size) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + if (buf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (size<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + int ret = ERROR_NONE; + +#ifdef JPEG_WA_FOR_PAGEFAULT + size += JPEG_WA_BUFFER_SIZE; + + freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size); + + if (m_ionJpegClient == 0) { + m_ionJpegClient = ion_client_create(); + if (m_ionJpegClient < 0) { + JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__, size); + m_ionJpegClient = 0; + return ret; + } + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size); + if (ret != ERROR_NONE) { + return ret; + } + + ret = m_jpegMain->setInBuf(&m_pJpegInputBuffer, &size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return ret; + } + m_iInBufSize = size; + + m_pExtInBuf = buf; + +#else // NO JPEG_WA_FOR_PAGEFAULT + ret = m_jpegMain->setInBuf(buf, size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return ret; + } +#endif // JPEG_WA_FOR_PAGEFAULT + + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::setOutBuf(char *buf, int size) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + if (buf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (size<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + int ret = ERROR_NONE; + ret = m_jpegMain->setOutBuf(buf, size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG output buffer!!\n", __func__); + return ret; + } + + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo) +{ + int ret = ERROR_NONE; + unsigned char *exifOut = NULL; + + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + +#ifdef JPEG_WA_FOR_PAGEFAULT + memcpy(m_pJpegInputBuffer, m_pExtInBuf, m_iInBufSize-JPEG_WA_BUFFER_SIZE); +#endif // JPEG_WA_FOR_PAGEFAULT + + ret = m_jpegMain->encode(); + if (ret) { + JPEG_ERROR_LOG("encode failed\n"); + return ret; + } + + int iJpegSize = m_jpegMain->getJpegSize(); + + if (iJpegSize<=0) { + JPEG_ERROR_LOG("%s:: output_size is too small(%d)!!\n", __func__, iJpegSize); + return ERROR_OUT_BUFFER_SIZE_TOO_SMALL; + } + + int iOutputSize = 0; + char *pcJpegBuffer = NULL; + ret = m_jpegMain->getOutBuf((char **)&pcJpegBuffer, &iOutputSize); + if (ret != ERROR_NONE) { + return ret; + } + + if (pcJpegBuffer == NULL) { + JPEG_ERROR_LOG("%s::pcJpegBuffer is null!!\n", __func__); + return ERROR_OUT_BUFFER_CREATE_FAIL; + } + + if (pcJpegBuffer[0] == NULL) { + JPEG_ERROR_LOG("%s::pcJpegBuffer[0] is null!!\n", __func__); + return ERROR_OUT_BUFFER_CREATE_FAIL; + } + + if (exifInfo != NULL) { + unsigned int thumbLen, exifLen; + + unsigned int bufSize = 0; + if (exifInfo->enableThumb) { + if (encodeThumbnail(&thumbLen)) { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } else { + if (thumbLen > EXIF_LIMIT_SIZE) { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } + else { + bufSize = EXIF_FILE_SIZE + thumbLen; + } + } + } else { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } + + exifOut = new unsigned char[bufSize]; + if (exifOut == NULL) { + JPEG_ERROR_LOG("%s::Failed to allocate for exifOut\n", __func__); + delete[] exifOut; + return ERROR_EXIFOUT_ALLOC_FAIL; + } + memset(exifOut, 0, bufSize); + + if (makeExif (exifOut, exifInfo, &exifLen)) { + JPEG_ERROR_LOG("%s::Failed to make EXIF\n", __func__); + delete[] exifOut; + return ERROR_MAKE_EXIF_FAIL; + } + + if (exifLen <= EXIF_LIMIT_SIZE) { + memmove(pcJpegBuffer+exifLen+2, pcJpegBuffer+2, iJpegSize - 2); + memcpy(pcJpegBuffer+2, exifOut, exifLen); + iJpegSize += exifLen; + } + + delete[] exifOut; + } + + *size = iJpegSize; + + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::makeExif (unsigned char *exifOut, + exif_attribute_t *exifInfo, + unsigned int *size, + bool useMainbufForThumb) +{ + unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset; + unsigned int tmp, LongerTagOffest = 0, exifSizeExceptThumb; + pApp1Start = pCur = exifOut; + + //2 Exif Identifier Code & TIFF Header + pCur += 4; // Skip 4 Byte for APP1 marker and length + unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + memcpy(pCur, ExifIdentifierCode, 6); + pCur += 6; + + /* Byte Order - little endian, Offset of IFD - 0x00000008.H */ + unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; + memcpy(pCur, TiffHeader, 8); + pIfdStart = pCur; + pCur += 8; + + //2 0th IFD TIFF Tags + if (exifInfo->enableGps) + tmp = NUM_0TH_IFD_TIFF; + else + tmp = NUM_0TH_IFD_TIFF - 1; + + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT, + 1, exifInfo->ycbcr_positioning); + writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); + if (exifInfo->enableGps) { + pGpsIfdPtr = pCur; + pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer + } + + pNextIfdOffset = pCur; // Skip a offset size for next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD Exif Private Tags + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_0TH_IFD_EXIF; + memcpy(pCur, &tmp , NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL, + 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL, + 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT, + 1, exifInfo->exposure_program); + writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT, + 1, exifInfo->iso_speed_rating); + writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED, + 4, exifInfo->exif_version); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, + 1, exifInfo->metering_mode); + writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, + 1, exifInfo->flash); + writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, + 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart); + char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 }; + int commentsLen = strlen((char *)exifInfo->user_comment) + 1; + memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen); + memcpy(exifInfo->user_comment, code, sizeof(code)); + writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED, + commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT, + 1, exifInfo->color_space); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG, + 1, exifInfo->exposure_mode); + writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG, + 1, exifInfo->white_balance); + writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG, + 1, exifInfo->scene_capture_type); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD GPS Info Tags + if (exifInfo->enableGps) { + writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + if (exifInfo->gps_processing_method[0] == 0) { + // don't create GPS_PROCESSING_METHOD tag if there isn't any + tmp = NUM_0TH_IFD_GPS - 1; + } else { + tmp = NUM_0TH_IFD_GPS; + } + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE, + 4, exifInfo->gps_version_id); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_latitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_longitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE, + 1, exifInfo->gps_altitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart); + tmp = strlen((char*)exifInfo->gps_processing_method); + if (tmp > 0) { + if (tmp > 100) { + tmp = 100; + } + unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)]; + memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); + memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp); + writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED, + tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart); + } + writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII, + 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + } + + //2 1th IFD TIFF Tags + char *thumbBuf = NULL; + unsigned int thumbSize = 0; + int ret = ERROR_NONE; + + if (useMainbufForThumb) { + if (m_jpegMain) { + ret = m_jpegMain->getOutBuf((char **)&thumbBuf, (int *)&thumbSize); + if (ret != ERROR_NONE) { + thumbBuf = NULL; + } + thumbSize = (unsigned int)m_jpegMain->getJpegSize(); + } + } else { + if (m_jpegThumb) { + ret = m_jpegThumb->getOutBuf((char **)&thumbBuf, (int *)&thumbSize); + if (ret != ERROR_NONE) { + thumbBuf = NULL; + } + thumbSize = (unsigned int)m_jpegThumb->getJpegSize(); + } + } + + if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize != 0)) { + exifSizeExceptThumb = tmp = LongerTagOffest; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_1TH_IFD_TIFF; + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->widthThumb); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->heightThumb); + writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT, + 1, exifInfo->compression_scheme); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT, + 1, exifInfo->resolution_unit); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG, + 1, LongerTagOffest); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG, + 1, thumbSize); + + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + memcpy(pIfdStart + LongerTagOffest, + thumbBuf, thumbSize); + LongerTagOffest += thumbSize; + if (LongerTagOffest > EXIF_LIMIT_SIZE) { + LongerTagOffest = exifSizeExceptThumb; + tmp = 0; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + } + } else { + tmp = 0; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + } + + unsigned char App1Marker[2] = { 0xff, 0xe1 }; + memcpy(pApp1Start, App1Marker, 2); + pApp1Start += 2; + + *size = 10 + LongerTagOffest; + tmp = *size - 2; // APP1 Maker isn't counted + unsigned char size_mm[2] = {(tmp >> 8) & 0xFF, tmp & 0xFF}; + memcpy(pApp1Start, size_mm, 2); + + return ERROR_NONE; +} + +/* + * private member functions +*/ +inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned int value) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, &value, 4); + *pCur += 4; +} + +inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue) +{ + char buf[4] = { 0,}; + + memcpy(buf, pValue, count); + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, buf, 4); + *pCur += 4; +} + +inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, count); + *offset += count; +} + +inline void ExynosJpegEncoderForCamera::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + rational_t *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, 8 * count); + *offset += 8 * count; +} + +int ExynosJpegEncoderForCamera::scaleDownYuv422(char **srcBuf, unsigned int srcW, unsigned int srcH, char **dstBuf, unsigned int dstW, unsigned int dstH) +{ + int step_x, step_y; + int src_y_start_pos, dst_pos, src_pos; + char *src_buf = srcBuf[0]; + char *dst_buf = dstBuf[0]; + + if (dstW & 0x01 || dstH & 0x01) { + return ERROR_INVALID_SCALING_WIDTH_HEIGHT; + } + + step_x = srcW / dstW; + step_y = srcH / dstH; + + unsigned int srcWStride = srcW * 2; + unsigned int stepXStride = step_x * 2; + + dst_pos = 0; + for (unsigned int y = 0; y < dstH; y++) { + src_y_start_pos = srcWStride * step_y * y; + + for (unsigned int x = 0; x < dstW; x += 2) { + src_pos = src_y_start_pos + (stepXStride * x); + + dst_buf[dst_pos++] = src_buf[src_pos ]; + dst_buf[dst_pos++] = src_buf[src_pos + 1]; + dst_buf[dst_pos++] = src_buf[src_pos + 2]; + dst_buf[dst_pos++] = src_buf[src_pos + 3]; + } + } + + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::scaleDownYuv422_2p(char **srcBuf, unsigned int srcW, unsigned int srcH, char **dstBuf, unsigned int dstW, unsigned int dstH) +{ + int32_t step_x, step_y; + int32_t src_y_start_pos, dst_pos, src_pos; + int32_t src_Y_offset; + char *src_buf; + char *dst_buf; + + if (dstW % 2 != 0 || dstH % 2 != 0) { + return ERROR_INVALID_SCALING_WIDTH_HEIGHT; + } + + step_x = srcW / dstW; + step_y = srcH / dstH; + + // Y scale down + src_buf = srcBuf[0]; + dst_buf = dstBuf[0]; + dst_pos = 0; + for (uint32_t y = 0; y < dstH; y++) { + src_y_start_pos = y * step_y * srcW; + + for (uint32_t x = 0; x < dstW; x++) { + src_pos = src_y_start_pos + (x * step_x); + + dst_buf[dst_pos++] = src_buf[src_pos]; + } + } + + // UV scale down + src_buf = srcBuf[1]; + dst_buf = dstBuf[1]; + dst_pos = 0; + for (uint32_t i = 0; i < dstH; i++) { + src_y_start_pos = i * step_y * srcW; + + for (uint32_t j = 0; j < dstW; j += 2) { + src_pos = src_y_start_pos + (j * step_x); + + dst_buf[dst_pos++] = src_buf[src_pos ]; + dst_buf[dst_pos++] = src_buf[src_pos + 1]; + } + } + + return ERROR_NONE; +} + +// thumbnail +int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) +{ + if (m_flagCreate == false) { + return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; + } + + if (w < 0 || MAX_JPG_WIDTH < w) { + return false; + } + + if (h < 0 || MAX_JPG_HEIGHT < h) { + return false; + } + + m_thumbnailW = w; + m_thumbnailH = h; + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) +{ + if (m_flagCreate == false) { + return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; + } + + if (quality < 1 || 100 < quality) { + return false; + } + + m_thumbnailQuality = quality; + return ERROR_NONE; +} + +int ExynosJpegEncoderForCamera::encodeThumbnail(unsigned int *size, bool useMain) +{ + int ret = ERROR_NONE; + + if (m_flagCreate == false) { + return ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL; + } + + // create jpeg thumbnail class + if (m_jpegThumb == NULL) { + m_jpegThumb = new ExynosJpegEncoder; + + if (m_jpegThumb == NULL) { + JPEG_ERROR_LOG("ERR(%s):Cannot open a jpeg device file\n", __func__); + return ERROR_CANNOT_CREATE_SEC_THUMB; + } + } + + ret = m_jpegThumb->create(); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail create\n", __func__); + return ret; + } + + ret = m_jpegThumb->setCache(JPEG_CACHE_ON); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail cache set\n", __func__); + return ret; + } + + void *pConfig = m_jpegMain->getJpegConfig(); + if (pConfig == NULL) { + JPEG_ERROR_LOG("ERR(%s):Fail getJpegConfig\n", __func__); + return ERROR_BUFFR_IS_NULL; + } + + ret = m_jpegThumb->setJpegConfig(pConfig); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setJpegConfig\n", __func__); + return ret; + } + + /* TODO: Currently we fix the thumbnail quality */ + ret = m_jpegThumb->setQuality(JPEG_THUMBNAIL_QUALITY); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setQuality\n", __func__); + return ret; + } + + ret = m_jpegThumb->setSize(m_thumbnailW, m_thumbnailH); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setSize\n", __func__); + return ret; + } + + int iThumbSize = sizeof(char)*m_thumbnailW*m_thumbnailH*THUMBNAIL_IMAGE_PIXEL_SIZE; + char *pcThumbInBuf[MAX_INPUT_BUFFER_PLANE_NUM]; + int iThumbInBufSize[MAX_INPUT_BUFFER_PLANE_NUM]; + switch (m_jpegMain->getColorFormat()) { + case V4L2_PIX_FMT_YUYV: + iThumbInBufSize[0] = m_thumbnailW*m_thumbnailH*2; + iThumbInBufSize[1] = 0; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + iThumbInBufSize[0] = m_thumbnailW*m_thumbnailH; + iThumbInBufSize[1] = m_thumbnailW*m_thumbnailH; + break; + default: + return ERROR_INVALID_COLOR_FORMAT; + } +#ifdef JPEG_WA_FOR_PAGEFAULT + iThumbSize += JPEG_WA_BUFFER_SIZE; +#endif //JPEG_WA_FOR_PAGEFAULT + + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize); + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize); + + if (m_ionJpegClient == 0) { + m_ionJpegClient = ion_client_create(); + if (m_ionJpegClient < 0) { + JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__, m_ionJpegClient); + m_ionJpegClient = 0; + return ret; + } + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize); + if (ret != ERROR_NONE) { + return ret; + } + + pcThumbInBuf[0] = m_pThumbInputBuffer; + pcThumbInBuf[1] = pcThumbInBuf[0] + iThumbInBufSize[0]; + + ret = m_jpegThumb->setInBuf(pcThumbInBuf, iThumbInBufSize); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setInBuf\n", __func__); + return ret; + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize); + if (ret != ERROR_NONE) { + return ret; + } + + ret = m_jpegThumb->setOutBuf((char *)m_pThumbOutputBuffer, iThumbSize); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setOutBuf\n", __func__); + return ret; + } + + ret = m_jpegThumb->updateConfig(); + if (ret) { + JPEG_ERROR_LOG("update config failed\n"); + return ret; + } + + if (useMain) { + int iTempWidth=0; + int iTempHeight=0; + char *pcMainInputBuf[MAX_INPUT_BUFFER_PLANE_NUM]; + char *pcThumbInputBuf[MAX_INPUT_BUFFER_PLANE_NUM]; + int iMainInputSize[MAX_INPUT_BUFFER_PLANE_NUM]; + int iThumbInputSize[MAX_INPUT_BUFFER_PLANE_NUM]; + int iTempColorformat = 0; + + iTempColorformat = m_jpegMain->getColorFormat(); + + ret = m_jpegMain->getSize(&iTempWidth, &iTempHeight); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail getSize\n", __func__); + return ret; + } + + ret = m_jpegMain->getInBuf(pcMainInputBuf, iMainInputSize, MAX_INPUT_BUFFER_PLANE_NUM); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail getInBuf\n", __func__); + return ret; + } + + ret = m_jpegThumb->getInBuf(pcThumbInputBuf, iThumbInputSize, MAX_INPUT_BUFFER_PLANE_NUM); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail getInBuf\n", __func__); + return ret; + } + + switch (iTempColorformat) { + case V4L2_PIX_FMT_YUYV: + ret = scaleDownYuv422(pcMainInputBuf, + iTempWidth, + iTempHeight, + pcThumbInputBuf, + m_thumbnailW, + m_thumbnailH); + break; + case V4L2_PIX_FMT_NV16: + ret = scaleDownYuv422_2p(pcMainInputBuf, + iTempWidth, + iTempHeight, + pcThumbInputBuf, + m_thumbnailW, + m_thumbnailH); + break; + default: + return ERROR_INVALID_COLOR_FORMAT; + break; + } + if (ret) { + JPEG_ERROR_LOG("%s::scaleDown(%d, %d, %d, %d) fail", __func__, iTempWidth, iTempHeight, m_thumbnailW, m_thumbnailH); + return ret; + } + } + else { + return ERROR_IMPLEMENT_NOT_YET; + } + + int outSizeThumb; + + ret = m_jpegThumb->encode(); + if (ret) { + JPEG_ERROR_LOG("encode failed\n"); + return ret; + } + + outSizeThumb = m_jpegThumb->getJpegSize(); + if (outSizeThumb<=0) { + JPEG_ERROR_LOG("jpeg size is too small\n"); + return ERROR_THUMB_JPEG_SIZE_TOO_SMALL; + } + + *size = (unsigned int)outSizeThumb; + + return ERROR_NONE; + +} + +int ExynosJpegEncoderForCamera::allocJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size) +{ + int ret = ERROR_NONE; + + if (ionClient == 0) { + JPEG_ERROR_LOG("[%s]ionClient is zero (%d)\n", __func__, ionClient); + return ERROR_BUFFR_IS_NULL; + } + + *ionBuffer = ion_alloc(ionClient, size, 0, ION_HEAP_SYSTEM_MASK); + if (*ionBuffer == -1) { + JPEG_ERROR_LOG("[%s]ion_alloc(%d) failed\n", __func__, size); + *ionBuffer = 0; + return ret; + } + + *buffer = (char *)ion_map(*ionBuffer, size, 0); + if (*buffer == MAP_FAILED) { + JPEG_ERROR_LOG("[%s]src ion map failed(%d)\n", __func__, size); + ion_free(*ionBuffer); + *ionBuffer = 0; + *buffer = NULL; + return ret; + } + + return ret; +} + +void ExynosJpegEncoderForCamera::freeJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size) +{ + if (ionClient == 0) { + return; + } + + if (*buffer != NULL) { + ion_unmap(*buffer, size); + *buffer = NULL; + } + + if (*ionBuffer != 0) { + ion_free(*ionBuffer); + *ionBuffer = 0; + } +} + diff --git a/libcamera/ExynosJpegEncoderForCamera.h b/libcamera/ExynosJpegEncoderForCamera.h new file mode 100644 index 0000000..2a4e9e2 --- /dev/null +++ b/libcamera/ExynosJpegEncoderForCamera.h @@ -0,0 +1,159 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2010 The Android Open Source 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. + */ + +#ifndef EXYNOS_JPEG_ENCODER_FOR_CAMERA_H_ +#define EXYNOS_JPEG_ENCODER_FOR_CAMERA_H_ + +#include "ExynosExif.h" + +#include "ExynosJpegApi.h" + +#include <sys/mman.h> +#include "ion.h" + +#define JPEG_THUMBNAIL_QUALITY 60 +#define EXIF_LIMIT_SIZE 64*1024 +//#define JPEG_WA_FOR_PAGEFAULT +#define JPEG_WA_BUFFER_SIZE 64 + +class ExynosJpegEncoderForCamera { +public : + ; + enum ERROR { + ERROR_ALREADY_CREATE = -0x200, + ERROR_CANNOT_CREATE_EXYNOS_JPEG_ENC_HAL, + ERROR_NOT_YET_CREATED, + ERROR_ALREADY_DESTROY, + ERROR_INPUT_DATA_SIZE_TOO_LARGE, + ERROR_OUT_BUFFER_SIZE_TOO_SMALL, + ERROR_EXIFOUT_ALLOC_FAIL, + ERROR_MAKE_EXIF_FAIL, + ERROR_INVALID_SCALING_WIDTH_HEIGHT, + ERROR_CANNOT_CREATE_SEC_THUMB, + ERROR_THUMB_JPEG_SIZE_TOO_SMALL, + ERROR_IMPLEMENT_NOT_YET, + ERROR_JPEG_DEVICE_ALREADY_CREATE = -0x100, + ERROR_CANNOT_OPEN_JPEG_DEVICE, + ERROR_JPEG_DEVICE_ALREADY_CLOSED, + ERROR_JPEG_DEVICE_ALREADY_DESTROY, + ERROR_JPEG_DEVICE_NOT_CREATE_YET, + ERROR_INVALID_COLOR_FORMAT, + ERROR_INVALID_JPEG_FORMAT, + ERROR_JPEG_CONFIG_POINTER_NULL, + ERROR_INVALID_JPEG_CONFIG, + ERROR_IN_BUFFER_CREATE_FAIL, + ERROR_OUT_BUFFER_CREATE_FAIL, + ERROR_EXCUTE_FAIL, + ERROR_JPEG_SIZE_TOO_SMALL, + ERROR_CANNOT_CHANGE_CACHE_SETTING, + ERROR_SIZE_NOT_SET_YET, + ERROR_BUFFR_IS_NULL, + ERROR_BUFFER_TOO_SMALL, + ERROR_GET_SIZE_FAIL, + ERROR_REQBUF_FAIL, + ERROR_INVALID_V4l2_BUF_TYPE = -0x80, + ERROR_MMAP_FAILED, + ERROR_FAIL, + ERROR_NONE = 0 + }; + + ExynosJpegEncoderForCamera(); + virtual ~ExynosJpegEncoderForCamera(); + + bool flagCreate(); + int create(void); + int destroy(void); + + int setSize(int w, int h); + int setQuality(int quality); + int setColorFormat(int colorFormat); + int setJpegFormat(int jpegFormat); + + int updateConfig(void); + + int setInBuf(char **buf, int *size); + int setOutBuf(char *buf, int size); + + int encode(int *size, exif_attribute_t *exifInfo); + + int setThumbnailSize(int w, int h); + int setThumbnailQuality(int quality); + + int makeExif(unsigned char *exifOut, + exif_attribute_t *exifIn, + unsigned int *size, + bool useMainbufForThumb = false); + +private: + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + uint32_t value); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + rational_t *pValue, + unsigned int *offset, + unsigned char *start); + inline void writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue, + unsigned int *offset, + unsigned char *start); + int scaleDownYuv422(char **srcBuf, unsigned int srcW, unsigned int srcH, + char **dstBuf, unsigned int dstW, unsigned int dstH); + int scaleDownYuv422_2p(char **srcBuf, unsigned int srcW, unsigned int srcH, + char **dstBuf, unsigned int dstW, unsigned int dstH); + // thumbnail + int encodeThumbnail(unsigned int *size, bool useMain = true); + + int allocJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size); + void freeJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size); + + bool m_flagCreate; + + ExynosJpegEncoder *m_jpegMain; + ExynosJpegEncoder *m_jpegThumb; + + char *m_pThumbInputBuffer; + char *m_pThumbOutputBuffer; +#ifdef JPEG_WA_FOR_PAGEFAULT + char *m_pExtInBuf; + char *m_pJpegInputBuffer; + int m_iInBufSize; +#endif // JPEG_WA_FOR_PAGEFAULT + ion_client m_ionJpegClient; + ion_buffer m_ionThumbInBuffer, m_ionThumbOutBuffer; +#ifdef JPEG_WA_FOR_PAGEFAULT + ion_buffer m_ionJpegInBuffer; +#endif // JPEG_WA_FOR_PAGEFAULT + + int m_thumbnailW; + int m_thumbnailH; + int m_thumbnailQuality; +}; + +#endif /* __SEC_JPG_ENC_H__ */ diff --git a/libcamera/NOTICE b/libcamera/NOTICE new file mode 100644 index 0000000..f921593 --- /dev/null +++ b/libcamera/NOTICE @@ -0,0 +1,190 @@ + + Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + |