Reduce memory usage by the MP4 file writer
- Don't store timestamp for each output sample
- Don't store timestamp for statistical data collection if the collection of statistical data is not requested

TODO:
1. Reduce CPU load by elimnating the list cost associated with List.size() call.

Change-Id: I590bc17176596a65952c982574b82ee3b15b7d1c
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 78970b3..16b1094 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -66,11 +66,7 @@
 
     pthread_t mThread;
 
-    struct SampleInfo {
-        size_t size;
-        int64_t timestampUs;
-    };
-    List<SampleInfo>    mSampleInfos;
+    List<size_t>        mSampleSizes;
     bool                mSamplesHaveSameSize;
 
     List<MediaBuffer *> mChunkSamples;
@@ -916,6 +912,15 @@
     return OK;
 }
 
+static bool collectStatisticalData() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.record-stats", value, NULL)
+        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        return true;
+    }
+    return false;
+}
+
 void MPEG4Writer::Track::threadEntry() {
     sp<MetaData> meta = mSource->getFormat();
     const char *mime;
@@ -935,6 +940,7 @@
     uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     sp<MetaData> meta_data;
+    bool collectStats = collectStatisticalData();
 
     status_t err = OK;
     MediaBuffer *buffer;
@@ -1081,8 +1087,8 @@
 
         if (is_avc) StripStartcode(copy);
 
-        SampleInfo info;
-        info.size = is_avc
+        size_t sampleSize;
+        sampleSize = is_avc
 #if USE_NALLEN_FOUR
                 ? copy->range_length() + 4
 #else
@@ -1091,7 +1097,7 @@
                 : copy->range_length();
 
         // Max file size or duration handling
-        mEstimatedTrackSizeBytes += info.size;
+        mEstimatedTrackSizeBytes += sampleSize;
         if (mOwner->exceedsFileSizeLimit()) {
             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
             break;
@@ -1109,7 +1115,7 @@
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
 
 ////////////////////////////////////////////////////////////////////////////////
-        if (mSampleInfos.empty()) {
+        if (mSampleSizes.empty()) {
             mStartTimestampUs = timestampUs;
             mOwner->setStartTimestampUs(mStartTimestampUs);
         }
@@ -1126,10 +1132,9 @@
             mMaxTimeStampUs = timestampUs;
         }
 
-        info.timestampUs = timestampUs;
-        mSampleInfos.push_back(info);
-        if (mSampleInfos.size() > 2) {
-            if (lastDurationUs != info.timestampUs - lastTimestampUs) {
+        mSampleSizes.push_back(sampleSize);
+        if (mSampleSizes.size() > 2) {
+            if (lastDurationUs != timestampUs - lastTimestampUs) {
                 SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
                 mSttsTableEntries.push_back(sttsEntry);
                 sampleCount = 1;
@@ -1138,16 +1143,16 @@
             }
         }
         if (mSamplesHaveSameSize) {
-            if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) {
+            if (mSampleSizes.size() >= 2 && previousSampleSize != sampleSize) {
                 mSamplesHaveSameSize = false;
             }
-            previousSampleSize = info.size;
+            previousSampleSize = sampleSize;
         }
-        lastDurationUs = info.timestampUs - lastTimestampUs;
-        lastTimestampUs = info.timestampUs;
+        lastDurationUs = timestampUs - lastTimestampUs;
+        lastTimestampUs = timestampUs;
 
         if (isSync != 0) {
-            mStssTableEntries.push_back(mSampleInfos.size());
+            mStssTableEntries.push_back(mSampleSizes.size());
         }
 
         if (mTrackingProgressStatus) {
@@ -1178,7 +1183,9 @@
             } else {
                 if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
                     ++nChunks;
-                    mChunkDurations.push_back(timestampUs - chunkTimestampUs);
+                    if (collectStats) {
+                        mChunkDurations.push_back(timestampUs - chunkTimestampUs);
+                    }
                     if (nChunks == 1 ||  // First chunk
                         (--(mStscTableEntries.end()))->samplesPerChunk !=
                          mChunkSamples.size()) {
@@ -1194,14 +1201,14 @@
 
     }
 
-    if (mSampleInfos.empty()) {
+    if (mSampleSizes.empty()) {
         err = UNKNOWN_ERROR;
     }
     mOwner->trackProgressStatus(this, -1, err);
 
     // Last chunk
     if (mOwner->numTracks() == 1) {
-        StscTableEntry stscEntry(1, mSampleInfos.size(), 1);
+        StscTableEntry stscEntry(1, mSampleSizes.size(), 1);
         mStscTableEntries.push_back(stscEntry);
     } else if (!mChunkSamples.empty()) {
         ++nChunks;
@@ -1213,7 +1220,7 @@
     // We don't really know how long the last frame lasts, since
     // there is no frame time after it, just repeat the previous
     // frame's duration.
-    if (mSampleInfos.size() == 1) {
+    if (mSampleSizes.size() == 1) {
         lastDurationUs = 0;  // A single sample's duration
     } else {
         ++sampleCount;  // Count for the last sample
@@ -1222,7 +1229,7 @@
     mSttsTableEntries.push_back(sttsEntry);
     mReachedEOS = true;
     LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
-            count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");
+            count, nZeroLengthFrames, mSampleSizes.size(), is_audio? "audio": "video");
 
     logStatisticalData(is_audio);
 }
@@ -1284,8 +1291,8 @@
 
 void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
         int32_t *min, int32_t *avg, int32_t *max) {
-    CHECK(!mSampleInfos.empty());
-    int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mSampleInfos.size();
+    CHECK(!mSampleSizes.empty());
+    int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mSampleSizes.size();
     int32_t minSampleDurationMs = 0x7FFFFFFF;
     int32_t maxSampleDurationMs = 0;
     for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
@@ -1327,22 +1334,17 @@
 }
 
 void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
-    if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) {
+    if (mMaxTimeStampUs <= 0 || mSampleSizes.empty()) {
         LOGI("nothing is recorded");
         return;
     }
 
-    bool collectStats = false;
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.record-stats", value, NULL)
-        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-        collectStats = true;
-    }
+    bool collectStats = collectStatisticalData();
 
     if (collectStats) {
         LOGI("%s track - duration %lld us, total %d frames",
                 isAudio? "audio": "video", mMaxTimeStampUs,
-                mSampleInfos.size());
+                mSampleSizes.size());
         int32_t min, avg, max;
         findMinAvgMaxSampleDurationMs(&min, &avg, &max);
         LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max);
@@ -1355,9 +1357,9 @@
         }
 
         int64_t totalBytes = 0;
-        for (List<SampleInfo>::iterator it = mSampleInfos.begin();
-            it != mSampleInfos.end(); ++it) {
-            totalBytes += it->size;
+        for (List<size_t>::iterator it = mSampleSizes.begin();
+            it != mSampleSizes.end(); ++it) {
+            totalBytes += (*it);
         }
         float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs;
         LOGI("avg bit rate (bps): %.2f", bitRate);
@@ -1731,16 +1733,16 @@
           mOwner->beginBox("stsz");
             mOwner->writeInt32(0);  // version=0, flags=0
             if (mSamplesHaveSameSize) {
-                List<SampleInfo>::iterator it = mSampleInfos.begin();
-                mOwner->writeInt32(it->size);  // default sample size
+                List<size_t>::iterator it = mSampleSizes.begin();
+                mOwner->writeInt32(*it);  // default sample size
             } else {
                 mOwner->writeInt32(0);
             }
-            mOwner->writeInt32(mSampleInfos.size());
+            mOwner->writeInt32(mSampleSizes.size());
             if (!mSamplesHaveSameSize) {
-                for (List<SampleInfo>::iterator it = mSampleInfos.begin();
-                     it != mSampleInfos.end(); ++it) {
-                    mOwner->writeInt32((*it).size);
+                for (List<size_t>::iterator it = mSampleSizes.begin();
+                     it != mSampleSizes.end(); ++it) {
+                    mOwner->writeInt32(*it);
                 }
             }
           mOwner->endBox();  // stsz