Camera2: Enable frameskip for thermal mitigation

Use system property to switch between fps adjustment
and isp frameskip.

For FPS adjustment, when maximum adjustment is needed,
instead of applying minimum fps range, apply minimum
fps for the minimum range.

Change-Id: I1704d6b8ccd590f95ae06bbdcd37869d18b554e0
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index 07985fb..b77f827 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -2104,69 +2104,13 @@
                                                 int threshold,
                                                 qcamera_thermal_level_enum_t level)
 {
-    int ret = NO_ERROR;
-    cam_fps_range_t adjustedRange;
-    int minFPS, maxFPS;
-
-    mParameters.getPreviewFpsRange(&minFPS, &maxFPS);
-
-    switch(level) {
-    case QCAMERA_THERMAL_NO_ADJUSTMENT:
-        {
-            adjustedRange.min_fps = minFPS/1000.0f;
-            adjustedRange.max_fps = maxFPS/1000.0f;
-        }
-        break;
-    case QCAMERA_THERMAL_SLIGHT_ADJUSTMENT:
-        {
-            adjustedRange.min_fps = minFPS/1000.0f;
-            adjustedRange.max_fps = (maxFPS / 2 ) / 1000.0f;
-            if ( adjustedRange.max_fps < adjustedRange.min_fps ) {
-                adjustedRange.max_fps = adjustedRange.min_fps;
-            }
-        }
-        break;
-    case QCAMERA_THERMAL_BIG_ADJUSTMENT:
-        {
-            adjustedRange.min_fps = minFPS/1000.0f;
-            adjustedRange.max_fps = adjustedRange.min_fps;
-        }
-        break;
-    case QCAMERA_THERMAL_SHUTDOWN:
-        {
-            // Stop Preview?
-            // Set lowest FPS range for now
-            adjustedRange.min_fps = minFPS/1000.0f;
-            adjustedRange.max_fps = maxFPS/1000.0f;
-            for ( int i = 0 ; i < gCamCapability[mCameraId]->fps_ranges_tbl_cnt ; i++ ) {
-                if ( gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps < adjustedRange.min_fps ) {
-                    adjustedRange.min_fps = gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps;
-                }
-                if ( gCamCapability[mCameraId]->fps_ranges_tbl[i].max_fps < adjustedRange.max_fps ) {
-                    adjustedRange.max_fps = gCamCapability[mCameraId]->fps_ranges_tbl[i].max_fps;
-                }
-            }
-        }
-        break;
-    default:
-        {
-            ALOGE("%s: Invalid thermal level %d", __func__, level);
-            return BAD_VALUE;
-        }
-        break;
-    }
-
-    ALOGI("%s: Thermal level %d, threshold %d, FPS range [%3.2f,%3.2f], name %s",
-          __func__,
-          level,
-          threshold,
-          adjustedRange.min_fps,
-          adjustedRange.max_fps,
-          name);
-
-    ret = processAPI(QCAMERA_SM_EVT_THERMAL_NOTIFY, &adjustedRange);
-
-    return ret;
+    // Make sure thermal events are logged
+    ALOGE("%s: name = %s, threshold = %d, level = %d",
+        __func__, name, threshold, level);
+    //We don't need to lockAPI, waitAPI here. QCAMERA_SM_EVT_THERMAL_NOTIFY
+    // becomes an aync call. This also means we can only pass payload
+    // by value, not by address.
+    return processAPI(QCAMERA_SM_EVT_THERMAL_NOTIFY, (void *)level);
 }
 
 /*===========================================================================
@@ -3267,20 +3211,92 @@
 }
 
 /*===========================================================================
- * FUNCTION   : updateThermalFPS
+ * FUNCTION   : updateThermalLevel
  *
- * DESCRIPTION: update FPS depending on thermal events
+ * DESCRIPTION: update thermal level depending on thermal events
  *
  * PARAMETERS :
- *   @fpsRange  : adjusted min/max FPS range
+ *   @level   : thermal level
  *
  * RETURN     : int32_t type of status
  *              NO_ERROR  -- success
  *              none-zero failure code
  *==========================================================================*/
-int QCamera2HardwareInterface::updateThermalFPS(cam_fps_range_t *fpsRange)
+int QCamera2HardwareInterface::updateThermalLevel(
+            qcamera_thermal_level_enum_t level)
 {
-    return mParameters.adjustPreviewFpsRange(fpsRange);
+    int ret = NO_ERROR;
+    cam_fps_range_t adjustedRange;
+    int minFPS, maxFPS;
+    qcamera_thermal_mode thermalMode = mParameters.getThermalMode();
+    enum msm_vfe_frame_skip_pattern skipPattern;
+
+    mParameters.getPreviewFpsRange(&minFPS, &maxFPS);
+
+    switch(level) {
+    case QCAMERA_THERMAL_NO_ADJUSTMENT:
+        {
+            adjustedRange.min_fps = minFPS/1000.0f;
+            adjustedRange.max_fps = maxFPS/1000.0f;
+            skipPattern = NO_SKIP;
+        }
+        break;
+    case QCAMERA_THERMAL_SLIGHT_ADJUSTMENT:
+        {
+            adjustedRange.min_fps = minFPS/1000.0f;
+            adjustedRange.max_fps = (maxFPS / 2 ) / 1000.0f;
+            if ( adjustedRange.max_fps < adjustedRange.min_fps ) {
+                adjustedRange.max_fps = adjustedRange.min_fps;
+            }
+            skipPattern = EVERY_2FRAME;
+        }
+        break;
+    case QCAMERA_THERMAL_BIG_ADJUSTMENT:
+        {
+            adjustedRange.min_fps = minFPS/1000.0f;
+            adjustedRange.max_fps = adjustedRange.min_fps;
+            skipPattern = EVERY_4FRAME;
+        }
+        break;
+    case QCAMERA_THERMAL_SHUTDOWN:
+        {
+            // Stop Preview?
+            // Set lowest min FPS for now
+            adjustedRange.min_fps = minFPS/1000.0f;
+            adjustedRange.max_fps = minFPS/1000.0f;
+            for ( int i = 0 ; i < gCamCapability[mCameraId]->fps_ranges_tbl_cnt ; i++ ) {
+                if ( gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps < adjustedRange.min_fps ) {
+                    adjustedRange.min_fps = gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps;
+                    adjustedRange.max_fps = adjustedRange.min_fps;
+                }
+            }
+            skipPattern = MAX_SKIP;
+        }
+        break;
+    default:
+        {
+            ALOGE("%s: Invalid thermal level %d", __func__, level);
+            return BAD_VALUE;
+        }
+        break;
+    }
+
+    ALOGI("%s: Thermal level %d, FPS range [%3.2f,%3.2f], frameskip %d",
+          __func__,
+          level,
+          adjustedRange.min_fps,
+          adjustedRange.max_fps,
+          skipPattern);
+
+    if (thermalMode == QCAMERA_THERMAL_ADJUST_FPS)
+        ret = mParameters.adjustPreviewFpsRange(&adjustedRange);
+    else if (thermalMode == QCAMERA_THERMAL_ADJUST_FRAMESKIP)
+        ret = mParameters.setFrameSkip(skipPattern);
+    else
+        ALOGE("%s: Incorrect thermal mode %d", __func__, thermalMode);
+
+    return ret;
+
 }
 
 /*===========================================================================
diff --git a/QCamera2/HAL/QCamera2HWI.h b/QCamera2/HAL/QCamera2HWI.h
index b29f12f..cbe1619 100644
--- a/QCamera2/HAL/QCamera2HWI.h
+++ b/QCamera2/HAL/QCamera2HWI.h
@@ -180,7 +180,7 @@
     void unlockAPI();
     void signalAPIResult(qcamera_api_result_t *result);
 
-    int updateThermalFPS(cam_fps_range_t *fpsRange);
+    int updateThermalLevel(qcamera_thermal_level_enum_t level);
 
     // update entris to set parameters and check if restart is needed
     int updateParameters(const char *parms, bool &needRestart);
diff --git a/QCamera2/HAL/QCameraParameters.cpp b/QCamera2/HAL/QCameraParameters.cpp
index fdc17a3..ba52b80 100644
--- a/QCamera2/HAL/QCameraParameters.cpp
+++ b/QCamera2/HAL/QCameraParameters.cpp
@@ -522,6 +522,18 @@
     m_bDebugFps = atoi(value) > 0 ? true : false;
     property_get("persist.camera.dumpimg", value, "0");
     m_nDumpFrameEnabled = atoi(value);
+
+    // For thermal mode, it should be set as system property
+    // because system property applies to all applications, while
+    // parameters only apply to specific app.
+    property_get("persist.camera.thermal.mode", value, "fps");
+    if (!strcmp(value, "frameskip")) {
+        m_ThermalMode = QCAMERA_THERMAL_ADJUST_FRAMESKIP;
+    } else {
+        if (strcmp(value, "fps"))
+            ALOGE("%s: Invalid camera thermal mode %s", __func__, value);
+        m_ThermalMode = QCAMERA_THERMAL_ADJUST_FPS;
+    }
 }
 
 /*===========================================================================
@@ -4901,6 +4913,46 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : setFrameSkip
+ *
+ * DESCRIPTION: send ISP frame skip pattern to camera daemon
+ *
+ * PARAMETERS :
+ *   @pattern : skip pattern for ISP
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCameraParameters::setFrameSkip(enum msm_vfe_frame_skip_pattern pattern)
+{
+    int32_t rc = NO_ERROR;
+    int32_t value = (int32_t)pattern;
+
+    if(initBatchUpdate(m_pParamBuf) < 0 ) {
+        ALOGE("%s:Failed to initialize group update table", __func__);
+        return BAD_TYPE;
+    }
+
+    rc = AddSetParmEntryToBatch(m_pParamBuf,
+                                CAM_INTF_PARM_FRAMESKIP,
+                                sizeof(value),
+                                &value);
+    if (rc != NO_ERROR) {
+        ALOGE("%s:Failed to update table", __func__);
+        return rc;
+    }
+
+    rc = commitSetBatch();
+    if (rc != NO_ERROR) {
+        ALOGE("%s:Failed to set frameskip info parm", __func__);
+        return rc;
+    }
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : parseNDimVector
  *
  * DESCRIPTION: helper function to parse a string like "(1, 2, 3, 4, ..., N)"
diff --git a/QCamera2/HAL/QCameraParameters.h b/QCamera2/HAL/QCameraParameters.h
index 1be811a..f101ee7 100644
--- a/QCamera2/HAL/QCameraParameters.h
+++ b/QCamera2/HAL/QCameraParameters.h
@@ -28,6 +28,7 @@
 #include <utils/Errors.h>
 #include "cam_intf.h"
 #include "QCameraMem.h"
+#include "QCameraThermalAdapter.h"
 
 extern "C" {
 #include <mm_jpeg_interface.h>
@@ -373,7 +374,9 @@
     int32_t setHistogram(bool enabled);
     int32_t setFaceDetection(bool enabled);
     int32_t setBundleInfo(cam_bundle_config_t &bundle_info);
+    int32_t setFrameSkip(enum msm_vfe_frame_skip_pattern pattern);
     int getEnabledFileDumpMask() {return m_nDumpFrameEnabled;};
+    qcamera_thermal_mode getThermalMode() {return m_ThermalMode;};
 
     cam_focus_mode_type getFocusMode() const {return mFocusMode;};
     bool isJpegPictureFormat() {return (mPictureFormat == CAMERA_PICTURE_TYPE_JPEG);};
@@ -533,6 +536,7 @@
     bool m_bNeedRestart;            // if preview needs restart after parameters updated
     bool m_bNoDisplayMode;
     bool m_bWNROn;
+    qcamera_thermal_mode m_ThermalMode; // adjust fps vs adjust frameskip
 
     DefaultKeyedVector<String8,String8> m_tempMap; // map for temororily store parameters to be set
 };
diff --git a/QCamera2/HAL/QCameraStateMachine.cpp b/QCamera2/HAL/QCameraStateMachine.cpp
index 8bc0ede..1e119dd 100644
--- a/QCamera2/HAL/QCameraStateMachine.cpp
+++ b/QCamera2/HAL/QCameraStateMachine.cpp
@@ -1062,7 +1062,8 @@
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
         {
-            rc = m_parent->updateThermalFPS((cam_fps_range_t *) payload);
+            rc = m_parent->updateThermalLevel(
+                    *(qcamera_thermal_level_enum_t *)&payload);
         }
         break;
     case QCAMERA_SM_EVT_JPEG_EVT_NOTIFY:
@@ -1607,7 +1608,8 @@
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
         {
-            rc = m_parent->updateThermalFPS((cam_fps_range_t *) payload);
+            rc = m_parent->updateThermalLevel(
+                    *(qcamera_thermal_level_enum_t *)&payload);
         }
         break;
     case QCAMERA_SM_EVT_JPEG_EVT_NOTIFY:
@@ -1890,7 +1892,8 @@
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
         {
-            rc = m_parent->updateThermalFPS((cam_fps_range_t *) payload);
+            rc = m_parent->updateThermalLevel(
+                    *(qcamera_thermal_level_enum_t *)&payload);
         }
         break;
     default:
@@ -2187,7 +2190,8 @@
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
         {
-            rc = m_parent->updateThermalFPS((cam_fps_range_t *) payload);
+            rc = m_parent->updateThermalLevel(
+                    *(qcamera_thermal_level_enum_t *)&payload);
         }
         break;
     default:
diff --git a/QCamera2/HAL/QCameraThermalAdapter.h b/QCamera2/HAL/QCameraThermalAdapter.h
index 4b37846..1c6f194 100644
--- a/QCamera2/HAL/QCameraThermalAdapter.h
+++ b/QCamera2/HAL/QCameraThermalAdapter.h
@@ -39,6 +39,11 @@
     QCAMERA_THERMAL_SHUTDOWN
 } qcamera_thermal_level_enum_t;
 
+typedef enum {
+    QCAMERA_THERMAL_ADJUST_FPS,
+    QCAMERA_THERMAL_ADJUST_FRAMESKIP,
+} qcamera_thermal_mode;
+
 class QCameraThermalCallback
 {
 public: