QCamera2: Adds support for early preview restart

- This change will internally restart preview
  during the jpeg encoding stage in non-zsl.
  This feature can be enabled via this property:
  "persist.camera.feature.restart -> 0/1"

Change-Id: I3044b99cc0cac6c088d4435583aa2c703ba4ed8c
CRs-fixed: 547748
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index 41d486f..cd1b820 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -1581,16 +1581,24 @@
         break;
     case CAM_STREAM_TYPE_POSTVIEW:
         {
-            cam_dimension_t dim;
-            QCameraGrallocMemory *grallocMemory =
-                new QCameraGrallocMemory(mGetMemory);
+            if (isPreviewRestartEnabled()) {
+                mem = new QCameraStreamMemory(mGetMemory, bCachedMem);
+            } else {
+                cam_dimension_t dim;
+                QCameraGrallocMemory *grallocMemory =
+                    new QCameraGrallocMemory(mGetMemory);
 
-            mParameters.getStreamDimension(stream_type, dim);
-            if (grallocMemory)
-                grallocMemory->setWindowInfo(mPreviewWindow, dim.width,
-                    dim.height, stride, scanline,
-                    mParameters.getPreviewHalPixelFormat());
-            mem = grallocMemory;
+                mParameters.getStreamDimension(stream_type, dim);
+                if (grallocMemory) {
+                    grallocMemory->setWindowInfo(mPreviewWindow,
+                        dim.width,
+                        dim.height,
+                        stride,
+                        scanline,
+                        mParameters.getPreviewHalPixelFormat());
+                }
+                mem = grallocMemory;
+            }
         }
         break;
     case CAM_STREAM_TYPE_SNAPSHOT:
@@ -2581,18 +2589,24 @@
  *
  * DESCRIPTION: Stops capture channel
  *
- * PARAMETERS : none
+ * PARAMETERS :
+ *   @destroy : Set to true to stop and delete camera channel.
+ *              Set to false to only stop capture channel.
  *
  * RETURN     : int32_t type of status
  *              NO_ERROR  -- success
  *              none-zero failure code
  *==========================================================================*/
-int QCamera2HardwareInterface::stopCaptureChannel()
+int QCamera2HardwareInterface::stopCaptureChannel(bool destroy)
 {
     if (mParameters.isJpegPictureFormat() ||
         mParameters.isNV16PictureFormat() ||
         mParameters.isNV21PictureFormat()) {
         stopChannel(QCAMERA_CH_TYPE_CAPTURE);
+        if (destroy) {
+            // Destroy camera channel but dont release context
+            delChannel(QCAMERA_CH_TYPE_CAPTURE, false);
+        }
     }
 
     return NO_ERROR;
@@ -4435,16 +4449,22 @@
  *
  * PARAMETERS :
  *   @ch_type : channel type
+ *   @destroy : delete context as well
  *
  * RETURN     : int32_t type of status
  *              NO_ERROR  -- success
  *              none-zero failure code
  *==========================================================================*/
-int32_t QCamera2HardwareInterface::delChannel(qcamera_ch_type_enum_t ch_type)
+int32_t QCamera2HardwareInterface::delChannel(qcamera_ch_type_enum_t ch_type,
+                                              bool destroy)
 {
     if (m_channels[ch_type] != NULL) {
-        delete m_channels[ch_type];
-        m_channels[ch_type] = NULL;
+        if (destroy) {
+            delete m_channels[ch_type];
+            m_channels[ch_type] = NULL;
+        } else {
+            m_channels[ch_type]->deleteChannel();
+        }
     }
 
     return NO_ERROR;
@@ -5167,6 +5187,26 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : isPreviewRestartEnabled
+ *
+ * DESCRIPTION: Check whether preview should be restarted automatically
+ *              during image capture.
+ *
+ * PARAMETERS : none
+ *
+ * RETURN     : true: needed
+ *              false: no need
+ *==========================================================================*/
+bool QCamera2HardwareInterface::isPreviewRestartEnabled()
+{
+    char prop[PROPERTY_VALUE_MAX];
+    memset(prop, 0, sizeof(prop));
+    property_get("persist.camera.feature.restart", prop, "0");
+    int earlyRestart = atoi(prop);
+    return earlyRestart == 1;
+}
+
+/*===========================================================================
  * FUNCTION   : needReprocess
  *
  * DESCRIPTION: if reprocess is needed
diff --git a/QCamera2/HAL/QCamera2HWI.h b/QCamera2/HAL/QCamera2HWI.h
index 4d427da..f459d69 100644
--- a/QCamera2/HAL/QCamera2HWI.h
+++ b/QCamera2/HAL/QCamera2HWI.h
@@ -275,7 +275,7 @@
     int autoFocus();
     int cancelAutoFocus();
     int takePicture();
-    int stopCaptureChannel();
+    int stopCaptureChannel(bool destroy);
     int cancelPicture();
     int takeLiveSnapshot();
     int cancelLiveSnapshot();
@@ -316,6 +316,7 @@
 
     bool needDebugFps();
     bool isCACEnabled();
+    bool isPreviewRestartEnabled();
     bool needReprocess();
     bool needRotationReprocess();
     bool needScaleReprocess();
@@ -354,7 +355,7 @@
     int32_t addChannel(qcamera_ch_type_enum_t ch_type);
     int32_t startChannel(qcamera_ch_type_enum_t ch_type);
     int32_t stopChannel(qcamera_ch_type_enum_t ch_type);
-    int32_t delChannel(qcamera_ch_type_enum_t ch_type);
+    int32_t delChannel(qcamera_ch_type_enum_t ch_type, bool destroy = true);
     int32_t addPreviewChannel();
     int32_t addSnapshotChannel();
     int32_t addVideoChannel();
diff --git a/QCamera2/HAL/QCameraChannel.cpp b/QCamera2/HAL/QCameraChannel.cpp
index 5fcdd04..b09d71b 100644
--- a/QCamera2/HAL/QCameraChannel.cpp
+++ b/QCamera2/HAL/QCameraChannel.cpp
@@ -109,6 +109,29 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : deleteChannel
+ *
+ * DESCRIPTION: deletes a camera channel
+ *
+ * PARAMETERS : none
+ *
+ * RETURN     : none
+ *==========================================================================*/
+void QCameraChannel::deleteChannel()
+{
+    if (m_bIsActive) {
+        stop();
+    }
+
+    for (int i = 0; i < m_numStreams; i++) {
+        if (mStreams[i] != NULL) {
+            mStreams[i]->deleteStream();
+        }
+    }
+    m_camOps->delete_channel(m_camHandle, m_handle);
+}
+
+/*===========================================================================
  * FUNCTION   : init
  *
  * DESCRIPTION: initialization of channel
diff --git a/QCamera2/HAL/QCameraChannel.h b/QCamera2/HAL/QCameraChannel.h
index 53d51ba..6eeb724 100644
--- a/QCamera2/HAL/QCameraChannel.h
+++ b/QCamera2/HAL/QCameraChannel.h
@@ -69,6 +69,7 @@
     QCameraStream *getStreamByIndex(uint8_t index);
     QCameraStream *getStreamByServerID(uint32_t serverID);
     int32_t UpdateStreamBasedParameters(QCameraParameters &param);
+    void deleteChannel();
 
 protected:
     uint32_t m_camHandle;
diff --git a/QCamera2/HAL/QCameraStateMachine.cpp b/QCamera2/HAL/QCameraStateMachine.cpp
index ed68400..f90e24e 100644
--- a/QCamera2/HAL/QCameraStateMachine.cpp
+++ b/QCamera2/HAL/QCameraStateMachine.cpp
@@ -1687,7 +1687,17 @@
         break;
     case QCAMERA_SM_EVT_STOP_CAPTURE_CHANNEL:
         {
-            rc = m_parent->stopCaptureChannel();
+            bool restartPreview = m_parent->isPreviewRestartEnabled();
+            rc = m_parent->stopCaptureChannel(restartPreview);
+
+            if (restartPreview && (NO_ERROR == rc)) {
+                rc = m_parent->preparePreview();
+                if (NO_ERROR == rc) {
+                    m_parent->m_bPreviewStarted = true;
+                    rc = m_parent->startPreview();
+                }
+            }
+
             result.status = rc;
             result.request_api = evt;
             result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
@@ -1697,7 +1707,14 @@
     case QCAMERA_SM_EVT_SNAPSHOT_DONE:
         {
             rc = m_parent->cancelPicture();
-            m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
+
+            bool restartPreview = m_parent->isPreviewRestartEnabled();
+            if (restartPreview) {
+                m_state = QCAMERA_SM_STATE_PREVIEWING;
+            } else {
+                m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
+            }
+
             result.status = rc;
             result.request_api = evt;
             result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
diff --git a/QCamera2/HAL/QCameraStream.cpp b/QCamera2/HAL/QCameraStream.cpp
index f0c4b4d..10c2055 100644
--- a/QCamera2/HAL/QCameraStream.cpp
+++ b/QCamera2/HAL/QCameraStream.cpp
@@ -277,20 +277,14 @@
     pthread_mutex_destroy(&mCropLock);
     pthread_mutex_destroy(&mParameterLock);
 
-    if (mDefferedAllocation)
+    if (mDefferedAllocation) {
+        mStreamBufsAcquired = false;
         releaseBuffs();
-
-    if (mStreamInfoBuf != NULL) {
-        int rc = mCamOps->unmap_stream_buf(mCamHandle,
-                    mChannelHandle, mHandle, CAM_MAPPING_BUF_TYPE_STREAM_INFO, 0, -1);
-        if (rc < 0) {
-            ALOGE("Failed to map stream info buffer");
-        }
-        mStreamInfoBuf->deallocate();
-        delete mStreamInfoBuf;
-        mStreamInfoBuf = NULL;
     }
 
+    unmapStreamInfoBuf();
+    releaseStreamInfoBuf();
+
     // delete stream
     if (mHandle > 0) {
         mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle);
@@ -299,6 +293,80 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : unmapStreamInfoBuf
+ *
+ * DESCRIPTION: Unmap stream info buffer
+ *
+ * PARAMETERS :
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCameraStream::unmapStreamInfoBuf()
+{
+    int rc = NO_ERROR;
+
+    if (mStreamInfoBuf != NULL) {
+        rc = mCamOps->unmap_stream_buf(mCamHandle,
+            mChannelHandle,
+            mHandle,
+            CAM_MAPPING_BUF_TYPE_STREAM_INFO,
+            0,
+            -1);
+
+        if (rc < 0) {
+            ALOGE("Failed to unmap stream info buffer");
+        }
+    }
+
+    return rc;
+}
+
+/*===========================================================================
+ * FUNCTION   : releaseStreamInfoBuf
+ *
+ * DESCRIPTION: Release stream info buffer
+ *
+ * PARAMETERS :
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCameraStream::releaseStreamInfoBuf()
+{
+    int rc = NO_ERROR;
+
+    if (mStreamInfoBuf != NULL) {
+        mStreamInfoBuf->deallocate();
+        delete mStreamInfoBuf;
+        mStreamInfoBuf = NULL;
+    }
+
+    return rc;
+}
+
+/*===========================================================================
+ * FUNCTION   : deleteStream
+ *
+ * DESCRIPTION: Deletes a camera stream
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : None
+ *==========================================================================*/
+void QCameraStream::deleteStream()
+{
+    if (mHandle > 0) {
+        acquireStreamBufs();
+        releaseBuffs();
+        unmapStreamInfoBuf();
+        mCamOps->delete_stream(mCamHandle, mChannelHandle, mHandle);
+    }
+}
+
+/*===========================================================================
  * FUNCTION   : init
  *
  * DESCRIPTION: initialize stream obj
@@ -503,6 +571,11 @@
 {
     int32_t rc = 0;
 
+    if (!m_bActive) {
+        ALOGV("%s : Stream not active", __func__);
+        return NO_ERROR;
+    }
+
     // get stream param for crop info
     for (int i = 0; i < crop_info.num_of_streams; i++) {
         if (crop_info.crop_info[i].stream_id == mStreamInfo->stream_svr_id) {
@@ -958,16 +1031,19 @@
 {
     int rc = NO_ERROR;
 
-    for (int i = 0; i < mNumBufs; i++) {
-        rc = unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1);
-        if (rc < 0) {
-            ALOGE("%s: map_stream_buf failed: %d", __func__, rc);
+    if (NULL != mBufDefs) {
+        for (int i = 0; i < mNumBufs; i++) {
+            rc = unmapBuf(CAM_MAPPING_BUF_TYPE_STREAM_BUF, i, -1);
+            if (rc < 0) {
+                ALOGE("%s: map_stream_buf failed: %d", __func__, rc);
+            }
         }
+
+        // mBufDefs just keep a ptr to the buffer
+        // mm-camera-interface owns the buffer, so no need to free
+        mBufDefs = NULL;
+        memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset));
     }
-    // mBufDefs just keep a ptr to the buffer
-    // mm-camera-interface owns the buffer, so no need to free
-    mBufDefs = NULL;
-    memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset));
     if ( !mStreamBufsAcquired ) {
         mStreamBufs->deallocate();
         delete mStreamBufs;
diff --git a/QCamera2/HAL/QCameraStream.h b/QCamera2/HAL/QCameraStream.h
index 699612a..3a6f0dd 100644
--- a/QCamera2/HAL/QCameraStream.h
+++ b/QCamera2/HAL/QCameraStream.h
@@ -98,6 +98,7 @@
     static void releaseFrameData(void *data, void *user_data);
     int32_t configStream();
     bool isDeffered() const { return mDefferedAllocation; }
+    void deleteStream();
 
     int mDumpFrame;
     int mDumpMetaFrame;
@@ -170,6 +171,8 @@
     int32_t invalidateBuf(int index);
     int32_t cleanInvalidateBuf(int index);
     int32_t calcOffset(cam_stream_info_t *streamInfo);
+    int32_t unmapStreamInfoBuf();
+    int32_t releaseStreamInfoBuf();
     bool mDefferedAllocation;
 
 };