Revert "Revert "media: Globaly adjust timestamp to make sure all tracks' time are align""

Test: Video Recording.
This reverts commit 59f57541aee1221dd552a202c8a35d799d34979c.

Change-Id: I38e6252743235900d0cff3408d8f7f4690a2ae77
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7e0c164..27c121f 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -112,6 +112,7 @@
     int64_t getDurationUs() const;
     int64_t getEstimatedTrackSizeBytes() const;
     void writeTrackHeader(bool use32BitOffset = true);
+    int64_t getMinCttsOffsetTimeUs();
     void bufferChunk(int64_t timestampUs);
     bool isAvc() const { return mIsAvc; }
     bool isHevc() const { return mIsHevc; }
@@ -307,7 +308,8 @@
     ListTableEntries<uint32_t, 2> *mCttsTableEntries;
 
     int64_t mMinCttsOffsetTimeUs;
-    int64_t mMaxCttsOffsetTimeUs;
+    int64_t mMinCttsOffsetTicks;
+    int64_t mMaxCttsOffsetTicks;
 
     // Save the last 10 frames' timestamp for debug.
     std::list<std::pair<int64_t, int64_t>> mTimestampDebugHelper;
@@ -343,7 +345,7 @@
 
     void dumpTimeStamps();
 
-    int64_t getStartTimeOffsetScaledTimeUs() const;
+    int64_t getStartTimeOffsetTimeUs() const;
     int32_t getStartTimeOffsetScaledTime() const;
 
     static void *ThreadWrapper(void *me);
@@ -1134,9 +1136,22 @@
         writeUdtaBox();
     }
     writeMetaBox();
-    int32_t id = 1;
+    // Loop through all the tracks to get the global time offset if there is
+    // any ctts table appears in a video track.
+    int64_t minCttsOffsetTimeUs = kMaxCttsOffsetTimeUs;
     for (List<Track *>::iterator it = mTracks.begin();
-        it != mTracks.end(); ++it, ++id) {
+        it != mTracks.end(); ++it) {
+        minCttsOffsetTimeUs =
+            std::min(minCttsOffsetTimeUs, (*it)->getMinCttsOffsetTimeUs());
+    }
+    ALOGI("Ajust the moov start time from %lld us -> %lld us",
+            (long long)mStartTimestampUs,
+            (long long)(mStartTimestampUs + minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs));
+    // Adjust the global start time.
+    mStartTimestampUs += minCttsOffsetTimeUs - kMaxCttsOffsetTimeUs;
+
+    for (List<Track *>::iterator it = mTracks.begin();
+        it != mTracks.end(); ++it) {
         (*it)->writeTrackHeader(mUse32BitOffset);
     }
     endBox();  // moov
@@ -1626,6 +1641,9 @@
       mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
       mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
       mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
+      mMinCttsOffsetTimeUs(0),
+      mMinCttsOffsetTicks(0),
+      mMaxCttsOffsetTicks(0),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
@@ -2814,16 +2832,16 @@
 
             // Update ctts time offset range
             if (mStszTableEntries->count() == 0) {
-                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
             } else {
-                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
-                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
-                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
-                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) {
+                    mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
+                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) {
+                    mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
+                    mMinCttsOffsetTimeUs = cttsOffsetTimeUs;
                 }
             }
-
         }
 
         if (mOwner->isRealTimeRecording()) {
@@ -3164,7 +3182,7 @@
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
-    return mTrackDurationUs + getStartTimeOffsetScaledTimeUs();
+    return mTrackDurationUs + getStartTimeOffsetTimeUs();
 }
 
 int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
@@ -3219,6 +3237,16 @@
     mOwner->endBox();  // trak
 }
 
+int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() {
+    // For video tracks with ctts table, this should return the minimum ctts
+    // offset in the table. For non-video tracks or video tracks without ctts
+    // table, this will return kMaxCttsOffsetTimeUs.
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        return kMaxCttsOffsetTimeUs;
+    }
+    return mMinCttsOffsetTimeUs;
+}
+
 void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
     mOwner->beginBox("stbl");
     mOwner->beginBox("stsd");
@@ -3648,7 +3676,7 @@
     mOwner->endBox();  // pasp
 }
 
-int64_t MPEG4Writer::Track::getStartTimeOffsetScaledTimeUs() const {
+int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const {
     int64_t trackStartTimeOffsetUs = 0;
     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
     if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) {
@@ -3659,23 +3687,30 @@
 }
 
 int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
-    return (getStartTimeOffsetScaledTimeUs() *  mTimeScale + 500000LL) / 1000000LL;
+    return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL;
 }
 
 void MPEG4Writer::Track::writeSttsBox() {
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    uint32_t duration;
-    CHECK(mSttsTableEntries->get(duration, 1));
-    duration = htonl(duration);  // Back to host byte order
-    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
+        // For non-vdeio tracks or video tracks without ctts table,
+        // adjust duration of first sample for tracks to account for
+        // first sample not starting at the media start time.
+        // TODO: consider signaling this using some offset
+        // as this is not quite correct.
+        uint32_t duration;
+        CHECK(mSttsTableEntries->get(duration, 1));
+        duration = htonl(duration);  // Back to host byte order
+        mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    }
     mSttsTableEntries->write(mOwner);
     mOwner->endBox();  // stts
 }
 
 void MPEG4Writer::Track::writeCttsBox() {
     // There is no B frame at all
-    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
+    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
         return;
     }
 
@@ -3685,11 +3720,12 @@
     }
 
     ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
-            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
+            mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks);
 
     mOwner->beginBox("ctts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
+    int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs();
+    int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL;
     mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
         // entries are <count, ctts> pairs; adjust only ctts
         uint32_t duration = htonl(value[1]); // back to host byte order
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 1c4827f..dd357cc 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -83,6 +83,10 @@
         kWhatSwitch                          = 'swch',
     };
 
+    enum {
+        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
+    };
+
     int  mFd;
     int mNextFd;
     sp<MetaData> mStartMeta;