IOMX: move max pts gap handling to OMX

bug: 31399200

Change-Id: I52177d6826caeedf670ecf3e6d0ff85d0e3bf1df
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 311119b..b902cf5 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -163,7 +163,7 @@
     virtual status_t emptyGraphicBuffer(
             buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) = 0;
+            OMX_TICKS timestamp, int fenceFd) = 0;
 
     virtual status_t getExtensionIndex(
             const char *parameter_name,
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 1901d8c..4bd1ab8 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -475,14 +475,13 @@
     virtual status_t emptyGraphicBuffer(
             buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+            OMX_TICKS timestamp, int fenceFd) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
         data.writeInt32((int32_t)buffer);
         data.write(*graphicBuffer);
         data.writeInt32(flags);
         data.writeInt64(timestamp);
-        data.writeInt64(origTimestamp);
         data.writeInt32(fenceFd >= 0);
         if (fenceFd >= 0) {
             data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
@@ -990,12 +989,10 @@
             data.read(*graphicBuffer);
             OMX_U32 flags = data.readInt32();
             OMX_TICKS timestamp = data.readInt64();
-            OMX_TICKS origTimestamp = data.readInt64();
             bool haveFence = data.readInt32();
             int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
             reply->writeInt32(emptyGraphicBuffer(
-                    buffer, graphicBuffer, flags,
-                    timestamp, origTimestamp, fenceFd));
+                    buffer, graphicBuffer, flags, timestamp, fenceFd));
 
             return NO_ERROR;
         }
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index e9bf739..a8dd309 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -27,7 +27,6 @@
     void configure(IOMXNode omxNode, int dataSpace);
     void setSuspend(boolean suspend);
     void setRepeatPreviousFrameDelayUs(long repeatAfterUs);
-    void setMaxTimestampGapUs(long maxGapUs);
     void setMaxFps(float maxFps);
     void setTimeLapseConfig(long timePerFrameUs, long timePerCaptureUs);
     void setStartTimeUs(long startTimeUs);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index dbb5f0d..ed29859 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1723,8 +1723,12 @@
             mRepeatFrameDelayUs = -1ll;
         }
 
+        // only allow 32-bit value, since we pass it as U32 to OMX.
         if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
             mMaxPtsGapUs = -1ll;
+        } else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < 0) {
+            ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);
+            mMaxPtsGapUs = -1ll;
         }
 
         if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
@@ -6569,9 +6573,14 @@
     }
 
     if (mCodec->mMaxPtsGapUs > 0ll) {
-        err = statusFromBinderStatus(
-                mCodec->mGraphicBufferSource->setMaxTimestampGapUs(
-                        mCodec->mMaxPtsGapUs));
+        OMX_PARAM_U32TYPE maxPtsGapParams;
+        InitOMXParams(&maxPtsGapParams);
+        maxPtsGapParams.nPortIndex = kPortIndexInput;
+        maxPtsGapParams.nU32 = (uint32_t) mCodec->mMaxPtsGapUs;
+
+        err = mCodec->mOMXNode->setParameter(
+                (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
+                &maxPtsGapParams, sizeof(maxPtsGapParams));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index d911508..bda29fa 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -99,7 +99,7 @@
     status_t emptyGraphicBuffer(
             OMX::buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
+            OMX_TICKS timestamp, int fenceFd);
 
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
@@ -162,9 +162,13 @@
     };
     SecureBufferType mSecureBufferType[2];
 
+    // Following are OMX parameters managed by us (instead of the component)
+    // OMX_IndexParamMaxFrameDurationForBitrateControl
     KeyedVector<int64_t, int64_t> mOriginalTimeUs;
-    bool mShouldRestorePts;
     bool mRestorePtsFailed;
+    int64_t mMaxTimestampGapUs;
+    int64_t mPrevOriginalTimeUs;
+    int64_t mPrevModifiedTimeUs;
 
     // For debug support
     char *mName;
@@ -250,6 +254,9 @@
 
     bool handleDataSpaceChanged(omx_message &msg);
 
+    status_t setMaxPtsGapUs(const void *params, size_t size);
+    int64_t getCodecTimestamp(OMX_TICKS timestamp);
+
     OMXNodeInstance(const OMXNodeInstance &);
     OMXNodeInstance &operator=(const OMXNodeInstance &);
 };
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index afb8173..4575d28 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -51,9 +51,7 @@
     mNumBufferAcquired(0),
     mEndOfStream(false),
     mEndOfStreamSent(false),
-    mMaxTimestampGapUs(-1ll),
     mPrevOriginalTimeUs(-1ll),
-    mPrevModifiedTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
     mRepeatAfterUs(-1ll),
     mRepeatLastFrameGeneration(0),
@@ -515,9 +513,7 @@
 }
 
 bool GraphicBufferSource::getTimestamp(
-        const BufferItem &item, int64_t *origTimeUs, int64_t *codecTimeUs) {
-    *origTimeUs = -1ll;
-
+        const BufferItem &item, int64_t *codecTimeUs) {
     int64_t timeUs = item.mTimestamp / 1000;
     timeUs += mInputBufferTimeOffsetUs;
 
@@ -558,29 +554,7 @@
             return false;
         }
 
-        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;
-            }
-            *origTimeUs = originalTimeUs;
-            ALOGV("IN  timestamp: %lld -> %lld",
-                static_cast<long long>(originalTimeUs),
-                static_cast<long long>(timeUs));
-        }
-
         mPrevOriginalTimeUs = originalTimeUs;
-        mPrevModifiedTimeUs = timeUs;
     }
 
     *codecTimeUs = timeUs;
@@ -590,8 +564,8 @@
 status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
     ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
 
-    int64_t origTimeUs, codecTimeUs;
-    if (!getTimestamp(item, &origTimeUs, &codecTimeUs)) {
+    int64_t codecTimeUs;
+    if (!getTimestamp(item, &codecTimeUs)) {
         return UNKNOWN_ERROR;
     }
 
@@ -605,8 +579,7 @@
     int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
 
     status_t err = mOMXNode->emptyGraphicBuffer(
-            bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME,
-            codecTimeUs, origTimeUs, fenceID);
+            bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
 
     if (err != OK) {
         ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
@@ -641,7 +614,7 @@
     status_t err = mOMXNode->emptyGraphicBuffer(
             bufferID, NULL /* buffer */,
             OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
-            0 /* timestamp */, -1ll /* origTimestamp */, -1 /* fenceFd */);
+            0 /* timestamp */, -1 /* fenceFd */);
     if (err != OK) {
         ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
     } else {
@@ -855,9 +828,7 @@
         mSuspended = false;
         mEndOfStream = false;
         mEndOfStreamSent = false;
-        mMaxTimestampGapUs = -1ll;
         mPrevOriginalTimeUs = -1ll;
-        mPrevModifiedTimeUs = -1ll;
         mSkipFramesBeforeNs = -1ll;
         mRepeatAfterUs = -1ll;
         mRepeatLastFrameGeneration = 0;
@@ -928,20 +899,6 @@
     return Status::ok();
 }
 
-Status GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
-    ALOGV("setMaxTimestampGapUs: maxGapUs=%lld", (long long)maxGapUs);
-
-    Mutex::Autolock autoLock(mMutex);
-
-    if (mExecuting || maxGapUs <= 0ll) {
-        return Status::fromServiceSpecificError(INVALID_OPERATION);
-    }
-
-    mMaxTimestampGapUs = maxGapUs;
-
-    return Status::ok();
-}
-
 Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
     Mutex::Autolock autoLock(mMutex);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 045a86a..80fe078 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -120,15 +120,6 @@
     // state and once this behaviour is specified it cannot be reset.
     Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
 
-    // When set, the timestamp fed to the encoder will be modified such that
-    // the gap between two adjacent frames is capped at maxGapUs. Timestamp
-    // will be restored to the original when the encoded frame is returned to
-    // the client.
-    // This is to solve a problem in certain real-time streaming case, where
-    // encoder's rate control logic produces huge frames after a long period
-    // of suspension on input.
-    Status setMaxTimestampGapUs(int64_t maxGapUs) override;
-
     // Sets the input buffer timestamp offset.
     // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
     Status setTimeOffsetUs(int64_t timeOffsetUs) override;
@@ -220,7 +211,7 @@
 
     void setLatestBuffer_l(const BufferItem &item);
     bool repeatLatestBuffer_l();
-    bool getTimestamp(const BufferItem &item, int64_t *timeUs, int64_t *codecTimeUs);
+    bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
 
     // called when the data space of the input buffer changes
     void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
@@ -279,9 +270,7 @@
         kRepeatLastFrameCount = 10,
     };
 
-    int64_t mMaxTimestampGapUs;
     int64_t mPrevOriginalTimeUs;
-    int64_t mPrevModifiedTimeUs;
     int64_t mSkipFramesBeforeNs;
 
     sp<FrameDropper> mFrameDropper;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 2a4bd15..41f3e4a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -340,8 +340,10 @@
       mQueriedProhibitedExtensions(false),
       mQuirks(0),
       mBufferIDCount(0),
-      mShouldRestorePts(false),
-      mRestorePtsFailed(false)
+      mRestorePtsFailed(false),
+      mMaxTimestampGapUs(-1ll),
+      mPrevOriginalTimeUs(-1ll),
+      mPrevModifiedTimeUs(-1ll)
 {
     mName = ADebug::GetDebugName(name);
     DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
@@ -546,18 +548,17 @@
         "OMX.google.android.index.getAndroidNativeBufferUsage",
     };
 
-    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
-            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
-            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
-            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
-            || (index > OMX_IndexCommonStartUnused
-                    && index <= OMX_IndexConfigCommonTransitionEffect)
+    if ((index > OMX_IndexComponentStartUnused && index < OMX_IndexComponentEndUnused)
+            || (index > OMX_IndexPortStartUnused && index < OMX_IndexPortEndUnused)
+            || (index > OMX_IndexAudioStartUnused && index < OMX_IndexAudioEndUnused)
+            || (index > OMX_IndexVideoStartUnused && index < OMX_IndexVideoEndUnused)
+            || (index > OMX_IndexCommonStartUnused && index < OMX_IndexCommonEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtAudioEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtVideoEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtOtherEndUnused)) {
         return false;
     }
 
@@ -598,6 +599,10 @@
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (extIndex == OMX_IndexParamMaxFrameDurationForBitrateControl) {
+        return setMaxPtsGapUs(params, size);
+    }
+
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
         return BAD_INDEX;
@@ -1524,7 +1529,7 @@
 // like emptyBuffer, but the data is already in header->pBuffer
 status_t OMXNodeInstance::emptyGraphicBuffer(
         OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
-        OMX_U32 flags, OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
@@ -1541,13 +1546,7 @@
         return err;
     }
 
-    // If we're required to restore original timestamp, origTimestamp will
-    // be set to non-negative number for all frames. If it's not required
-    // client will set it to -1ll for all frames.
-    if (origTimestamp >= 0ll && !mRestorePtsFailed) {
-        mShouldRestorePts = true;
-        mOriginalTimeUs.add(timestamp, origTimestamp);
-    }
+    int64_t codecTimeUs = getCodecTimestamp(timestamp);
 
     header->nOffset = 0;
     if (graphicBuffer == NULL) {
@@ -1557,13 +1556,55 @@
     } else {
         header->nFilledLen = sizeof(VideoNativeMetadata);
     }
-    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
+    return emptyBuffer_l(header, flags, codecTimeUs, (intptr_t)header->pBuffer, fenceFd);
+}
+
+status_t OMXNodeInstance::setMaxPtsGapUs(const void *params, size_t size) {
+    if (params == NULL || size != sizeof(OMX_PARAM_U32TYPE)) {
+        CLOG_ERROR(setMaxPtsGapUs, BAD_VALUE, "invalid params (%p,%zu)", params, size);
+        return BAD_VALUE;
+    }
+
+    mMaxTimestampGapUs = (int64_t)((OMX_PARAM_U32TYPE*)params)->nU32;
+
+    return OK;
+}
+
+int64_t OMXNodeInstance::getCodecTimestamp(OMX_TICKS timestamp) {
+    int64_t originalTimeUs = timestamp;
+
+    if (mMaxTimestampGapUs > 0ll) {
+        /* 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;
+            timestamp = (timestampGapUs < mMaxTimestampGapUs ?
+                timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+        }
+        ALOGV("IN  timestamp: %lld -> %lld",
+            static_cast<long long>(originalTimeUs),
+            static_cast<long long>(timestamp));
+    }
+
+    mPrevOriginalTimeUs = originalTimeUs;
+    mPrevModifiedTimeUs = timestamp;
+
+    if (mMaxTimestampGapUs > 0ll && !mRestorePtsFailed) {
+        mOriginalTimeUs.add(timestamp, originalTimeUs);
+    }
+
+    return timestamp;
 }
 
 void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
     Mutex::Autolock autoLock(mBufferIDLock);
 
-    if (!mShouldRestorePts || mRestorePtsFailed) {
+    if (mMaxTimestampGapUs <= 0ll || mRestorePtsFailed) {
         return;
     }
 
@@ -1583,12 +1624,6 @@
             ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
             mRestorePtsFailed = true;
         }
-        if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
-            // something terribly wrong must have happened, giving up...
-            ALOGE("mOriginalTimeUs has too many entries (%zu)",
-                    mOriginalTimeUs.size());
-            mRestorePtsFailed = true;
-        }
     }
 }