media: Move video buffer timestamp adjustment from CodecSource to GraphicBufferSource.

Bug:31158120
Bug:30919939
Change-Id: I7c1b626eee8512dac691b03309f724b3351e6e2f
(cherry picked from commit 61fcfd1b0b58dff9284ede8dc49749ca7395856d)
(cherry picked from commit fcf7cf78bc0abc61b86ccb08fb3391f560143ad2)
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 15d691f..1c39b9c 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -192,6 +192,7 @@
         INTERNAL_OPTION_START_TIME, // data is an int64_t
         INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
         INTERNAL_OPTION_COLOR_ASPECTS, // data is ColorAspects
+        INTERNAL_OPTION_TIME_OFFSET, // data is an int64_t
     };
     virtual status_t setInternalOption(
             node_id node,
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 00b2c71..18b1955 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -49,7 +49,7 @@
 
     bool isVideo() const { return mIsVideo; }
     sp<IGraphicBufferProducer> getGraphicBufferProducer();
-    void setInputBufferTimeOffset(int64_t timeOffsetUs);
+    status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
     int64_t getFirstSampleSystemTimeUs();
 
     // MediaSource
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cfdc341..37fd5a5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7473,6 +7473,23 @@
         }
     }
 
+    int64_t timeOffsetUs;
+    if (params->findInt64("time-offset-us", &timeOffsetUs)) {
+        status_t err = mOMX->setInternalOption(
+            mNode,
+            kPortIndexInput,
+            IOMX::INTERNAL_OPTION_TIME_OFFSET,
+            &timeOffsetUs,
+            sizeof(timeOffsetUs));
+
+        if (err != OK) {
+            ALOGE("[%s] Unable to set input buffer time offset (err %d)",
+                mComponentName.c_str(),
+                err);
+            return err;
+        }
+    }
+
     int64_t skipFramesBeforeUs;
     if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) {
         status_t err =
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 311c745..33d624e 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -336,10 +336,10 @@
     return NULL;
 }
 
-void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+status_t MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
     sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
     msg->setInt64("time-offset-us", timeOffsetUs);
-    postSynchronouslyAndReturnError(msg);
+    return postSynchronouslyAndReturnError(msg);
 }
 
 int64_t MediaCodecSource::getFirstSampleSystemTimeUs() {
@@ -874,9 +874,7 @@
                                 break;
                             }
                         }
-                        // Time offset is not applied at
-                        // feedEncoderInputBuffer() in surface input case.
-                        timeUs += mInputBufferTimeOffsetUs;
+                        // Timestamp offset is already adjusted in GraphicBufferSource.
                         // GraphicBufferSource is supposed to discard samples
                         // queued before start, and offset timeUs by start time
                         CHECK_GE(timeUs, 0ll);
@@ -1015,10 +1013,18 @@
     {
         sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
-
+        status_t err = OK;
         CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
 
+        // Propagate the timestamp offset to GraphicBufferSource.
+        if (mIsVideo) {
+            sp<AMessage> params = new AMessage;
+            params->setInt64("time-offset-us", mInputBufferTimeOffsetUs);
+            err = mEncoder->setParameters(params);
+        }
+
         sp<AMessage> response = new AMessage;
+        response->setInt32("err", err);
         response->postReply(replyID);
         break;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 0c8fd67..e025653 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -145,7 +145,8 @@
     mTimePerCaptureUs(-1ll),
     mTimePerFrameUs(-1ll),
     mPrevCaptureUs(-1ll),
-    mPrevFrameUs(-1ll) {
+    mPrevFrameUs(-1ll),
+    mInputBufferTimeOffsetUs(0ll) {
 
     ALOGV("GraphicBufferSource w=%u h=%u c=%u",
             bufferWidth, bufferHeight, bufferCount);
@@ -774,6 +775,7 @@
 
 int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
     int64_t timeUs = item.mTimestamp / 1000;
+    timeUs += mInputBufferTimeOffsetUs;
 
     if (mTimePerCaptureUs > 0ll
             && (mTimePerCaptureUs > 2 * mTimePerFrameUs
@@ -802,35 +804,38 @@
                 static_cast<long long>(mPrevFrameUs));
 
         return mPrevFrameUs;
-    } else if (mMaxTimestampGapUs > 0ll) {
-        //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
-
-        /* Cap timestamp gap between adjacent frames to specified max
-         *
-         * In the scenario of cast mirroring, encoding could be suspended for
-         * prolonged periods. Limiting the pts gap to workaround the problem
-         * where encoder's rate control logic produces huge frames after a
-         * long period of suspension.
-         */
-
+    } else {
         int64_t originalTimeUs = timeUs;
-        if (mPrevOriginalTimeUs >= 0ll) {
-            if (originalTimeUs < mPrevOriginalTimeUs) {
+        if (originalTimeUs <= mPrevOriginalTimeUs) {
                 // Drop the frame if it's going backward in time. Bad timestamp
                 // could disrupt encoder's rate control completely.
-                ALOGW("Dropping frame that's going backward in time");
-                return -1;
-            }
-            int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
-            timeUs = (timestampGapUs < mMaxTimestampGapUs ?
-                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+            ALOGW("Dropping frame that's going backward in time");
+            return -1;
         }
+
+        if (mMaxTimestampGapUs > 0ll) {
+            //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
+
+            /* Cap timestamp gap between adjacent frames to specified max
+             *
+             * In the scenario of cast mirroring, encoding could be suspended for
+             * prolonged periods. Limiting the pts gap to workaround the problem
+             * where encoder's rate control logic produces huge frames after a
+             * long period of suspension.
+             */
+            if (mPrevOriginalTimeUs >= 0ll) {
+                int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+                timeUs = (timestampGapUs < mMaxTimestampGapUs ?
+                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+                mOriginalTimeUs.add(timeUs, originalTimeUs);
+                ALOGV("IN  timestamp: %lld -> %lld",
+                    static_cast<long long>(originalTimeUs),
+                    static_cast<long long>(timeUs));
+            }
+        }
+
         mPrevOriginalTimeUs = originalTimeUs;
         mPrevModifiedTimeUs = timeUs;
-        mOriginalTimeUs.add(timeUs, originalTimeUs);
-        ALOGV("IN  timestamp: %lld -> %lld",
-            static_cast<long long>(originalTimeUs),
-            static_cast<long long>(timeUs));
     }
 
     return timeUs;
@@ -1048,6 +1053,18 @@
     return OK;
 }
 
+status_t GraphicBufferSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+    Mutex::Autolock autoLock(mMutex);
+
+    // timeOffsetUs must be negative for adjustment.
+    if (timeOffsetUs >= 0ll) {
+        return INVALID_OPERATION;
+    }
+
+    mInputBufferTimeOffsetUs = timeOffsetUs;
+    return OK;
+}
+
 status_t GraphicBufferSource::setMaxFps(float maxFps) {
     Mutex::Autolock autoLock(mMutex);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index c8b0e62..30bfddb 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -131,6 +131,10 @@
     // of suspension on input.
     status_t setMaxTimestampGapUs(int64_t maxGapUs);
 
+    // Sets the input buffer timestamp offset.
+    // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
+    status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
+
     // When set, the max frame rate fed to the encoder will be capped at maxFps.
     status_t setMaxFps(float maxFps);
 
@@ -336,6 +340,8 @@
     int64_t mPrevCaptureUs;
     int64_t mPrevFrameUs;
 
+    int64_t mInputBufferTimeOffsetUs;
+
     MetadataBufferType mMetadataBufferType;
     ColorAspects mColorAspects;
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 4f1a952..4908062 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1445,6 +1445,7 @@
         case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
         case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
         case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
         default:                                      return def;
     }
 }
@@ -1473,6 +1474,7 @@
         case IOMX::INTERNAL_OPTION_MAX_FPS:
         case IOMX::INTERNAL_OPTION_START_TIME:
         case IOMX::INTERNAL_OPTION_TIME_LAPSE:
+        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
         case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
         {
             const sp<GraphicBufferSource> &bufferSource =
@@ -1499,6 +1501,13 @@
 
                 CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
                 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
+            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
+                int64_t timeOffsetUs;
+                if (!getInternalOption(data, size, &timeOffsetUs)) {
+                    return INVALID_OPERATION;
+                }
+                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
+                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
             } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
                 int64_t maxGapUs;
                 if (!getInternalOption(data, size, &maxGapUs)) {