Use audio clock as the reference media clock

o Only do this for realtime applications
o Adjust other track clock based on audio clock
o Assume other track uses wall clock as the media clock
o Use some heuristics to reduce the size of stts box by 2/3.

- also
o Remove one unused key from MetaData.h

Change-Id: Ib9432842627b61795b533508158c25258a527332
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2e1e8d8..be96935 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -128,6 +128,12 @@
     // Write the first chunk from the given ChunkInfo.
     void writeFirstChunk(ChunkInfo* info);
 
+    // Adjust other track media clock (presumably wall clock)
+    // based on audio track media clock with the drift time.
+    int64_t mDriftTimeUs;
+    void addDriftTimeUs(int64_t driftTimeUs);
+    int64_t getDriftTimeUs();
+
     void lock();
     void unlock();
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab1fa4f..43354c2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -86,10 +86,10 @@
 
     // Track authoring progress status
     // kKeyTrackTimeStatus is used to track progress in elapsed time
-    // kKeyTrackFrameStatus is used to track progress in authored frames
-    kKeyTrackFrameStatus  = 'tkfm',  // int32_t
     kKeyTrackTimeStatus   = 'tktm',  // int64_t
 
+    kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
+
 };
 
 enum {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 1460f37..9fe3864 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,6 +72,11 @@
     bool mIsAudio;
     bool mIsMPEG4;
     int64_t mTrackDurationUs;
+
+    // For realtime applications, we need to adjust the media clock
+    // for video track based on the audio media clock
+    bool mIsRealTimeRecording;
+    int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMaxWriteTimeUs;
     int32_t mTimeScale;
@@ -940,6 +945,7 @@
 
     mDone = false;
     mIsFirstChunk = true;
+    mDriftTimeUs = 0;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         ChunkInfo info;
@@ -967,6 +973,14 @@
         startTimeUs = 0;
     }
 
+    mIsRealTimeRecording = true;
+    {
+        int32_t isNotRealTime;
+        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
+            mIsRealTimeRecording = (isNotRealTime == 0);
+        }
+    }
+
     initTrackingProgressStatus(params);
 
     sp<MetaData> meta = new MetaData;
@@ -1326,6 +1340,10 @@
     uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs;
+
+    int64_t wallClockTimeUs = 0;
+    int64_t lastWallClockTimeUs = 0;
+
     sp<MetaData> meta_data;
     bool collectStats = collectStatisticalData();
 
@@ -1429,6 +1447,33 @@
         }
 
         timestampUs -= previousPausedDurationUs;
+        if (mIsRealTimeRecording && !mIsAudio) {
+            // The minor adjustment on the timestamp is heuristic/experimental
+            // We are adjusting the timestamp to reduce the fluctuation of the duration
+            // of neighboring samples. This in turn helps reduce the track header size,
+            // especially, the number of entries in the "stts" box.
+            if (mNumSamples > 1) {
+                int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs;
+                int64_t diffUs = (durationUs > lastDurationUs)
+                            ? durationUs - lastDurationUs
+                            : lastDurationUs - durationUs;
+                if (diffUs <= 5000) {  // XXX: Magic number 5ms
+                    timestampUs = lastTimestampUs + lastDurationUs;
+                } else {
+                    timestampUs += mOwner->getDriftTimeUs();
+                }
+            }
+        }
+        CHECK(timestampUs >= 0);
+        if (mNumSamples > 1) {
+            if (timestampUs <= lastTimestampUs) {
+                LOGW("Drop a frame, since it arrives too late!");
+                copy->release();
+                copy = NULL;
+                continue;
+            }
+        }
+
         LOGV("time stamp: %lld and previous paused duration %lld",
                 timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
@@ -1454,6 +1499,14 @@
         }
         lastDurationUs = timestampUs - lastTimestampUs;
         lastTimestampUs = timestampUs;
+        if (mIsRealTimeRecording && mIsAudio) {
+            wallClockTimeUs = systemTime() / 1000;
+            int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs;
+            if (mNumSamples > 2) {
+                mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs);
+            }
+            lastWallClockTimeUs = wallClockTimeUs;
+        }
 
         if (isSync != 0) {
             mStssTableEntries.push_back(mNumSamples);
@@ -1679,6 +1732,18 @@
     }
 }
 
+void MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) {
+    LOGV("addDriftTimeUs: %lld us", driftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    mDriftTimeUs += driftTimeUs;
+}
+
+int64_t MPEG4Writer::getDriftTimeUs() {
+    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    return mDriftTimeUs;
+}
+
 void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
     LOGV("bufferChunk");