Merge "QCamera2: Removes obsolete code for AF, zoom events"
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index 9b128d0..98cc249 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -854,14 +854,16 @@
 int QCamera2HardwareInterface::close_camera_device(hw_device_t *hw_dev)
 {
     int ret = NO_ERROR;
+    ALOGD("[KPI Perf] %s: E",__func__);
     QCamera2HardwareInterface *hw =
         reinterpret_cast<QCamera2HardwareInterface *>(
             reinterpret_cast<camera_device_t *>(hw_dev)->priv);
     if (!hw) {
-        ALOGE("NULL camera device");
+        ALOGE("%s: NULL camera device", __func__);
         return BAD_VALUE;
     }
     delete hw;
+    ALOGD("[KPI Perf] %s: X",__func__);
     return ret;
 }
 
@@ -1124,7 +1126,7 @@
     }
 
     /* Allocate memory for capability buffer */
-    capabilityHeap = new QCameraHeapMemory();
+    capabilityHeap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE);
     rc = capabilityHeap->allocate(1, sizeof(cam_capability_t));
     if(rc != OK) {
         ALOGE("%s: No memory for cappability", __func__);
@@ -1340,16 +1342,18 @@
 {
     int rc = NO_ERROR;
     QCameraMemory *mem = NULL;
+    bool bCachedMem = QCAMERA_ION_USE_CACHE;
 
     // Allocate stream buffer memory object
     switch (stream_type) {
     case CAM_STREAM_TYPE_PREVIEW:
         {
             if (isNoDisplayMode()) {
-                mem = new QCameraStreamMemory(mGetMemory);
+                mem = new QCameraStreamMemory(mGetMemory, bCachedMem);
             } else {
                 cam_dimension_t dim;
-                QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory);
+                QCameraGrallocMemory *grallocMemory =
+                    new QCameraGrallocMemory(mGetMemory);
 
                 mParameters.getStreamDimension(stream_type, dim);
                 if (grallocMemory)
@@ -1362,7 +1366,8 @@
     case CAM_STREAM_TYPE_POSTVIEW:
         {
             cam_dimension_t dim;
-            QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory);
+            QCameraGrallocMemory *grallocMemory =
+                new QCameraGrallocMemory(mGetMemory);
 
             mParameters.getStreamDimension(stream_type, dim);
             if (grallocMemory)
@@ -1375,10 +1380,18 @@
     case CAM_STREAM_TYPE_RAW:
     case CAM_STREAM_TYPE_METADATA:
     case CAM_STREAM_TYPE_OFFLINE_PROC:
-        mem = new QCameraStreamMemory(mGetMemory);
+        mem = new QCameraStreamMemory(mGetMemory, bCachedMem);
         break;
     case CAM_STREAM_TYPE_VIDEO:
-        mem = new QCameraVideoMemory(mGetMemory);
+        {
+            char value[32];
+            property_get("persist.camera.mem.usecache", value, "1");
+            if (atoi(value) == 0) {
+                bCachedMem = QCAMERA_ION_USE_NOCACHE;
+            }
+            ALOGD("%s: vidoe buf using cached memory = %d", __func__, bCachedMem);
+            mem = new QCameraVideoMemory(mGetMemory, bCachedMem);
+        }
         break;
     case CAM_STREAM_TYPE_DEFAULT:
     case CAM_STREAM_TYPE_MAX:
@@ -1415,7 +1428,7 @@
 {
     int rc = NO_ERROR;
 
-    QCameraHeapMemory *streamInfoBuf = new QCameraHeapMemory();
+    QCameraHeapMemory *streamInfoBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE);
     if (!streamInfoBuf) {
         ALOGE("allocateStreamInfoBuf: Unable to allocate streamInfo object");
         return NULL;
@@ -2156,7 +2169,7 @@
     }
 
     // allocate ion memory for source image
-    QCameraHeapMemory *imgBuf = new QCameraHeapMemory();
+    QCameraHeapMemory *imgBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE);
     if (imgBuf == NULL) {
         ALOGE("%s: Unable to new heap memory obj for image buf", __func__);
         return NO_MEMORY;
@@ -3021,8 +3034,6 @@
         return rc;
     }
 
-    // TODO: commented out for now
-#if 0
     rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_POSTVIEW,
                             postview_stream_cb_routine, this);
 
@@ -3031,7 +3042,6 @@
         delete pChannel;
         return rc;
     }
-#endif
 
     rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_SNAPSHOT,
                             NULL, this);
@@ -3151,6 +3161,10 @@
             pp_config.denoise2d.denoise_enable = 1;
             pp_config.denoise2d.process_plates = mParameters.getWaveletDenoiseProcessPlate();
         }
+
+        if (isCACEnabled()) {
+            pp_config.feature_mask |= CAM_QCOM_FEATURE_CAC;
+        }
     }
     if (needRotationReprocess()) {
         pp_config.feature_mask |= CAM_QCOM_FEATURE_ROTATION;
@@ -3852,6 +3866,25 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : isCACEnabled
+ *
+ * DESCRIPTION: if CAC is enabled
+ *
+ * PARAMETERS : none
+ *
+ * RETURN     : true: needed
+ *              false: no need
+ *==========================================================================*/
+bool QCamera2HardwareInterface::isCACEnabled()
+{
+    char prop[PROPERTY_VALUE_MAX];
+    memset(prop, 0, sizeof(prop));
+    property_get("persist.camera.feature.cac", prop, "0");
+    int enableCAC = atoi(prop);
+    return enableCAC == 1;
+}
+
+/*===========================================================================
  * FUNCTION   : needReprocess
  *
  * DESCRIPTION: if reprocess is needed
@@ -3870,7 +3903,7 @@
 
     if (mParameters.isZSLMode() &&
         ((gCamCapability[mCameraId]->min_required_pp_mask > 0) ||
-         mParameters.isWNREnabled())) {
+         mParameters.isWNREnabled() || isCACEnabled())) {
         // TODO: add for ZSL HDR later
         // pp module has min requirement for zsl reprocess, or WNR in ZSL mode
         ALOGD("%s: need do reprocess for ZSL WNR or min PP reprocess", __func__);
@@ -4167,6 +4200,7 @@
  *==========================================================================*/
 int32_t QCamera2HardwareInterface::prepareHardwareForSnapshot(int32_t afNeeded)
 {
+    ALOGD("[KPI Perf] %s: Prepare hardware such as LED",__func__);
     return mCameraHandle->ops->prepare_snapshot(mCameraHandle->camera_handle,
                                                 afNeeded);
 }
diff --git a/QCamera2/HAL/QCamera2HWI.h b/QCamera2/HAL/QCamera2HWI.h
index a1b217d..bc4db20 100644
--- a/QCamera2/HAL/QCamera2HWI.h
+++ b/QCamera2/HAL/QCamera2HWI.h
@@ -101,6 +101,9 @@
 
 #define QCAMERA_DUMP_FRM_MASK_ALL    0x000000ff
 
+#define QCAMERA_ION_USE_CACHE   true
+#define QCAMERA_ION_USE_NOCACHE false
+
 typedef enum {
     QCAMERA_NOTIFY_CALLBACK,
     QCAMERA_DATA_CALLBACK,
@@ -272,6 +275,7 @@
     int commitParameterChanges();
 
     bool needDebugFps();
+    bool isCACEnabled();
     bool needReprocess();
     bool needRotationReprocess();
     bool needOnlineRotation();
diff --git a/QCamera2/HAL/QCamera2HWICallbacks.cpp b/QCamera2/HAL/QCamera2HWICallbacks.cpp
index 40fffa6..ca534a4 100644
--- a/QCamera2/HAL/QCamera2HWICallbacks.cpp
+++ b/QCamera2/HAL/QCamera2HWICallbacks.cpp
@@ -684,6 +684,7 @@
                 __func__, pMetaData->faces_data.num_faces_detected);
         } else {
             // process face detection result
+            ALOGD("[KPI Perf] %s: Number of faces detected %d",__func__,pMetaData->faces_data.num_faces_detected);
             pme->processFaceDetectionResult(&pMetaData->faces_data);
         }
     }
@@ -987,12 +988,9 @@
     qcamera_callback_argm_t *arg = ( qcamera_callback_argm_t * ) data;
 
     if ( ( NULL != arg ) && ( NULL != user_data ) ) {
-
         if ( arg->release_cb ) {
             arg->release_cb(arg->user_data, arg->cookie);
         }
-
-        delete arg;
     }
 }
 
diff --git a/QCamera2/HAL/QCameraMem.cpp b/QCamera2/HAL/QCameraMem.cpp
index 03da59f..2b846ae 100644
--- a/QCamera2/HAL/QCameraMem.cpp
+++ b/QCamera2/HAL/QCameraMem.cpp
@@ -53,11 +53,13 @@
  *
  * DESCRIPTION: default constructor of QCameraMemory
  *
- * PARAMETERS : none
+ * PARAMETERS :
+ *   @cached  : flag indicates if using cached memory
  *
  * RETURN     : None
  *==========================================================================*/
-QCameraMemory::QCameraMemory()
+QCameraMemory::QCameraMemory(bool cached)
+    :m_bCached(cached)
 {
     mBufferCount = 0;
     for (int i = 0; i < MM_CAMERA_MAX_NUM_FRAMES; i++) {
@@ -97,6 +99,12 @@
  *==========================================================================*/
 int QCameraMemory::cacheOpsInternal(int index, unsigned int cmd, void *vaddr)
 {
+    if (!m_bCached) {
+        // Memory is not cached, no need for cache ops
+        ALOGV("%s: No cache ops here for uncached memory", __func__);
+        return OK;
+    }
+
     struct ion_flush_data cache_inv_data;
     struct ion_custom_data custom_data;
     int ret = OK;
@@ -293,7 +301,7 @@
     int main_ion_fd = 0;
 
     main_ion_fd = open("/dev/ion", O_RDONLY);
-    if (main_ion_fd <= 0) {
+    if (main_ion_fd < 0) {
         ALOGE("Ion dev open failed: %s\n", strerror(errno));
         goto ION_OPEN_FAILED;
     }
@@ -303,7 +311,9 @@
     /* to make it page size aligned */
     alloc.len = (alloc.len + 4095) & (~4095);
     alloc.align = 4096;
-    alloc.flags = ION_FLAG_CACHED;
+    if (m_bCached) {
+        alloc.flags = ION_FLAG_CACHED;
+    }
     alloc.heap_mask = heap_id;
     rc = ioctl(main_ion_fd, ION_IOC_ALLOC, &alloc);
     if (rc < 0) {
@@ -370,12 +380,13 @@
  *
  * DESCRIPTION: constructor of QCameraHeapMemory for ion memory used internally in HAL
  *
- * PARAMETERS : none
+ * PARAMETERS :
+ *   @cached  : flag indicates if using cached memory
  *
  * RETURN     : none
  *==========================================================================*/
-QCameraHeapMemory::QCameraHeapMemory()
-    : QCameraMemory()
+QCameraHeapMemory::QCameraHeapMemory(bool cached)
+    : QCameraMemory(cached)
 {
     for (int i = 0; i < MM_CAMERA_MAX_NUM_FRAMES; i ++)
         mPtr[i] = NULL;
@@ -563,11 +574,14 @@
  *
  * PARAMETERS :
  *   @getMemory : camera memory request ops table
+ *   @cached    : flag indicates if using cached memory
  *
  * RETURN     : none
  *==========================================================================*/
-QCameraStreamMemory::QCameraStreamMemory(camera_request_memory getMemory) :
-        mGetMemory(getMemory)
+QCameraStreamMemory::QCameraStreamMemory(camera_request_memory getMemory,
+                                         bool cached)
+    :QCameraMemory(cached),
+     mGetMemory(getMemory)
 {
     for (int i = 0; i < MM_CAMERA_MAX_NUM_FRAMES; i ++)
         mCameraMemory[i] = NULL;
@@ -745,11 +759,13 @@
  *
  * PARAMETERS :
  *   @getMemory : camera memory request ops table
+ *   @cached    : flag indicates if using cached ION memory
  *
  * RETURN     : none
  *==========================================================================*/
-QCameraVideoMemory::QCameraVideoMemory(camera_request_memory getMemory)
-    : QCameraStreamMemory(getMemory)
+QCameraVideoMemory::QCameraVideoMemory(camera_request_memory getMemory,
+                                       bool cached)
+    : QCameraStreamMemory(getMemory, cached)
 {
     memset(mMetadata, 0, sizeof(mMetadata));
 }
@@ -894,7 +910,7 @@
  * RETURN     : none
  *==========================================================================*/
 QCameraGrallocMemory::QCameraGrallocMemory(camera_request_memory getMemory)
-        : QCameraMemory()
+        : QCameraMemory(true)
 {
     mMinUndequeuedBuffers = 0;
     mWindow = NULL;
@@ -1091,7 +1107,7 @@
         mPrivateHandle[cnt] =
             (struct private_handle_t *)(*mBufferHandle[cnt]);
         mMemInfo[cnt].main_ion_fd = open("/dev/ion", O_RDONLY);
-        if (mMemInfo[cnt].main_ion_fd <= 0) {
+        if (mMemInfo[cnt].main_ion_fd < 0) {
             ALOGE("%s: failed: could not open ion device", __func__);
             for(int i = 0; i < cnt; i++) {
                 struct ion_handle_data ion_handle;
diff --git a/QCamera2/HAL/QCameraMem.h b/QCamera2/HAL/QCameraMem.h
index 8fc7028..2890c9d 100644
--- a/QCamera2/HAL/QCameraMem.h
+++ b/QCamera2/HAL/QCameraMem.h
@@ -60,7 +60,7 @@
     virtual int getMatchBufIndex(const void *opaque, bool metadata) const = 0;
     virtual void *getPtr(int index) const= 0;
 
-    QCameraMemory();
+    QCameraMemory(bool cached);
     virtual ~QCameraMemory();
 
     void getBufDef(const cam_frame_len_offset_t &offset,
@@ -80,6 +80,7 @@
     void deallocOneBuffer(struct QCameraMemInfo &memInfo);
     int cacheOpsInternal(int index, unsigned int cmd, void *vaddr);
 
+    bool m_bCached;
     int mBufferCount;
     struct QCameraMemInfo mMemInfo[MM_CAMERA_MAX_NUM_FRAMES];
 };
@@ -88,7 +89,7 @@
 // They are allocated from /dev/ion.
 class QCameraHeapMemory : public QCameraMemory {
 public:
-    QCameraHeapMemory();
+    QCameraHeapMemory(bool cached);
     virtual ~QCameraHeapMemory();
 
     virtual int allocate(int count, int size);
@@ -107,7 +108,7 @@
 // framework. They are allocated from /dev/ion or gralloc.
 class QCameraStreamMemory : public QCameraMemory {
 public:
-    QCameraStreamMemory(camera_request_memory getMemory);
+    QCameraStreamMemory(camera_request_memory getMemory, bool cached);
     virtual ~QCameraStreamMemory();
 
     virtual int allocate(int count, int size);
@@ -127,7 +128,7 @@
 // framework. They are allocated from /dev/ion or gralloc.
 class QCameraVideoMemory : public QCameraStreamMemory {
 public:
-    QCameraVideoMemory(camera_request_memory getMemory);
+    QCameraVideoMemory(camera_request_memory getMemory, bool cached);
     virtual ~QCameraVideoMemory();
 
     virtual int allocate(int count, int size);
diff --git a/QCamera2/HAL/QCameraParameters.cpp b/QCamera2/HAL/QCameraParameters.cpp
index e4bf31a..72b44a6 100644
--- a/QCamera2/HAL/QCameraParameters.cpp
+++ b/QCamera2/HAL/QCameraParameters.cpp
@@ -816,6 +816,30 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : compareFPSValues
+ *
+ * DESCRIPTION: helper function for fps sorting
+ *
+ * PARAMETERS :
+ *   @p1     : first array element
+ *   @p2     : second array element
+ *
+ * RETURN     : -1 - left element is greater than right
+ *              0  - elements are equals
+ *              1  - left element is less than right
+ *==========================================================================*/
+int QCameraParameters::compareFPSValues(const void *p1, const void *p2)
+{
+    if ( *( (int *) p1) > *( (int *) p2) ) {
+        return -1;
+    } else if (  *( (int *) p1) < *( (int *) p2) ) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*===========================================================================
  * FUNCTION   : createFpsString
  *
  * DESCRIPTION: create string obj contains array of FPS rates
@@ -830,13 +854,29 @@
 {
     String8 str;
     char buffer[32];
+    int duplicate = INT_MAX;
+
+    int *fpsValues = new int[len];
 
     for (int i = 0; i < len; i++ ) {
-        snprintf(buffer, sizeof(buffer), "%d", int(fps[i].max_fps * 1000));
-        str.append(buffer);
-        if (i < len-1)
-            str.append(",");
+        fpsValues[i] = int(fps[i].max_fps);
     }
+
+    qsort(fpsValues, len, sizeof(int), compareFPSValues);
+
+    for (int i = 0; i < len; i++ ) {
+        if ( duplicate != fpsValues[i] ) {
+            snprintf(buffer, sizeof(buffer), "%d", fpsValues[i]);
+            str.append(buffer);
+            if (i < len-1) {
+                str.append(",");
+            }
+            duplicate = fpsValues[i];
+        }
+    }
+
+    delete [] fpsValues;
+
     return str;
 }
 
@@ -958,10 +998,7 @@
             }
 
             // set the new value
-            char val[32];
-            sprintf(val, "%dx%d", width, height);
-            updateParamEntry(KEY_PREVIEW_SIZE, val);
-            ALOGV("%s: %s", __func__, val);
+            CameraParameters::setPreviewSize(width, height);
             return NO_ERROR;
         }
     }
@@ -1000,10 +1037,7 @@
             }
 
             // set the new value
-            char val[32];
-            sprintf(val, "%dx%d", width, height);
-            updateParamEntry(KEY_PICTURE_SIZE, val);
-            ALOGV("%s: %s", __func__, val);
+            CameraParameters::setPictureSize(width, height);
             return NO_ERROR;
         }
     }
@@ -1050,10 +1084,7 @@
             }
 
             // set the new value
-            char val[32];
-            sprintf(val, "%dx%d", width, height);
-            updateParamEntry(KEY_VIDEO_SIZE, val);
-            ALOGV("%s: %s", __func__, val);
+            CameraParameters::setVideoSize(width, height);
             return NO_ERROR;
         }
     }
@@ -1179,7 +1210,7 @@
     if (previewFormat != NAME_NOT_FOUND) {
         mPreviewFormat = (cam_format_t)previewFormat;
 
-        updateParamEntry(KEY_PREVIEW_FORMAT, str);
+        CameraParameters::setPreviewFormat(str);
         ALOGV("%s: format %d\n", __func__, mPreviewFormat);
         return NO_ERROR;
     }
@@ -1209,7 +1240,7 @@
     if (pictureFormat != NAME_NOT_FOUND) {
         mPictureFormat = pictureFormat;
 
-        updateParamEntry(KEY_PICTURE_FORMAT, str);
+        CameraParameters::setPictureFormat(str);
         ALOGE("%s: format %d\n", __func__, mPictureFormat);
         return NO_ERROR;
     }
@@ -1271,11 +1302,8 @@
         }
     }
 
-    char val[16];
-    sprintf(val, "%d", optimalWidth);
-    updateParamEntry(KEY_JPEG_THUMBNAIL_WIDTH, val);
-    sprintf(val, "%d", optimalHeight);
-    updateParamEntry(KEY_JPEG_THUMBNAIL_HEIGHT, val);
+    set(KEY_JPEG_THUMBNAIL_WIDTH, optimalWidth);
+    set(KEY_JPEG_THUMBNAIL_HEIGHT, optimalHeight);
     return NO_ERROR;
 }
 
@@ -1304,9 +1332,7 @@
 
     quality = params.getInt(KEY_JPEG_THUMBNAIL_QUALITY);
     if (quality >= 0 && quality <= 100) {
-        char val[16];
-        sprintf(val, "%d", quality);
-        updateParamEntry(KEY_JPEG_THUMBNAIL_QUALITY, val);
+        set(KEY_JPEG_THUMBNAIL_QUALITY, quality);
     } else {
         ALOGE("%s: Invalid jpeg thumbnail quality=%d", __func__, quality);
         rc = BAD_VALUE;
@@ -1334,7 +1360,7 @@
         if (strcmp(str, portrait) == 0 || strcmp(str, landscape) == 0) {
             // Camera service needs this to decide if the preview frames and raw
             // pictures should be rotated.
-            updateParamEntry(KEY_QC_ORIENTATION, str);
+            set(KEY_QC_ORIENTATION, str);
         } else {
             ALOGE("%s: Invalid orientation value: %s", __func__, str);
             return BAD_VALUE;
@@ -2477,7 +2503,7 @@
     if(str_val && strlen(str_val) > 0) {
         if (prev_str == NULL || strcmp(str_val, prev_str) != 0) {
             m_bNoDisplayMode = atoi(str_val);
-            updateParamEntry(KEY_QC_NO_DISPLAY_MODE, str_val);
+            set(KEY_QC_NO_DISPLAY_MODE, str_val);
             m_bNeedRestart = true;
         }
     } else {
@@ -2510,7 +2536,7 @@
                                        sizeof(ON_OFF_MODES_MAP)/sizeof(QCameraMap),
                                        str_val);
             if (value != NAME_NOT_FOUND) {
-                updateParamEntry(KEY_QC_ZSL, str_val);
+                set(KEY_QC_ZSL, str_val);
                 m_bZslMode = (value > 0)? true : false;
 
                 // ZSL mode changed, need restart preview
@@ -2945,7 +2971,7 @@
         String8 fpsValues = createFpsString(m_pCapability->fps_ranges_tbl,
                                             m_pCapability->fps_ranges_tbl_cnt);
         set(KEY_SUPPORTED_PREVIEW_FRAME_RATES, fpsValues.string());
-        CameraParameters::setPreviewFrameRate(max_fps);
+        CameraParameters::setPreviewFrameRate(int(m_pCapability->fps_ranges_tbl[default_fps_index].max_fps));
     } else {
         ALOGE("%s: supported fps ranges cnt is 0 or exceeds max!!!", __func__);
     }
@@ -3260,7 +3286,7 @@
     m_pCamOpsTbl = mmOps;
 
     //Allocate Set Param Buffer
-    m_pParamHeap = new QCameraHeapMemory();
+    m_pParamHeap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE);
     rc = m_pParamHeap->allocate(1, sizeof(parm_buffer_t));
     if(rc != OK) {
         rc = NO_MEMORY;
@@ -5568,6 +5594,8 @@
     fd_set_parm.fd_mode = faceProcMask;
     fd_set_parm.num_fd = requested_faces;
 
+    ALOGD("[KPI Perf] %s: Face detection value = %d num_fd = %d",
+          __func__, faceProcMask,requested_faces);
     if(initBatchUpdate(m_pParamBuf) < 0 ) {
         ALOGE("%s:Failed to initialize group update table", __func__);
         return BAD_TYPE;
diff --git a/QCamera2/HAL/QCameraParameters.h b/QCamera2/HAL/QCameraParameters.h
index 711f9e6..3b6a9a6 100644
--- a/QCamera2/HAL/QCameraParameters.h
+++ b/QCamera2/HAL/QCameraParameters.h
@@ -520,6 +520,7 @@
     String8 createFpsRangeString(const cam_fps_range_t *fps,
                                  int len,
                                  int &default_fps_index);
+    static int compareFPSValues(const void *p1, const void *p2);
     String8 createFpsString(const cam_fps_range_t *fps, int len);
     String8 createZoomRatioValuesString(int *zoomRatios, int length);
     int lookupAttr(const QCameraMap arr[], int len, const char *name);
diff --git a/QCamera2/HAL/QCameraPostProc.cpp b/QCamera2/HAL/QCameraPostProc.cpp
index d77de9e..a2e6999 100644
--- a/QCamera2/HAL/QCameraPostProc.cpp
+++ b/QCamera2/HAL/QCameraPostProc.cpp
@@ -243,7 +243,7 @@
     cam_dimension_t thumbnailSize;
     memset(&thumbnailSize, 0, sizeof(cam_dimension_t));
     m_parent->getThumbnailSize(thumbnailSize);
-    if (thumbnailSize.width == 0 && thumbnailSize.height == 0) {
+    if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
         // (0,0) means no thumbnail
         m_bThumbnailNeeded = FALSE;
     }
@@ -328,7 +328,8 @@
         delete m_pJpegOutputMem;
         m_pJpegOutputMem = NULL;
     }
-    m_pJpegOutputMem = new QCameraStreamMemory(m_parent->mGetMemory);
+    m_pJpegOutputMem = new QCameraStreamMemory(m_parent->mGetMemory,
+                                               QCAMERA_ION_USE_CACHE);
     if (NULL == m_pJpegOutputMem) {
         ret = NO_MEMORY;
         ALOGE("%s : No memory for m_pJpegOutputMem", __func__);
@@ -633,6 +634,13 @@
         return BAD_VALUE;
     }
 
+    if (m_parent->mParameters.isNV16PictureFormat()) {
+        releaseSuperBuf(job->src_frame);
+        free(job->src_frame);
+        free(job);
+        return processRawData(frame);
+    }
+
     qcamera_jpeg_data_t *jpeg_job =
         (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t));
     if (jpeg_job == NULL) {
@@ -1349,13 +1357,14 @@
                     }
                 } else {
                     // not active, simply return buf and do no op
-                    mm_camera_super_buf_t *super_buf =
-                        (mm_camera_super_buf_t *)pme->m_inputJpegQ.dequeue();
-                    if (NULL != super_buf) {
-                        pme->releaseSuperBuf(super_buf);
-                        free(super_buf);
+                    qcamera_jpeg_data_t *jpeg_data =
+                        (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue();
+                    if (NULL != jpeg_data) {
+                        pme->releaseJpegJobData(jpeg_data);
+                        free(jpeg_data);
                     }
-                    super_buf = (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
+                    mm_camera_super_buf_t *super_buf =
+                        (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue();
                     if (NULL != super_buf) {
                         pme->releaseSuperBuf(super_buf);
                         free(super_buf);
diff --git a/QCamera2/HAL/QCameraThermalAdapter.cpp b/QCamera2/HAL/QCameraThermalAdapter.cpp
index 16d8a42..abdae3e 100644
--- a/QCamera2/HAL/QCameraThermalAdapter.cpp
+++ b/QCamera2/HAL/QCameraThermalAdapter.cpp
@@ -63,7 +63,7 @@
     int rc = NO_ERROR;
 
     ALOGV("%s E", __func__);
-    mHandle = dlopen("/system/lib/libthermalclient.so", RTLD_NOW);
+    mHandle = dlopen("/vendor/lib/libthermalclient.so", RTLD_NOW);
     if (!mHandle) {
         error = dlerror();
         ALOGE("%s: dlopen failed with error %s",
diff --git a/QCamera2/stack/common/cam_intf.h b/QCamera2/stack/common/cam_intf.h
index d3f50b1..ba555e1 100644
--- a/QCamera2/stack/common/cam_intf.h
+++ b/QCamera2/stack/common/cam_intf.h
@@ -174,6 +174,8 @@
     uint8_t meta_present;         /* if there is meta data associated with this reprocess frame */
     uint32_t meta_stream_handle;  /* meta data stream ID. only valid if meta_present != 0 */
     uint8_t meta_buf_index;       /* buf index to meta data buffer. only valid if meta_present != 0 */
+
+    cam_per_frame_pp_config_t frame_pp_config; /* per frame post-proc configuration */
 } cam_reprocess_param;
 
 typedef struct {
diff --git a/QCamera2/stack/common/cam_types.h b/QCamera2/stack/common/cam_types.h
index 0d3388f..dba418f 100644
--- a/QCamera2/stack/common/cam_types.h
+++ b/QCamera2/stack/common/cam_types.h
@@ -801,4 +801,16 @@
     cam_pp_feature_config_t pp_feature_config;
 } cam_stream_reproc_config_t;
 
+typedef struct {
+    uint8_t crop_enabled;
+    cam_rect_t input_crop;
+} cam_crop_param_t;
+
+typedef struct {
+    cam_denoise_param_t denoise;
+    cam_crop_param_t crop;
+    uint32_t flip;     /* 0 means no flip */
+    int32_t sharpness; /* 0 means no sharpness */
+} cam_per_frame_pp_config_t;
+
 #endif /* __QCAMERA_TYPES_H__ */
diff --git a/QCamera2/stack/common/mm_camera_interface.h b/QCamera2/stack/common/mm_camera_interface.h
index 7ccc130..eb8a458 100644
--- a/QCamera2/stack/common/mm_camera_interface.h
+++ b/QCamera2/stack/common/mm_camera_interface.h
@@ -608,6 +608,18 @@
      **/
     int32_t (*flush_super_buf_queue) (uint32_t camera_handle,
                                       uint32_t ch_id, uint32_t frame_idx);
+
+    /** configure_notify_mode: function definition for configuring the
+     *                         notification mode of channel
+     *    @camera_handle : camera handler
+     *    @ch_id : channel handler
+     *    @notify_mode : notification mode
+     *  Return value: 0 -- success
+     *                -1 -- failure
+     **/
+    int32_t (*configure_notify_mode) (uint32_t camera_handle,
+                                      uint32_t ch_id,
+                                      mm_camera_super_buf_notify_mode_t notify_mode);
 } mm_camera_ops_t;
 
 /** mm_camera_vtbl_t: virtual table for camera operations
diff --git a/QCamera2/stack/mm-camera-interface/inc/mm_camera.h b/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
index 4b535e5..02f4e34 100644
--- a/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
+++ b/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
@@ -67,6 +67,7 @@
     MM_CAMERA_CMD_TYPE_EXIT,       /* EXIT */
     MM_CAMERA_CMD_TYPE_REQ_DATA_CB,/* request data */
     MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB,    /* superbuf dataB CMD */
+    MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY, /* configure notify mode */
     MM_CAMERA_CMD_TYPE_FLUSH_QUEUE, /* flush queue */
     MM_CAMERA_CMD_TYPE_MAX
 } mm_camera_cmdcb_type_t;
@@ -89,6 +90,7 @@
         mm_camera_super_buf_t superbuf; /* superbuf if superbuf dataCB*/
         mm_camera_req_buf_t req_buf; /* num of buf requested */
         uint32_t frame_idx; /* frame idx boundary for flush superbuf queue*/
+        mm_camera_super_buf_notify_mode_t notify_mode; /* notification mode */
     } u;
 } mm_camera_cmdcb_t;
 
@@ -245,6 +247,7 @@
     MM_CHANNEL_EVT_REQUEST_SUPER_BUF,
     MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF,
     MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE,
+    MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE,
     MM_CHANNEL_EVT_MAP_STREAM_BUF,
     MM_CHANNEL_EVT_UNMAP_STREAM_BUF,
     MM_CHANNEL_EVT_SET_STREAM_PARM,
@@ -375,6 +378,8 @@
     pthread_mutex_t evt_lock;
     pthread_cond_t evt_cond;
     mm_camera_event_t evt_rcvd;
+
+    pthread_mutex_t msg_lock; /* lock for sending msg through socket */
 } mm_camera_obj_t;
 
 typedef struct {
@@ -461,6 +466,9 @@
 extern int32_t mm_camera_flush_super_buf_queue(mm_camera_obj_t *my_obj,
                                                uint32_t ch_id,
                                                uint32_t frame_idx);
+extern int32_t mm_camera_config_channel_notify(mm_camera_obj_t *my_obj,
+                                               uint32_t ch_id,
+                                               mm_camera_super_buf_notify_mode_t notify_mode);
 extern int32_t mm_camera_set_stream_parms(mm_camera_obj_t *my_obj,
                                           uint32_t ch_id,
                                           uint32_t s_id,
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera.c b/QCamera2/stack/mm-camera-interface/src/mm_camera.c
index 38c7197..deac8b8 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera.c
@@ -289,6 +289,7 @@
         rc = -1;
         goto on_error;
     }
+    pthread_mutex_init(&my_obj->msg_lock, NULL);
 
     pthread_mutex_init(&my_obj->cb_lock, NULL);
     pthread_mutex_init(&my_obj->evt_lock, NULL);
@@ -359,6 +360,7 @@
         mm_camera_socket_close(my_obj->ds_fd);
         my_obj->ds_fd = 0;
     }
+    pthread_mutex_destroy(&my_obj->msg_lock);
 
     pthread_mutex_destroy(&my_obj->cb_lock);
     pthread_mutex_destroy(&my_obj->evt_lock);
@@ -1102,6 +1104,43 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_camera_config_channel_notify
+ *
+ * DESCRIPTION: configures the channel notification mode
+ *
+ * PARAMETERS :
+ *   @my_obj       : camera object
+ *   @ch_id        : channel handle
+ *   @notify_mode  : notification mode
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_camera_config_channel_notify(mm_camera_obj_t *my_obj,
+                                        uint32_t ch_id,
+                                        mm_camera_super_buf_notify_mode_t notify_mode)
+{
+    int32_t rc = -1;
+    mm_channel_t * ch_obj =
+        mm_camera_util_get_channel_by_handler(my_obj, ch_id);
+
+    if (NULL != ch_obj) {
+        pthread_mutex_lock(&ch_obj->ch_lock);
+        pthread_mutex_unlock(&my_obj->cam_lock);
+
+        rc = mm_channel_fsm_fn(ch_obj,
+                               MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE,
+                               (void *)notify_mode,
+                               NULL);
+    } else {
+        pthread_mutex_unlock(&my_obj->cam_lock);
+    }
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_camera_set_stream_parms
  *
  * DESCRIPTION: set parameters per stream
@@ -1460,6 +1499,9 @@
 {
     int32_t rc = -1;
     int32_t status;
+
+    /* need to lock msg_lock, since sendmsg until reposonse back is deemed as one operation*/
+    pthread_mutex_lock(&my_obj->msg_lock);
     if(mm_camera_socket_sendmsg(my_obj->ds_fd, msg, buf_size, sendfd) > 0) {
         /* wait for event that mapping/unmapping is done */
         mm_camera_util_wait_for_event(my_obj, CAM_EVENT_TYPE_MAP_UNMAP_DONE, &status);
@@ -1467,6 +1509,7 @@
             rc = 0;
         }
     }
+    pthread_mutex_unlock(&my_obj->msg_lock);
     return rc;
 }
 
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
index 58a9254..9aa117a 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_channel.c
@@ -67,6 +67,8 @@
 int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
 int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj,
                                          uint32_t frame_idx);
+int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
+                                      mm_camera_super_buf_notify_mode_t notify_mode);
 int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, mm_channel_queue_t * queue);
 int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
                                    mm_evt_paylod_set_get_stream_parms_t *payload);
@@ -203,12 +205,13 @@
         /* skip frames if needed */
         ch_obj->pending_cnt = cmd_cb->u.req_buf.num_buf_requested;
         mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue);
+    } else if (MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY == cmd_cb->cmd_type) {
+           ch_obj->bundle.superbuf_queue.attr.notify_mode = cmd_cb->u.notify_mode;
     } else if (MM_CAMERA_CMD_TYPE_FLUSH_QUEUE  == cmd_cb->cmd_type) {
         ch_obj->bundle.superbuf_queue.expected_frame_id = cmd_cb->u.frame_idx;
         mm_channel_superbuf_flush(ch_obj, &ch_obj->bundle.superbuf_queue);
         return;
     }
-
     notify_mode = ch_obj->bundle.superbuf_queue.attr.notify_mode;
 
     /* bufdone for overflowed bufs */
@@ -518,6 +521,12 @@
             rc = mm_channel_flush_super_buf_queue(my_obj, frame_idx);
         }
         break;
+    case MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE:
+        {
+            mm_camera_super_buf_notify_mode_t notify_mode = ( mm_camera_super_buf_notify_mode_t ) in_val;
+            rc = mm_channel_config_notify_mode(my_obj, notify_mode);
+        }
+        break;
     case MM_CHANNEL_EVT_SET_STREAM_PARM:
         {
             mm_evt_paylod_set_get_stream_parms_t *payload =
@@ -1154,6 +1163,44 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_channel_config_notify_mode
+ *
+ * DESCRIPTION: configure notification mode
+ *
+ * PARAMETERS :
+ *   @my_obj  : channel object
+ *   @notify_mode : notification mode
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj,
+                                      mm_camera_super_buf_notify_mode_t notify_mode)
+{
+    int32_t rc = 0;
+    mm_camera_cmdcb_t* node = NULL;
+
+    node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
+    if (NULL != node) {
+        memset(node, 0, sizeof(mm_camera_cmdcb_t));
+        node->u.notify_mode = notify_mode;
+        node->cmd_type = MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY;
+
+        /* enqueue to cmd thread */
+        cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
+
+        /* wake up cmd thread */
+        cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
+    } else {
+        CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
+        rc = -1;
+    }
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_channel_qbuf
  *
  * DESCRIPTION: enqueue buffer back to kernel
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
index 3919fc4..f043bfb 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
@@ -923,6 +923,43 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_camera_intf_configure_notify_mode
+ *
+ * DESCRIPTION: Configures channel notification mode
+ *
+ * PARAMETERS :
+ *   @camera_handle: camera handle
+ *   @ch_id        : channel handle
+ *   @notify_mode  : notification mode
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+static int32_t mm_camera_intf_configure_notify_mode(uint32_t camera_handle,
+                                                    uint32_t ch_id,
+                                                    mm_camera_super_buf_notify_mode_t notify_mode)
+{
+    int32_t rc = -1;
+    mm_camera_obj_t * my_obj = NULL;
+
+    CDBG("%s :E camera_handler = %d,ch_id = %d",
+         __func__, camera_handle, ch_id);
+    pthread_mutex_lock(&g_intf_lock);
+    my_obj = mm_camera_util_get_camera_by_handler(camera_handle);
+
+    if(my_obj) {
+        pthread_mutex_lock(&my_obj->cam_lock);
+        pthread_mutex_unlock(&g_intf_lock);
+        rc = mm_camera_config_channel_notify(my_obj, ch_id, notify_mode);
+    } else {
+        pthread_mutex_unlock(&g_intf_lock);
+    }
+    CDBG("%s :X rc = %d", __func__, rc);
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : mm_camera_intf_map_buf
  *
  * DESCRIPTION: mapping camera buffer via domain socket to server
@@ -1304,7 +1341,8 @@
     .stop_channel = mm_camera_intf_stop_channel,
     .request_super_buf = mm_camera_intf_request_super_buf,
     .cancel_super_buf_request = mm_camera_intf_cancel_super_buf_request,
-    .flush_super_buf_queue = mm_camera_intf_flush_super_buf_queue
+    .flush_super_buf_queue = mm_camera_intf_flush_super_buf_queue,
+    .configure_notify_mode = mm_camera_intf_configure_notify_mode
 };
 
 /*===========================================================================
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
index 42ee99f..91c61bc 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
@@ -2281,8 +2281,10 @@
 {
     int32_t rc = 0;
     if (stream_info->reprocess_config.pp_type == CAM_OFFLINE_REPROCESS_TYPE) {
-        // take offset from input source
-        *buf_planes = stream_info->reprocess_config.offline.input_buf_planes;
+        if (buf_planes->plane_info.frame_len == 0) {
+            // take offset from input source
+            *buf_planes = stream_info->reprocess_config.offline.input_buf_planes;
+        }
         return rc;
     }
 
diff --git a/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c b/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
index d889b05..3e691ca 100755
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
@@ -92,6 +92,9 @@
     len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt));
     if(len < 1) {
         CDBG_ERROR("%s: len = %d, errno = %d", __func__, len, errno);
+        /* Avoid waiting for the signal */
+        pthread_mutex_unlock(&poll_cb->mutex);
+        return 0;
     }
     CDBG("%s: begin IN mutex write done, len = %d", __func__, len);
     /* wait till worker task gives positive signal */
@@ -482,6 +485,7 @@
             case MM_CAMERA_CMD_TYPE_DATA_CB:
             case MM_CAMERA_CMD_TYPE_REQ_DATA_CB:
             case MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB:
+            case MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY:
             case MM_CAMERA_CMD_TYPE_FLUSH_QUEUE:
                 if (NULL != cmd_thread->cb) {
                     cmd_thread->cb(node, cmd_thread->user_data);
diff --git a/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
index 2496cfe..593c7d4 100644
--- a/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
+++ b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
@@ -42,7 +42,7 @@
 #define MM_JPEG_MAX_THREADS 30
 #define MM_JPEG_CIRQ_SIZE 30
 #define MM_JPEG_MAX_SESSION 10
-#define MAX_EXIF_TABLE_ENTRIES 30
+#define MAX_EXIF_TABLE_ENTRIES 50
 
 typedef struct {
   struct cam_list list;
diff --git a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
index c13b51d..91ec30c 100644
--- a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
+++ b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
@@ -698,13 +698,24 @@
     return ret;
   }
 
-  // Enable thumbnail port
-  ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
-      p_session->inputTmbPort.nPortIndex, NULL);
+  if (p_session->params.encode_thumbnail) {
+    // Enable thumbnail port
+    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
+        p_session->inputTmbPort.nPortIndex, NULL);
 
-  if (ret) {
-    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
-    return ret;
+    if (ret) {
+      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
+      return ret;
+    }
+  } else {
+    // Disable thumbnail port
+    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
+        p_session->inputTmbPort.nPortIndex, NULL);
+
+    if (ret) {
+      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
+      return ret;
+    }
   }
 
   p_session->outputPort.nBufferSize =
@@ -1013,6 +1024,7 @@
   OMX_CONFIG_ROTATIONTYPE rotate;
   mm_jpeg_encode_params_t *p_params = &p_session->params;
   mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
+  QOMX_EXIF_INFO exif_info;
 
   /* set rotation */
   memset(&rotate, 0, sizeof(rotate));
@@ -1028,22 +1040,22 @@
     (int)p_jobparams->rotation, (int)rotate.nPortIndex);
 
   /* Set Exif data*/
-  memset(&p_session->exif_info_all,  0,  sizeof(p_session->exif_info_all));
+  memset(&p_session->exif_info_all[0],  0,  sizeof(p_session->exif_info_all));
 
+  exif_info.numOfEntries = p_params->exif_info.numOfEntries;
+  exif_info.exif_data = &p_session->exif_info_all[0];
   /*If Exif data has been passed copy it*/
   if (p_params->exif_info.numOfEntries > 0) {
     CDBG("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__,
       p_params->exif_info.numOfEntries);
-    memcpy(&p_session->exif_info_all, &p_params->exif_info.exif_data,
-      sizeof(p_params->exif_info.exif_data));
+    memcpy(exif_info.exif_data, p_params->exif_info.exif_data,
+      sizeof(QEXIF_INFO_DATA) * p_params->exif_info.numOfEntries);
   }
 
-  p_params->exif_info.exif_data = p_session->exif_info_all;
-
-  if (p_params->exif_info.numOfEntries > 0) {
+  if (exif_info.numOfEntries > 0) {
     /* set exif tags */
     CDBG("%s:%d] Set exif tags count %d", __func__, __LINE__,
-      (int)p_params->exif_info.numOfEntries);
+      (int)exif_info.numOfEntries);
     rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME,
       &exif_idx);
     if (OMX_ErrorNone != rc) {
@@ -1052,7 +1064,7 @@
     }
 
     rc = OMX_SetParameter(p_session->omx_handle, exif_idx,
-      &p_params->exif_info);
+      &exif_info);
     if (OMX_ErrorNone != rc) {
       CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
       return rc;
@@ -1345,11 +1357,13 @@
     goto error;
   }
 
-  ret = OMX_EmptyThisBuffer(p_session->omx_handle,
-      p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
-  if (ret) {
-    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
-    goto error;
+  if (p_session->params.encode_thumbnail) {
+    ret = OMX_EmptyThisBuffer(p_session->omx_handle,
+        p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
+    if (ret) {
+      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+      goto error;
+    }
   }
 
   ret = OMX_FillThisBuffer(p_session->omx_handle,
diff --git a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_exif.c b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_exif.c
index 2ab2b4e..016c9ae 100644
--- a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_exif.c
+++ b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_exif.c
@@ -266,5 +266,3 @@
 
   return 0;
 }
-
-