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;
- }
}
}