media: Move video buffer timestamp adjustment from CodecSource to GraphicBufferSource.
Bug:30919939
Change-Id: I7c1b626eee8512dac691b03309f724b3351e6e2f
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)) {