Merge "QCamera2: Support different color format for thumbnail"
diff --git a/Android.mk b/Android.mk
index fef381a..0d6f500 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,7 @@
 MM_V4L2_DRIVER_LIST += msm8960
 MM_V4L2_DRIVER_LIST += msm8974
 MM_V4L2_DRIVER_LIST += msm8226
+MM_V4L2_DRIVER_LIST += msm8610
 
 ifeq ($(call is-board-platform-in-list,$(MM_V4L2_DRIVER_LIST)),true)
   ifneq ($(USE_CAMERA_STUB),true)
diff --git a/QCamera/HAL/core/Android.mk b/QCamera/HAL/core/Android.mk
index df81ed4..f3160a8 100755
--- a/QCamera/HAL/core/Android.mk
+++ b/QCamera/HAL/core/Android.mk
@@ -31,6 +31,13 @@
         LOCAL_CFLAGS += -DCAMERA_ZSL_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
         LOCAL_CFLAGS += -DNUM_RECORDING_BUFFERS=9
+else ifeq ($(call is-board-platform,msm8610),true)
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_MM_HEAP
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
+        LOCAL_CFLAGS += -DCAMERA_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
+        LOCAL_CFLAGS += -DCAMERA_ZSL_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
+        LOCAL_CFLAGS += -DNUM_RECORDING_BUFFERS=9
 else ifeq ($(call is-board-platform,msm8960),true)
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_MM_HEAP
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index b6854f7..b2cf162 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -1023,6 +1023,7 @@
         ALOGE("Failure: Camera already opened");
         return ALREADY_EXISTS;
     }
+
     mCameraHandle = camera_open(mCameraId);
     if (!mCameraHandle) {
         ALOGE("camera_open failed.");
@@ -1036,6 +1037,8 @@
     int32_t rc = m_postprocessor.init(jpegEvtHandle, this);
     if (rc != 0) {
         ALOGE("Init Postprocessor failed");
+        mCameraHandle->ops->close_camera(mCameraHandle->camera_handle);
+        mCameraHandle = NULL;
         return UNKNOWN_ERROR;
     }
 
@@ -1080,6 +1083,10 @@
     int rc = NO_ERROR;
     int i;
 
+    if (!mCameraOpened) {
+        return NO_ERROR;
+    }
+
     // deinit Parameters
     mParameters.deinit();
 
@@ -1242,8 +1249,7 @@
     int bufferCnt = 0;
     int minCaptureBuffers = mParameters.getNumOfSnapshots();
 
-    int zslQBuffers = mParameters.getZSLQueueDepth() +
-                      mParameters.getMaxUnmatchedFramesInQueue();
+    int zslQBuffers = mParameters.getZSLQueueDepth();
 
     int minCircularBufNum = CAMERA_MIN_STREAMING_BUFFERS +
                             CAMERA_MIN_JPEG_ENCODING_BUFFERS +
@@ -2462,7 +2468,7 @@
 int32_t QCamera2HardwareInterface::processAutoFocusEvent(cam_auto_focus_data_t &focus_data)
 {
     int32_t ret = NO_ERROR;
-
+    ALOGD("%s: E",__func__);
     m_currentFocusState = focus_data.focus_state;
 
     cam_focus_mode_type focusMode = mParameters.getFocusMode();
@@ -2512,7 +2518,7 @@
         ALOGD("%s: no ops for autofocus event in focusmode %d", __func__, focusMode);
         break;
     }
-
+    ALOGD("%s: X",__func__);
     return ret;
 }
 
diff --git a/QCamera2/HAL/QCameraParameters.cpp b/QCamera2/HAL/QCameraParameters.cpp
index 827a01b..9913ad6 100644
--- a/QCamera2/HAL/QCameraParameters.cpp
+++ b/QCamera2/HAL/QCameraParameters.cpp
@@ -124,6 +124,7 @@
 const char QCameraParameters::PIXEL_FORMAT_YUV420SP_ADRENO[] = "yuv420sp-adreno";
 const char QCameraParameters::PIXEL_FORMAT_YV12[] = "yuv420p";
 const char QCameraParameters::PIXEL_FORMAT_NV12[] = "nv12";
+const char QCameraParameters::QC_PIXEL_FORMAT_NV12_VENUS[] = "nv12-venus";
 
 // Values for raw image formats
 const char QCameraParameters::QC_PIXEL_FORMAT_YUV_RAW_8BIT_YUYV[] = "yuv-raw8-yuyv";
@@ -307,7 +308,8 @@
     {PIXEL_FORMAT_YUV420P,         CAM_FORMAT_YUV_420_YV12},
     {PIXEL_FORMAT_YUV420SP_ADRENO, CAM_FORMAT_YUV_420_NV21_ADRENO},
     {PIXEL_FORMAT_YV12,            CAM_FORMAT_YUV_420_YV12},
-    {PIXEL_FORMAT_NV12,            CAM_FORMAT_YUV_420_NV12}
+    {PIXEL_FORMAT_NV12,            CAM_FORMAT_YUV_420_NV12},
+    {QC_PIXEL_FORMAT_NV12_VENUS,   CAM_FORMAT_YUV_420_NV12_VENUS}
 };
 
 const QCameraParameters::QCameraMap QCameraParameters::PICTURE_TYPES_MAP[] = {
@@ -555,6 +557,7 @@
       m_bNeedLockCAF(false),
       m_bCAFLocked(false),
       m_bAFRunning(false),
+      m_bInited(false),
       m_tempMap()
 {
     char value[32];
@@ -609,6 +612,7 @@
     m_bNeedLockCAF(false),
     m_bCAFLocked(false),
     m_bAFRunning(false),
+    m_bInited(false),
     m_tempMap()
 {
     memset(&m_LiveSnapshotSize, 0, sizeof(m_LiveSnapshotSize));
@@ -3313,6 +3317,8 @@
 
     initDefaultParameters();
 
+    m_bInited = true;
+
     goto TRANS_INIT_DONE;
 
 TRANS_INIT_ERROR2:
@@ -3337,6 +3343,10 @@
  *==========================================================================*/
 void QCameraParameters::deinit()
 {
+    if (!m_bInited) {
+        return;
+    }
+
     //clear all entries in the map
     String8 emptyStr;
     QCameraParameters::unflatten(emptyStr);
@@ -4935,6 +4945,9 @@
     case CAM_FORMAT_YUV_420_YV12:
         halPixelFormat = HAL_PIXEL_FORMAT_YV12;
         break;
+    case CAM_FORMAT_YUV_420_NV12_VENUS:
+        halPixelFormat = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;
+        break;
     case CAM_FORMAT_YUV_422_NV16:
     case CAM_FORMAT_YUV_422_NV61:
     default:
diff --git a/QCamera2/HAL/QCameraParameters.h b/QCamera2/HAL/QCameraParameters.h
index 0a47617..bd1cc89 100644
--- a/QCamera2/HAL/QCameraParameters.h
+++ b/QCamera2/HAL/QCameraParameters.h
@@ -176,6 +176,7 @@
     static const char PIXEL_FORMAT_YUV420SP_ADRENO[]; // ADRENO
     static const char PIXEL_FORMAT_YV12[]; // NV12
     static const char PIXEL_FORMAT_NV12[]; //NV12
+    static const char QC_PIXEL_FORMAT_NV12_VENUS[]; //NV12 VENUS
 
     // Values for raw picture format
     static const char QC_PIXEL_FORMAT_YUV_RAW_8BIT_YUYV[];
@@ -586,6 +587,7 @@
     bool m_bNeedLockCAF;
     bool m_bCAFLocked;
     bool m_bAFRunning;
+    bool m_bInited;
     qcamera_thermal_mode m_ThermalMode; // adjust fps vs adjust frameskip
     cam_dimension_t m_LiveSnapshotSize; // live snapshot size
 
diff --git a/QCamera2/HAL/QCameraPostProc.cpp b/QCamera2/HAL/QCameraPostProc.cpp
index f05fefa..1bcaa56 100644
--- a/QCamera2/HAL/QCameraPostProc.cpp
+++ b/QCamera2/HAL/QCameraPostProc.cpp
@@ -57,11 +57,13 @@
       m_pJpegExifObj(NULL),
       m_bThumbnailNeeded(TRUE),
       m_pReprocChannel(NULL),
+      m_bInited(FALSE),
       m_inputPPQ(releasePPInputData, this),
       m_ongoingPPQ(releaseOngoingPPData, this),
       m_inputJpegQ(releaseJpegData, this),
       m_ongoingJpegQ(releaseJpegData, this),
-      m_inputRawQ(releasePPInputData, this)
+      m_inputRawQ(releasePPInputData, this),
+      mRawBurstCount(0)
 {
     memset(&mJpegHandle, 0, sizeof(mJpegHandle));
 }
@@ -119,6 +121,7 @@
 
     m_dataProcTh.launch(dataProcessRoutine, this);
 
+    m_bInited = TRUE;
     return NO_ERROR;
 }
 
@@ -135,16 +138,18 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::deinit()
 {
-    m_dataProcTh.exit();
+    if (m_bInited == TRUE) {
+        m_dataProcTh.exit();
 
-    if(mJpegClientHandle > 0) {
-        int rc = mJpegHandle.close(mJpegClientHandle);
-        ALOGE("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
-              __func__, rc, mJpegClientHandle);
-        mJpegClientHandle = 0;
-        memset(&mJpegHandle, 0, sizeof(mJpegHandle));
+        if(mJpegClientHandle > 0) {
+            int rc = mJpegHandle.close(mJpegClientHandle);
+            ALOGE("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x",
+                  __func__, rc, mJpegClientHandle);
+            mJpegClientHandle = 0;
+            memset(&mJpegHandle, 0, sizeof(mJpegHandle));
+        }
+        m_bInited = FALSE;
     }
-
     return NO_ERROR;
 }
 
@@ -167,6 +172,11 @@
 int32_t QCameraPostProcessor::start(QCameraChannel *pSrcChannel)
 {
     int32_t rc = NO_ERROR;
+    if (m_bInited == FALSE) {
+        ALOGE("%s: postproc not initialized yet", __func__);
+        return UNKNOWN_ERROR;
+    }
+
     if (m_parent->needReprocess()) {
         if (m_pReprocChannel != NULL) {
             delete m_pReprocChannel;
@@ -190,7 +200,7 @@
 
     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE);
     m_parent->m_cbNotifier.startSnapshots();
-
+    mRawBurstCount = m_parent->numOfSnapshotsExpected();
     return rc;
 }
 
@@ -209,9 +219,11 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::stop()
 {
-    m_parent->m_cbNotifier.stopSnapshots();
-    // dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call
-    m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
+    if (m_bInited == TRUE) {
+        m_parent->m_cbNotifier.stopSnapshots();
+        // dataProc Thread need to process "stop" as sync call because abort jpeg job should be a sync call
+        m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE);
+    }
 
     return NO_ERROR;
 }
@@ -466,6 +478,11 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::processData(mm_camera_super_buf_t *frame)
 {
+    if (m_bInited == FALSE) {
+        ALOGE("%s: postproc not initialized yet", __func__);
+        return UNKNOWN_ERROR;
+    }
+
     if (m_parent->needReprocess()) {
         ALOGD("%s: need reprocess", __func__);
         // enqueu to post proc input queue
@@ -506,6 +523,11 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::processRawData(mm_camera_super_buf_t *frame)
 {
+    if (m_bInited == FALSE) {
+        ALOGE("%s: postproc not initialized yet", __func__);
+        return UNKNOWN_ERROR;
+    }
+
     // enqueu to raw input queue
     m_inputRawQ.enqueue((void *)frame);
     m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
@@ -531,6 +553,11 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::processJpegEvt(qcamera_jpeg_evt_payload_t *evt)
 {
+    if (m_bInited == FALSE) {
+        ALOGE("%s: postproc not initialized yet", __func__);
+        return UNKNOWN_ERROR;
+    }
+
     int32_t rc = NO_ERROR;
     camera_memory_t *jpeg_mem = NULL;
 
@@ -627,6 +654,11 @@
  *==========================================================================*/
 int32_t QCameraPostProcessor::processPPData(mm_camera_super_buf_t *frame)
 {
+    if (m_bInited == FALSE) {
+        ALOGE("%s: postproc not initialized yet", __func__);
+        return UNKNOWN_ERROR;
+    }
+
     qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue();
 
     if (job == NULL || job->src_frame == NULL) {
@@ -780,6 +812,11 @@
             free(app_cb->release_data.frame);
             app_cb->release_data.frame = NULL;
         }
+        if (app_cb && NULL != app_cb->release_data.streamBufs) {
+            app_cb->release_data.streamBufs->deallocate();
+            delete app_cb->release_data.streamBufs;
+            app_cb->release_data.streamBufs = NULL;
+        }
         free(app_cb);
     }
 }
@@ -1152,6 +1189,18 @@
         raw_mem = rawMemObj->getMemory(frame->buf_idx, false);
     }
 
+    QCameraChannel *pChannel = m_parent->getChannelByHandle(recvd_frame->ch_id);
+    if ( NULL == pChannel ) {
+        ALOGE("%s: Invalid channel", __func__);
+        return BAD_VALUE;
+    }
+
+    QCameraStream *pStream = pChannel->getStreamByHandle(frame->stream_id);
+    if ( NULL == pStream ) {
+        ALOGE("%s: Invalid stream", __func__);
+        return BAD_VALUE;
+    }
+
     if (NULL != rawMemObj && NULL != raw_mem) {
         // dump frame into file
         m_parent->dumpFrameToFile(frame->buffer, frame->frame_len,
@@ -1181,14 +1230,20 @@
 
         if ((m_parent->mDataCb != NULL) &&
             m_parent->msgTypeEnabledWithLock(CAMERA_MSG_COMPRESSED_IMAGE) > 0) {
+            mRawBurstCount--;
             qcamera_release_data_t release_data;
             memset(&release_data, 0, sizeof(qcamera_release_data_t));
-            release_data.frame = recvd_frame;
-            sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
-                           raw_mem,
-                           0,
-                           NULL,
-                           &release_data);
+            if ( 0 == mRawBurstCount ) {
+                release_data.streamBufs = rawMemObj;
+                pStream->acquireStreamBufs();
+            } else {
+                release_data.frame = recvd_frame;
+            }
+            rc = sendDataNotify(CAMERA_MSG_COMPRESSED_IMAGE,
+                                raw_mem,
+                                0,
+                                NULL,
+                                &release_data);
         }
     } else {
         ALOGE("%s: Cannot get raw mem", __func__);
diff --git a/QCamera2/HAL/QCameraPostProc.h b/QCamera2/HAL/QCameraPostProc.h
index 230f6df..3090b02 100644
--- a/QCamera2/HAL/QCameraPostProc.h
+++ b/QCamera2/HAL/QCameraPostProc.h
@@ -65,6 +65,7 @@
 typedef struct {
     camera_memory_t *        data;     // ptr to data memory struct
     mm_camera_super_buf_t *  frame;    // ptr to frame
+    QCameraMemory *          streamBufs; //ptr to stream buffers
 } qcamera_release_data_t;
 
 typedef struct {
@@ -149,12 +150,15 @@
     int8_t                     m_bThumbnailNeeded;
     QCameraReprocessChannel *  m_pReprocChannel;
 
+    int8_t                     m_bInited; // if postproc is inited
+
     QCameraQueue m_inputPPQ;            // input queue for postproc
     QCameraQueue m_ongoingPPQ;          // ongoing postproc queue
     QCameraQueue m_inputJpegQ;          // input jpeg job queue
     QCameraQueue m_ongoingJpegQ;        // ongoing jpeg job queue
     QCameraQueue m_inputRawQ;           // input raw job queue
     QCameraCmdThread m_dataProcTh;      // thread for data processing
+    uint32_t mRawBurstCount;            // current raw burst count
 };
 
 }; // namespace qcamera
diff --git a/QCamera2/HAL/QCameraStateMachine.cpp b/QCamera2/HAL/QCameraStateMachine.cpp
index 44ff872..42fe32e 100644
--- a/QCamera2/HAL/QCameraStateMachine.cpp
+++ b/QCamera2/HAL/QCameraStateMachine.cpp
@@ -1090,31 +1090,36 @@
     case QCAMERA_SM_EVT_TAKE_PICTURE:
        {
            if ( m_parent->mParameters.getRecordingHintValue() == false) {
-           rc = m_parent->takePicture();
-           if (rc == NO_ERROR) {
-               // move state to picture taking state
                if (m_parent->isZSLMode()) {
                    m_state = QCAMERA_SM_STATE_PREVIEW_PIC_TAKING;
+                   rc = m_parent->takePicture();
+                   if (rc != NO_ERROR) {
+                       // move state to previewing state
+                       m_state = QCAMERA_SM_STATE_PREVIEWING;
+                   }
                } else {
                    m_state = QCAMERA_SM_STATE_PIC_TAKING;
+                   rc = m_parent->takePicture();
+                   if (rc != NO_ERROR) {
+                       // move state to preview stopped state
+                       m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
+                   }
                }
-            } else {
-                // move state to preview stopped state
-                m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
-            }
-            result.status = rc;
-            result.request_api = evt;
-            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
-            m_parent->signalAPIResult(&result);
+
+               result.status = rc;
+               result.request_api = evt;
+               result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+               m_parent->signalAPIResult(&result);
            } else {
+               m_state = QCAMERA_SM_STATE_PREVIEW_PIC_TAKING;
                rc = m_parent->takeLiveSnapshot();
-               if (rc == NO_ERROR ) {
-                   m_state = QCAMERA_SM_STATE_PREVIEW_PIC_TAKING;
-                   result.status = rc;
-                   result.request_api = evt;
-                   result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
-                   m_parent->signalAPIResult(&result);
+               if (rc != NO_ERROR ) {
+                   m_state = QCAMERA_SM_STATE_PREVIEWING;
                }
+               result.status = rc;
+               result.request_api = evt;
+               result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+               m_parent->signalAPIResult(&result);
            }
         }
         break;
diff --git a/QCamera2/HAL/QCameraStream.cpp b/QCamera2/HAL/QCameraStream.cpp
index 7acff1d..20dfcb3 100644
--- a/QCamera2/HAL/QCameraStream.cpp
+++ b/QCamera2/HAL/QCameraStream.cpp
@@ -169,7 +169,8 @@
         mStreamInfoBuf(NULL),
         mStreamBufs(NULL),
         mAllocator(allocator),
-        mBufDefs(NULL)
+        mBufDefs(NULL),
+        mStreamBufsAcquired(false)
 {
     mMemVtbl.user_data = this;
     mMemVtbl.get_bufs = get_bufs;
@@ -666,8 +667,10 @@
     mBufDefs = NULL; // mBufDefs just keep a ptr to the buffer
                      // mm-camera-interface own the buffer, so no need to free
     memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset));
-    mStreamBufs->deallocate();
-    delete mStreamBufs;
+    if ( !mStreamBufsAcquired ) {
+        mStreamBufs->deallocate();
+        delete mStreamBufs;
+    }
 
     return rc;
 }
@@ -864,6 +867,24 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : acquireStreamBufs
+ *
+ * DESCRIPTION: acquire stream buffers and postpone their release.
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCameraStream::acquireStreamBufs()
+{
+    mStreamBufsAcquired = true;
+
+    return NO_ERROR;
+}
+
+/*===========================================================================
  * FUNCTION   : mapBuf
  *
  * DESCRIPTION: map stream related buffer to backend server
diff --git a/QCamera2/HAL/QCameraStream.h b/QCamera2/HAL/QCameraStream.h
index ab2e2f7..dabff26 100644
--- a/QCamera2/HAL/QCameraStream.h
+++ b/QCamera2/HAL/QCameraStream.h
@@ -79,6 +79,7 @@
     QCameraMemory *getStreamBufs() {return mStreamBufs;};
     uint32_t getMyServerID();
     cam_stream_type_t getMyType();
+    int32_t acquireStreamBufs();
 
     int32_t mapBuf(uint8_t buf_type, uint32_t buf_idx,
                    int32_t plane_idx, int fd, uint32_t size);
@@ -107,6 +108,7 @@
     cam_padding_info_t mPaddingInfo;
     cam_rect_t mCropInfo;
     pthread_mutex_t mCropLock; // lock to protect crop info
+    bool mStreamBufsAcquired;
 
     static int32_t get_bufs(
                      cam_frame_len_offset_t *offset,
diff --git a/QCamera2/HAL/test/qcamera_test.cpp b/QCamera2/HAL/test/qcamera_test.cpp
index 52c5415..49d423b 100644
--- a/QCamera2/HAL/test/qcamera_test.cpp
+++ b/QCamera2/HAL/test/qcamera_test.cpp
@@ -501,6 +501,7 @@
     mCamera.clear();
     mHardwareActive = false;
     mPreviewRunning = false;
+    mRecordRunning = false;
 
     return NO_ERROR;
 }
@@ -540,6 +541,7 @@
             return ret;
         }
 
+        mParams.set("recording-hint", "true");
         mParams.setPreviewSize(previewWidth, previewHeight);
         mParams.setPictureSize(currentPictureSize.width, currentPictureSize.height);
 
@@ -623,6 +625,52 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : startRecording
+ *
+ * DESCRIPTION: triggers start recording
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : status_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+status_t CameraContext::startRecording()
+{
+    status_t ret = NO_ERROR;
+
+    if ( mPreviewRunning ) {
+        ret = mCamera->startRecording();
+        mRecordRunning = true;
+    }
+
+    return ret;
+}
+
+/*===========================================================================
+ * FUNCTION   : stopRecording
+ *
+ * DESCRIPTION: triggers start recording
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : status_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+status_t CameraContext::stopRecording()
+{
+    status_t ret = NO_ERROR;
+
+    if ( mRecordRunning ) {
+        mCamera->stopRecording();
+        mRecordRunning = false;
+    }
+
+    return ret;
+}
+
+/*===========================================================================
  * FUNCTION   : stopPreview
  *
  * DESCRIPTION: stops camera preview
@@ -818,6 +866,10 @@
            CHANGE_PREVIEW_SIZE_CMD,
            currentPreviewSize.width,
            currentPreviewSize.height);
+    printf("   %c. Start Recording\n",
+            START_RECORD_CMD);
+    printf("   %c. Stop Recording\n",
+            STOP_RECORD_CMD);
     printf("   %c. Enable preview frames\n",
             ENABLE_PRV_CALLBACKS_CMD);
     printf("   %c. Trigger autofocus \n",
@@ -924,6 +976,18 @@
         }
         break;
 
+    case START_RECORD_CMD:
+        {
+            stat = currentCamera->startRecording();
+        }
+        break;
+
+    case STOP_RECORD_CMD:
+        {
+            stat = currentCamera->stopRecording();
+        }
+        break;
+
     case EXIT_CMD:
         {
             currentCamera->stopPreview();
diff --git a/QCamera2/HAL/test/qcamera_test.h b/QCamera2/HAL/test/qcamera_test.h
index 5bb8f67..3adf76c 100644
--- a/QCamera2/HAL/test/qcamera_test.h
+++ b/QCamera2/HAL/test/qcamera_test.h
@@ -41,6 +41,8 @@
     STOP_PREVIEW_CMD = '2',
     CHANGE_PREVIEW_SIZE_CMD = '4',
     CHANGE_PICTURE_SIZE_CMD = '5',
+    START_RECORD_CMD = '7',
+    STOP_RECORD_CMD = '8',
     DUMP_CAPS_CMD = 'E',
     AUTOFOCUS_CMD = 'f',
     TAKEPICTURE_CMD = 'p',
@@ -56,6 +58,7 @@
         mResizePreview(true),
         mHardwareActive(false),
         mPreviewRunning(false),
+        mRecordRunning(false),
         mCamera(NULL),
         mClient(NULL),
         mSurfaceControl(NULL),
@@ -70,6 +73,8 @@
     status_t autoFocus();
     status_t enablePreviewCallbacks();
     status_t takePicture();
+    status_t startRecording();
+    status_t stopRecording();
 
     status_t nextPreviewSize();
     status_t getCurrentPreviewSize(Size &previewSize);
@@ -108,6 +113,7 @@
     bool mResizePreview;
     bool mHardwareActive;
     bool mPreviewRunning;
+    bool mRecordRunning;
 
     sp<Camera> mCamera;
     sp<SurfaceComposerClient> mClient;
diff --git a/QCamera2/stack/common/cam_types.h b/QCamera2/stack/common/cam_types.h
index 5909b5b..f1b7255 100644
--- a/QCamera2/stack/common/cam_types.h
+++ b/QCamera2/stack/common/cam_types.h
@@ -72,6 +72,7 @@
     CAM_FORMAT_YUV_420_YV12,
     CAM_FORMAT_YUV_422_NV16,
     CAM_FORMAT_YUV_422_NV61,
+    CAM_FORMAT_YUV_420_NV12_VENUS,
 
     /* Please note below are the defintions for raw image.
      * Any format other than raw image format should be declared
diff --git a/QCamera2/stack/mm-camera-interface/Android.mk b/QCamera2/stack/mm-camera-interface/Android.mk
index bbdda7c..1e5af1e 100755
--- a/QCamera2/stack/mm-camera-interface/Android.mk
+++ b/QCamera2/stack/mm-camera-interface/Android.mk
@@ -16,7 +16,7 @@
     LOCAL_CFLAGS += -DUSE_ION
 endif
 
-ifeq ($(call is-board-platform-in-list,msm8974 msm8226),true)
+ifeq ($(call is-board-platform-in-list,msm8974 msm8226 msm8610),true)
     LOCAL_CFLAGS += -DVENUS_PRESENT
 endif
 
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 ff1b93b..c79c3c4 100644
--- a/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
+++ b/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
@@ -1595,6 +1595,7 @@
     uint32_t val;
     switch(fmt) {
     case CAM_FORMAT_YUV_420_NV12:
+    case CAM_FORMAT_YUV_420_NV12_VENUS:
         val = V4L2_PIX_FMT_NV12;
         break;
     case CAM_FORMAT_YUV_420_NV21:
@@ -1782,6 +1783,35 @@
                         buf_planes->plane_info.mp[1].len,
                         CAM_PAD_TO_4K);
         break;
+    case CAM_FORMAT_YUV_420_NV12_VENUS:
+#ifdef VENUS_PRESENT
+        // using Venus
+        stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, dim->width);
+        scanline = VENUS_Y_SCANLINES(COLOR_FMT_NV12, dim->height);
+
+        buf_planes->plane_info.frame_len =
+            VENUS_BUFFER_SIZE(COLOR_FMT_NV12, dim->width, dim->height);
+        buf_planes->plane_info.num_planes = 2;
+        buf_planes->plane_info.mp[0].len = stride * scanline;
+        buf_planes->plane_info.mp[0].offset = 0;
+        buf_planes->plane_info.mp[0].offset_x =0;
+        buf_planes->plane_info.mp[0].offset_y = 0;
+        buf_planes->plane_info.mp[0].stride = stride;
+        buf_planes->plane_info.mp[0].scanline = scanline;
+        stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, dim->width);
+        scanline = VENUS_UV_SCANLINES(COLOR_FMT_NV12, dim->height);
+        buf_planes->plane_info.mp[1].len =
+            buf_planes->plane_info.frame_len - buf_planes->plane_info.mp[0].len;
+        buf_planes->plane_info.mp[1].offset = 0;
+        buf_planes->plane_info.mp[1].offset_x =0;
+        buf_planes->plane_info.mp[1].offset_y = 0;
+        buf_planes->plane_info.mp[1].stride = stride;
+        buf_planes->plane_info.mp[1].scanline = scanline;
+#else
+        CDBG_ERROR("%s: Venus hardware not avail, cannot use this format", __func__);
+        rc = -1;
+#endif
+        break;
     default:
         CDBG_ERROR("%s: Invalid cam_format for preview %d",
                    __func__, fmt);
diff --git a/QCamera2/stack/mm-camera-test/Android.mk b/QCamera2/stack/mm-camera-test/Android.mk
index 3e6ceaa..c4eccda 100644
--- a/QCamera2/stack/mm-camera-test/Android.mk
+++ b/QCamera2/stack/mm-camera-test/Android.mk
@@ -47,6 +47,12 @@
         LOCAL_CFLAGS += -DCAMERA_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
         LOCAL_CFLAGS += -DNUM_RECORDING_BUFFERS=9
+else ifeq ($(call is-board-platform,msm8610),true)
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_MM_HEAP
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
+        LOCAL_CFLAGS += -DCAMERA_ION_FALLBACK_HEAP_ID=ION_IOMMU_HEAP_ID
+        LOCAL_CFLAGS += -DCAMERA_GRALLOC_CACHING_ID=0
+        LOCAL_CFLAGS += -DNUM_RECORDING_BUFFERS=9
 else ifeq ($(call is-board-platform,msm8960),true)
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
         LOCAL_CFLAGS += -DCAMERA_GRALLOC_FALLBACK_HEAP_ID=GRALLOC_USAGE_PRIVATE_IOMMU_HEAP
diff --git a/QCamera2/stack/mm-jpeg-interface/Android.mk b/QCamera2/stack/mm-jpeg-interface/Android.mk
index a157602..5b15f05 100644
--- a/QCamera2/stack/mm-jpeg-interface/Android.mk
+++ b/QCamera2/stack/mm-jpeg-interface/Android.mk
@@ -24,7 +24,8 @@
     src/mm_jpeg_queue.c \
     src/mm_jpeg_exif.c \
     src/mm_jpeg.c \
-    src/mm_jpeg_interface.c
+    src/mm_jpeg_interface.c \
+    src/mm_jpeg_ionbuf.c
 
 LOCAL_MODULE           := libmmjpeg_interface
 LOCAL_PRELINK_MODULE   := false
diff --git a/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
index 593c7d4..1f3e239 100644
--- a/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
+++ b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
@@ -38,11 +38,13 @@
 #include "OMX_Core.h"
 #include "OMX_Component.h"
 #include "QOMX_JpegExtensions.h"
+#include "mm_jpeg_ionbuf.h"
 
 #define MM_JPEG_MAX_THREADS 30
 #define MM_JPEG_CIRQ_SIZE 30
 #define MM_JPEG_MAX_SESSION 10
 #define MAX_EXIF_TABLE_ENTRIES 50
+#define MAX_JPEG_SIZE 18000000
 
 typedef struct {
   struct cam_list list;
@@ -120,6 +122,9 @@
   int job_hist;
 
   OMX_BOOL encoding;
+
+  buffer_t work_buffer;
+
 } mm_jpeg_job_session_t;
 
 typedef struct {
@@ -158,6 +163,7 @@
   pthread_mutex_t job_lock;                       /* job lock */
   mm_jpeg_job_cmd_thread_t job_mgr;               /* job mgr thread including todo_q*/
   mm_jpeg_queue_t ongoing_job_q;                  /* queue for ongoing jobs */
+  buffer_t ionBuffer;
 } mm_jpeg_obj;
 
 extern int32_t mm_jpeg_init(mm_jpeg_obj *my_obj);
diff --git a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.h b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg_ionbuf.h
similarity index 95%
rename from QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.h
rename to QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg_ionbuf.h
index 7bc62cc..3bdd7eb 100644
--- a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.h
+++ b/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg_ionbuf.h
@@ -47,7 +47,7 @@
   long size;
   int ion_fd;
   uint8_t *addr;
-} buffer_test_t;
+} buffer_t;
 
 /** buffer_allocate:
  *
@@ -61,7 +61,7 @@
  *      allocates ION buffer
  *
  **/
-void* buffer_allocate(buffer_test_t *p_buffer);
+void* buffer_allocate(buffer_t *p_buffer, int cached);
 
 /** buffer_deallocate:
  *
@@ -75,7 +75,7 @@
  *      deallocates ION buffer
  *
  **/
-int buffer_deallocate(buffer_test_t *p_buffer);
+int buffer_deallocate(buffer_t *p_buffer);
 
 #endif
 
diff --git a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
index 8632dce..5d8562e 100644
--- a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
+++ b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
@@ -45,6 +45,8 @@
 
 #define JOB_ID_MAGICVAL 0x1
 #define JOB_HIST_MAX 10000
+#define ENCODING_MODE_PARALLEL 0
+
 
 /** DUMP_TO_FILE:
  *  @filename: file name
@@ -485,6 +487,7 @@
 void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session)
 {
   OMX_ERRORTYPE rc = OMX_ErrorNone;
+  OMX_STATETYPE state;
 
   CDBG("%s:%d] E", __func__, __LINE__);
   if (NULL == p_session->omx_handle) {
@@ -492,15 +495,24 @@
     return;
   }
 
-  rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
-  if (rc) {
-    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+  rc = OMX_GetState(p_session->omx_handle, &state);
+
+  //Check state before state transition
+  if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) {
+    rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
+    if (rc) {
+      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+    }
   }
 
-  rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
-    mm_jpeg_session_free_buffers);
-  if (rc) {
-    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+  rc = OMX_GetState(p_session->omx_handle, &state);
+
+  if (state == OMX_StateIdle) {
+    rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
+      mm_jpeg_session_free_buffers);
+    if (rc) {
+      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+    }
   }
 
   rc = OMX_FreeHandle(p_session->omx_handle);
@@ -513,6 +525,7 @@
   if (rc) {
     CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc);
   }
+
   pthread_mutex_destroy(&p_session->lock);
   pthread_cond_destroy(&p_session->cond);
   CDBG("%s:%d] X", __func__, __LINE__);
@@ -608,11 +621,13 @@
     return rc;
   }
 
-  CDBG_HIGH("%s:%d] OMX_Serial_Encoding = %d, OMX_Parallel_Encoding = %d ", __func__, __LINE__,
-    (int)OMX_Serial_Encoding,
-    (int)OMX_Parallel_Encoding);
-
+ if(ENCODING_MODE_PARALLEL){
+   encoding_mode = OMX_Parallel_Encoding;
+ } else {
   encoding_mode = OMX_Serial_Encoding;
+ }
+  CDBG_HIGH("%s:%d] encoding mode = %d ", __func__, __LINE__,
+    (int)encoding_mode);
   rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode);
   if (rc != OMX_ErrorNone) {
     CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
@@ -858,25 +873,6 @@
   thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
   thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
 
-  if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) ||
-    (p_main_dim->src_dim.height < p_thumb_dim->src_dim.height)) {
-    CDBG_ERROR("%s:%d] Improper thumbnail dim %dx%d resetting to %dx%d",
-      __func__, __LINE__,
-      p_thumb_dim->src_dim.width,
-      p_thumb_dim->src_dim.height,
-      p_main_dim->src_dim.width,
-      p_main_dim->src_dim.height);
-    thumbnail_info.input_width = p_main_dim->src_dim.width;
-    thumbnail_info.input_height = p_main_dim->src_dim.height;
-    if ((thumbnail_info.crop_info.nWidth > thumbnail_info.input_width)
-      || (thumbnail_info.crop_info.nHeight > thumbnail_info.input_height)) {
-      thumbnail_info.crop_info.nLeft = 0;
-      thumbnail_info.crop_info.nTop = 0;
-      thumbnail_info.crop_info.nWidth = thumbnail_info.input_width;
-      thumbnail_info.crop_info.nHeight = thumbnail_info.input_height;
-    }
-  }
-
   if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width)
     || (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) {
     CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",
@@ -900,7 +896,7 @@
   p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset;
   p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset;
 
-  ret = OMX_SetParameter(p_session->omx_handle, thumb_indextype,
+  ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype,
     &thumbnail_info);
   if (ret) {
     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
@@ -1009,8 +1005,6 @@
 OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session)
 {
   OMX_ERRORTYPE rc = OMX_ErrorNone;
-  OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
-  mm_jpeg_encode_params_t *p_params = &p_session->params;
   mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
 
   /* config port */
@@ -1028,26 +1022,6 @@
     CDBG_ERROR("%s: config buffer offset failed", __func__);
     return rc;
   }
-
-  /* config crop */
-  CDBG("%s:%d] config main crop", __func__, __LINE__);
-  rc = mm_jpeg_session_config_main_crop(p_session);
-  if (OMX_ErrorNone != rc) {
-    CDBG_ERROR("%s: config crop failed", __func__);
-    return rc;
-  }
-
-  /* set quality */
-  memset(&q_factor, 0, sizeof(q_factor));
-  q_factor.nPortIndex = 0;
-  q_factor.nQFactor = p_params->quality;
-  rc = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor);
-  CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
-  if (OMX_ErrorNone != rc) {
-    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
-    return rc;
-  }
-
   return rc;
 }
 
@@ -1094,7 +1068,7 @@
   /*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);
+      (int)p_params->exif_info.numOfEntries);
     memcpy(exif_info.exif_data, p_params->exif_info.exif_data,
       sizeof(QEXIF_INFO_DATA) * p_params->exif_info.numOfEntries);
   }
@@ -1110,7 +1084,7 @@
       return rc;
     }
 
-    rc = OMX_SetParameter(p_session->omx_handle, exif_idx,
+    rc = OMX_SetConfig(p_session->omx_handle, exif_idx,
       &exif_info);
     if (OMX_ErrorNone != rc) {
       CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
@@ -1257,6 +1231,87 @@
   return p_session;
 }
 
+/** mm_jpeg_configure_params
+ *
+ *  Arguments:
+ *    @p_session: encode session
+ *
+ *  Return:
+ *       none
+ *
+ *  Description:
+ *       Configure the job specific params
+ *
+ **/
+static OMX_ERRORTYPE mm_jpeg_configure_job_params(mm_jpeg_job_session_t *p_session)
+{
+  OMX_ERRORTYPE ret = OMX_ErrorNone;
+  OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
+  QOMX_WORK_BUFFER work_buffer;
+  OMX_INDEXTYPE work_buffer_index;
+  mm_jpeg_encode_params_t *p_params = &p_session->params;
+  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
+
+    /* common config */
+  ret = mm_jpeg_session_config_common(p_session);
+  if (OMX_ErrorNone != ret) {
+    CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);
+
+  }
+
+  /* config Main Image crop */
+  CDBG("%s:%d] config main crop", __func__, __LINE__);
+  ret = mm_jpeg_session_config_main_crop(p_session);
+  if (OMX_ErrorNone != ret) {
+    CDBG_ERROR("%s: config crop failed", __func__);
+    return ret;
+  }
+
+  /* set quality */
+  memset(&q_factor, 0, sizeof(q_factor));
+  q_factor.nPortIndex = 0;
+  q_factor.nQFactor = p_params->quality;
+  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor);
+  CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
+  if (OMX_ErrorNone != ret) {
+    CDBG_ERROR("%s:%d] Error setting Q factor %d", __func__, __LINE__, ret);
+    return ret;
+  }
+
+  /* config thumbnail */
+  ret = mm_jpeg_session_config_thumbnail(p_session);
+  if (OMX_ErrorNone != ret) {
+    CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
+    return ret;
+  }
+
+  if (ENCODING_MODE_PARALLEL) {
+  //Pass the ION buffer to be used as o/p for HW
+  memset(&work_buffer, 0x0, sizeof(QOMX_WORK_BUFFER));
+  ret = OMX_GetExtensionIndex(p_session->omx_handle,
+    QOMX_IMAGE_EXT_WORK_BUFFER_NAME,
+    &work_buffer_index);
+  if (ret) {
+    CDBG_ERROR("%s:%d] Error getting work buffer index %d",
+      __func__, __LINE__, ret);
+    return ret;
+  }
+  work_buffer.fd = p_session->work_buffer.ion_fd;
+  work_buffer.vaddr = p_session->work_buffer.addr;
+
+  ret = OMX_SetConfig(p_session->omx_handle, work_buffer_index,
+    &work_buffer);
+  if (ret) {
+    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+    return ret;
+  }
+
+  }
+
+  return ret;
+
+}
+
 /** mm_jpeg_session_configure:
  *
  *  Arguments:
@@ -1286,29 +1341,6 @@
     CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
     goto error;
   }
-
-  /* config thumbnail */
-  ret = mm_jpeg_session_config_thumbnail(p_session);
-  if (OMX_ErrorNone != ret) {
-    CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
-    goto error;
-  }
-
-  /* config encoding mode */
-  CDBG("%s:%d] config encoding mode", __func__, __LINE__);
-  ret = mm_jpeg_encoding_mode(p_session);
-  if (OMX_ErrorNone != ret) {
-    CDBG_ERROR("%s: config encoding mode failed", __func__);
-    return ret;
-  }
-
-  /* common config */
-  ret = mm_jpeg_session_config_common(p_session);
-  if (OMX_ErrorNone != ret) {
-    CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);
-    goto error;
-  }
-
   ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
     mm_jpeg_session_send_buffers);
   if (ret) {
@@ -1393,6 +1425,11 @@
     p_session->config = OMX_TRUE;
   }
 
+  ret = mm_jpeg_configure_job_params(p_session);
+  if (ret) {
+      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
+      goto error;
+  }
   pthread_mutex_lock(&p_session->lock);
   p_session->encoding = OMX_TRUE;
   pthread_mutex_unlock(&p_session->lock);
@@ -1668,10 +1705,24 @@
     return -1;
   }
 
+  //Allocate Ion buffer of max jpeg size
+  if (ENCODING_MODE_PARALLEL) {
+    my_obj->ionBuffer.size = MAX_JPEG_SIZE;
+    my_obj->ionBuffer.addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer, 0);
+    if (NULL == my_obj->ionBuffer.addr) {
+      mm_jpeg_jobmgr_thread_release(my_obj);
+      mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
+      pthread_mutex_destroy(&my_obj->job_lock);
+      CDBG_ERROR("%s:%d] Ion allocation failed",__func__, __LINE__);
+      return -1;
+    }
+  }
+
   /* load OMX */
   if (OMX_ErrorNone != OMX_Init()) {
     /* roll back in error case */
     CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
+    buffer_deallocate(&my_obj->ionBuffer);
     mm_jpeg_jobmgr_thread_release(my_obj);
     mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
     pthread_mutex_destroy(&my_obj->job_lock);
@@ -1711,6 +1762,14 @@
     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
   }
 
+  if (ENCODING_MODE_PARALLEL) {
+    /*Release the ION buffer*/
+    rc = buffer_deallocate(&my_obj->ionBuffer);
+    if (0 != rc) {
+          CDBG_ERROR("%s:%d] Error releasing ION buffer", __func__, __LINE__);
+    }
+  }
+
   /* destroy locks */
   pthread_mutex_destroy(&my_obj->job_lock);
 
@@ -1946,6 +2005,8 @@
     return rc;
   }
 
+  p_session->work_buffer = my_obj->ionBuffer;
+
   ret = mm_jpeg_session_create(p_session);
   if (OMX_ErrorNone != ret) {
     p_session->active = OMX_FALSE;
diff --git a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_interface.c b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_interface.c
index 4ffaeba..d507444 100644
--- a/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_interface.c
+++ b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_interface.c
@@ -156,7 +156,7 @@
     return rc;
   }
 
-  rc = mm_jpeg_create_session(g_jpeg_obj, client_hdl, p_params, p_session_id);
+ rc = mm_jpeg_create_session(g_jpeg_obj, client_hdl, p_params, p_session_id);
   pthread_mutex_unlock(&g_intf_lock);
   return rc;
 }
diff --git a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.c b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_ionbuf.c
similarity index 95%
rename from QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.c
rename to QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_ionbuf.c
index fbfcd6a..e55a511 100644
--- a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_ionbuf.c
+++ b/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg_ionbuf.c
@@ -42,7 +42,7 @@
  *      allocates ION buffer
  *
  **/
-void *buffer_allocate(buffer_test_t *p_buffer)
+void *buffer_allocate(buffer_t *p_buffer, int cached)
 {
   void *l_buffer = NULL;
 
@@ -51,7 +51,7 @@
 
    p_buffer->alloc.len = p_buffer->size;
    p_buffer->alloc.align = 4096;
-   p_buffer->alloc.flags = ION_FLAG_CACHED;
+   p_buffer->alloc.flags = (cached) ? ION_FLAG_CACHED : 0;
    p_buffer->alloc.heap_mask = 0x1 << ION_IOMMU_HEAP_ID;
 
    p_buffer->ion_fd = open("/dev/ion", O_RDONLY);
@@ -111,7 +111,7 @@
  *      deallocates ION buffer
  *
  **/
-int buffer_deallocate(buffer_test_t *p_buffer)
+int buffer_deallocate(buffer_t *p_buffer)
 {
   int lrc = 0;
   int lsize = (p_buffer->size + 4095) & (~4095);
diff --git a/QCamera2/stack/mm-jpeg-interface/test/Android.mk b/QCamera2/stack/mm-jpeg-interface/test/Android.mk
index 1e73331..0a799b0 100644
--- a/QCamera2/stack/mm-jpeg-interface/test/Android.mk
+++ b/QCamera2/stack/mm-jpeg-interface/test/Android.mk
@@ -31,8 +31,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 
-LOCAL_SRC_FILES := mm_jpeg_ionbuf.c
-LOCAL_SRC_FILES += mm_jpeg_test.c 
+LOCAL_SRC_FILES := mm_jpeg_test.c
 
 LOCAL_MODULE           := mm-jpeg-interface-test
 LOCAL_PRELINK_MODULE   := false
diff --git a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_test.c b/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_test.c
index b3b9ac8..bc98fa6 100644
--- a/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_test.c
+++ b/QCamera2/stack/mm-jpeg-interface/test/mm_jpeg_test.c
@@ -69,8 +69,8 @@
   char *out_filename;
   pthread_mutex_t lock;
   pthread_cond_t cond;
-  buffer_test_t input;
-  buffer_test_t output;
+  buffer_t input;
+  buffer_t output;
   int use_ion;
   uint32_t handle;
   mm_jpeg_ops_t ops;
@@ -103,12 +103,12 @@
   }
 }
 
-int mm_jpeg_test_alloc(buffer_test_t *p_buffer, int use_pmem)
+int mm_jpeg_test_alloc(buffer_t *p_buffer, int use_pmem)
 {
   int ret = 0;
   /*Allocate buffers*/
   if (use_pmem) {
-    p_buffer->addr = (uint8_t *)buffer_allocate(p_buffer);
+    p_buffer->addr = (uint8_t *)buffer_allocate(p_buffer, 0);
     if (NULL == p_buffer->addr) {
       CDBG_ERROR("%s:%d] Error",__func__, __LINE__);
       return -1;
@@ -124,7 +124,7 @@
   return ret;
 }
 
-void mm_jpeg_test_free(buffer_test_t *p_buffer)
+void mm_jpeg_test_free(buffer_t *p_buffer)
 {
   if (p_buffer->addr == NULL)
     return;
@@ -134,7 +134,7 @@
   else
     free(p_buffer->addr);
 
-  memset(p_buffer, 0x0, sizeof(buffer_test_t));
+  memset(p_buffer, 0x0, sizeof(buffer_t));
 }
 
 int mm_jpeg_test_read(mm_jpeg_intf_test_t *p_obj)
diff --git a/mm-image-codec/qomx_core/QOMX_JpegExtensions.h b/mm-image-codec/qomx_core/QOMX_JpegExtensions.h
index 3aa7f70..5c9b1c1 100644
--- a/mm-image-codec/qomx_core/QOMX_JpegExtensions.h
+++ b/mm-image-codec/qomx_core/QOMX_JpegExtensions.h
@@ -55,6 +55,7 @@
 #define QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME "OMX.QCOM.image.exttype.bufferOffset"
 #define QOMX_IMAGE_EXT_MOBICAT_NAME            "OMX.QCOM.image.exttype.mobicat"
 #define QOMX_IMAGE_EXT_ENCODING_MODE_NAME        "OMX.QCOM.image.encoding.mode"
+#define QOMX_IMAGE_EXT_WORK_BUFFER_NAME      "OMX.QCOM.image.exttype.workbuffer"
 
 /** QOMX_IMAGE_EXT_INDEXTYPE
 *  This enum is an extension of the OMX_INDEXTYPE enum and
@@ -79,6 +80,9 @@
   //Name: OMX.QCOM.image.encoding.approach
   QOMX_IMAGE_EXT_ENCODING_MODE = 0x07F00004,
 
+  //Name: OMX.QCOM.image.exttype.workbuffer
+  QOMX_IMAGE_EXT_WORK_BUFFER = 0x07F00004,
+
 } QOMX_IMAGE_EXT_INDEXTYPE;
 
 /** QOMX_BUFFER_INFO
@@ -180,6 +184,16 @@
   OMX_U32 mobicatDataLength;
 } QOMX_MOBICAT;
 
+/**qomx_workbuffer
+*  Ion buffer to be used for the H/W encoder
+*  @fd - FD of the buffer allocated
+*  @vaddr - Buffer address
+**/
+typedef struct {
+  int fd;
+  uint8_t *vaddr;
+} QOMX_WORK_BUFFER;
+
 /** QOMX_IMG_COLOR_FORMATTYPE
 *  This enum is an extension of the OMX_COLOR_FORMATTYPE enum.
 *  It specifies Qcom supported color formats.