stagefright: update temporal layering selection in MediaRecorder

- Use max expected decode framerate to decide on number of layers
- Optimize for decoding on 30fps display (battery saver mode)

Bug: 27596987
Change-Id: I8902b4a78670cb0aebb8bccd640367e262f172b2
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index b03ae3f..653c30f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -59,6 +59,11 @@
 
 namespace android {
 
+static const float kTypicalDisplayRefreshingRate = 60.f;
+// display refresh rate drops on battery saver
+static const float kMinTypicalDisplayRefreshingRate = kTypicalDisplayRefreshingRate / 2;
+static const int kMaxNumVideoTemporalLayers = 8;
+
 // To collect the encoder usage for the battery app
 static void addBatteryData(uint32_t params) {
     sp<IBinder> binder =
@@ -1567,25 +1572,39 @@
         format->setInt32("level", mVideoEncoderLevel);
     }
 
-    uint32_t tsLayers = 0;
+    uint32_t tsLayers = 1;
     format->setInt32("priority", 0 /* realtime */);
+    float maxPlaybackFps = mFrameRate; // assume video is only played back at normal speed
+
     if (mCaptureFpsEnable) {
         format->setFloat("operating-rate", mCaptureFps);
 
         // enable layering for all time lapse and high frame rate recordings
-        if (mFrameRate / mCaptureFps >= 1.9 || mCaptureFps / mFrameRate >= 1.9) {
-            tsLayers = 2; // use at least two layers
-            for (float fps = mCaptureFps / 1.9; fps > mFrameRate; fps /= 2) {
-                ++tsLayers;
-            }
-
-            uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
-            uint32_t pLayers = tsLayers - bLayers;
-            format->setString(
-                    "ts-schema", AStringPrintf("android.generic.%u+%u", pLayers, bLayers));
+        if (mFrameRate / mCaptureFps >= 1.9) { // time lapse
+            tsLayers = 2; // use at least two layers as resulting video will likely be sped up
+        } else if (mCaptureFps > maxPlaybackFps) { // slow-mo
+            maxPlaybackFps = mCaptureFps; // assume video will be played back at full capture speed
         }
     }
 
+    for (uint32_t tryLayers = 1; tryLayers <= kMaxNumVideoTemporalLayers; ++tryLayers) {
+        if (tryLayers > tsLayers) {
+            tsLayers = tryLayers;
+        }
+        // keep going until the base layer fps falls below the typical display refresh rate
+        float baseLayerFps = maxPlaybackFps / (1 << (tryLayers - 1));
+        if (baseLayerFps < kMinTypicalDisplayRefreshingRate / 0.9) {
+            break;
+        }
+    }
+
+    if (tsLayers > 1) {
+        uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
+        uint32_t pLayers = tsLayers - bLayers;
+        format->setString(
+                "ts-schema", AStringPrintf("android.generic.%u+%u", pLayers, bLayers));
+    }
+
     if (mMetaDataStoredInVideoBuffers != kMetadataBufferTypeInvalid) {
         format->setInt32("android._input-metadata-buffer-type", mMetaDataStoredInVideoBuffers);
     }