hardware: exynos5: add initial libcamera directory
authorJiyoung Shin <idon.shin@samsung.com>
Mon, 2 Apr 2012 23:22:36 +0000 (16:22 -0700)
committerDima Zavin <dima@android.com>
Mon, 7 May 2012 18:26:48 +0000 (11:26 -0700)
Change-Id: I29abd427ac0554019ce9f66a272ec214779cf87b
Signed-off-by: Jiyoung Shin <idon.shin@samsung.com>
libcamera/Android.mk [new file with mode: 0644]
libcamera/ExynosCamera.cpp [new file with mode: 0644]
libcamera/ExynosCameraHWInterface.cpp [new file with mode: 0644]
libcamera/ExynosCameraHWInterface.h [new file with mode: 0644]
libcamera/ExynosExif.h [new file with mode: 0644]
libcamera/ExynosJpegEncoderForCamera.cpp [new file with mode: 0644]
libcamera/ExynosJpegEncoderForCamera.h [new file with mode: 0644]
libcamera/NOTICE [new file with mode: 0644]

diff --git a/libcamera/Android.mk b/libcamera/Android.mk
new file mode 100644 (file)
index 0000000..2729a2f
--- /dev/null
@@ -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 (file)
index 0000000..383c902
--- /dev/null
@@ -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 (file)
index 0000000..5069171
--- /dev/null
@@ -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 (file)
index 0000000..53ac270
--- /dev/null
@@ -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 (file)
index 0000000..5437b68
--- /dev/null
@@ -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 (file)
index 0000000..54b8864
--- /dev/null
@@ -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 (file)
index 0000000..2a4e9e2
--- /dev/null
@@ -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 (file)
index 0000000..f921593
--- /dev/null
@@ -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
+