summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MPEG4Writer.cpp
diff options
context:
space:
mode:
authorJames Dong <jdong@google.com>2011-06-07 19:45:54 -0700
committerJames Dong <jdong@google.com>2011-06-13 17:06:29 -0700
commit965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebd (patch)
tree96463de989057f23bb9c9670e434282ba2778185 /media/libstagefright/MPEG4Writer.cpp
parentafcedc9e6f17d8213d9bd8f6c36643dcc816d0ef (diff)
downloadframeworks_av-965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebd.zip
frameworks_av-965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebd.tar.gz
frameworks_av-965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebd.tar.bz2
Add B frame support for MPEG4Writer
o requires the support of negative ctts duration values (ctts version 1) Change-Id: Ib14130c9359c3bff3c76f20a7380d468a065dcaf
Diffstat (limited to 'media/libstagefright/MPEG4Writer.cpp')
-rw-r--r--media/libstagefright/MPEG4Writer.cpp127
1 files changed, 118 insertions, 9 deletions
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a953487..b8ae79c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -128,7 +128,6 @@ private:
size_t mNumStssTableEntries;
List<int32_t> mStssTableEntries;
- size_t mNumSttsTableEntries;
struct SttsTableEntry {
SttsTableEntry(uint32_t count, uint32_t duration)
@@ -137,8 +136,20 @@ private:
uint32_t sampleCount;
uint32_t sampleDuration; // time scale based
};
+ size_t mNumSttsTableEntries;
List<SttsTableEntry> mSttsTableEntries;
+ struct CttsTableEntry {
+ CttsTableEntry(uint32_t count, int32_t timescaledDur)
+ : sampleCount(count), sampleDuration(timescaledDur) {}
+
+ uint32_t sampleCount;
+ int32_t sampleDuration; // time scale based
+ };
+ bool mHasNegativeCttsDeltaDuration;
+ size_t mNumCttsTableEntries;
+ List<CttsTableEntry> mCttsTableEntries;
+
// Sequence parameter set or picture parameter set
struct AVCParamSet {
AVCParamSet(uint16_t length, const uint8_t *data)
@@ -219,6 +230,7 @@ private:
// Duration is time scale based
void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
+ void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
void sendTrackSummary(bool hasMultipleTracks);
// Write the boxes
@@ -227,6 +239,7 @@ private:
void writeStszBox();
void writeStssBox();
void writeSttsBox();
+ void writeCttsBox();
void writeD263Box();
void writePaspBox();
void writeAvccBox();
@@ -1147,6 +1160,7 @@ void MPEG4Writer::Track::updateTrackSizeEstimate() {
mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 + // stsc box size
mNumStssTableEntries * 4 + // stss box size
mNumSttsTableEntries * 8 + // stts box size
+ mNumCttsTableEntries * 8 + // ctts box size
stcoBoxSizeBytes + // stco box size
stszBoxSizeBytes; // stsz box size
}
@@ -1173,6 +1187,20 @@ void MPEG4Writer::Track::addOneSttsTableEntry(
++mNumSttsTableEntries;
}
+void MPEG4Writer::Track::addOneCttsTableEntry(
+ size_t sampleCount, int32_t duration) {
+
+ if (mIsAudio) {
+ return;
+ }
+ if (duration < 0 && !mHasNegativeCttsDeltaDuration) {
+ mHasNegativeCttsDeltaDuration = true;
+ }
+ CttsTableEntry cttsEntry(sampleCount, duration);
+ mCttsTableEntries.push_back(cttsEntry);
+ ++mNumCttsTableEntries;
+}
+
void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
++mNumStcoTableEntries;
mChunkOffsets.push_back(offset);
@@ -1483,6 +1511,7 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
mNumStssTableEntries = 0;
mNumStscTableEntries = 0;
mNumSttsTableEntries = 0;
+ mNumCttsTableEntries = 0;
mMdatSizeBytes = 0;
mIsMediaTimeAdjustmentOn = false;
mPrevMediaTimeAdjustTimestampUs = 0;
@@ -1491,6 +1520,7 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
mTotalDriftTimeToAdjustUs = 0;
mPrevTotalAccumDriftTimeUs = 0;
mMaxChunkDurationUs = 0;
+ mHasNegativeCttsDeltaDuration = false;
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
@@ -1932,14 +1962,19 @@ status_t MPEG4Writer::Track::threadEntry() {
int64_t chunkTimestampUs = 0;
int32_t nChunks = 0;
int32_t nZeroLengthFrames = 0;
- int64_t lastTimestampUs = 0; // Previous sample time stamp in ms
- int64_t lastDurationUs = 0; // Between the previous two samples in ms
- int64_t currDurationTicks = 0; // Timescale based ticks
- int64_t lastDurationTicks = 0; // Timescale based ticks
- int32_t sampleCount = 1; // Sample count in the current stts table entry
- uint32_t previousSampleSize = 0; // Size of the previous sample
+ int64_t lastTimestampUs = 0; // Previous sample time stamp
+ int64_t lastCttsTimeUs = 0; // Previous sample time stamp
+ int64_t lastDurationUs = 0; // Between the previous two samples
+ int64_t currDurationTicks = 0; // Timescale based ticks
+ int64_t lastDurationTicks = 0; // Timescale based ticks
+ int32_t sampleCount = 1; // Sample count in the current stts table entry
+ int64_t currCttsDurTicks = 0; // Timescale based ticks
+ int64_t lastCttsDurTicks = 0; // Timescale based ticks
+ int32_t cttsSampleCount = 1; // Sample count in the current ctts table entry
+ uint32_t previousSampleSize = 0; // Size of the previous sample
int64_t previousPausedDurationUs = 0;
- int64_t timestampUs;
+ int64_t timestampUs = 0;
+ int64_t cttsDeltaTimeUs = 0;
if (mIsAudio) {
prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
@@ -2063,7 +2098,6 @@ status_t MPEG4Writer::Track::threadEntry() {
*
*/
CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
- LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
////////////////////////////////////////////////////////////////////////////////
if (mNumSamples == 0) {
@@ -2084,6 +2118,24 @@ status_t MPEG4Writer::Track::threadEntry() {
timestampUs -= previousPausedDurationUs;
CHECK(timestampUs >= 0);
+ if (!mIsAudio) {
+ /*
+ * Composition time: timestampUs
+ * Decoding time: decodingTimeUs
+ * Composition time delta = composition time - decoding time
+ *
+ * We save picture decoding time stamp delta in stts table entries,
+ * and composition time delta duration in ctts table entries.
+ */
+ int64_t decodingTimeUs;
+ CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
+ decodingTimeUs -= previousPausedDurationUs;
+ int64_t timeUs = decodingTimeUs;
+ cttsDeltaTimeUs = timestampUs - decodingTimeUs;
+ timestampUs = decodingTimeUs;
+ LOGV("decoding time: %lld and ctts delta time: %lld",
+ timestampUs, cttsDeltaTimeUs);
+ }
// Media time adjustment for real-time applications
if (mIsRealTimeRecording) {
@@ -2139,6 +2191,18 @@ status_t MPEG4Writer::Track::threadEntry() {
} else {
++sampleCount;
}
+
+ if (!mIsAudio) {
+ currCttsDurTicks =
+ ((cttsDeltaTimeUs * mTimeScale + 500000LL) / 1000000LL -
+ (lastCttsTimeUs * mTimeScale + 500000LL) / 1000000LL);
+ if (currCttsDurTicks != lastCttsDurTicks) {
+ addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
+ cttsSampleCount = 1;
+ } else {
+ ++cttsSampleCount;
+ }
+ }
}
if (mSamplesHaveSameSize) {
if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
@@ -2152,6 +2216,11 @@ status_t MPEG4Writer::Track::threadEntry() {
lastDurationTicks = currDurationTicks;
lastTimestampUs = timestampUs;
+ if (!mIsAudio) {
+ lastCttsDurTicks = currCttsDurTicks;
+ lastCttsTimeUs = cttsDeltaTimeUs;
+ }
+
if (isSync != 0) {
addOneStssTableEntry(mNumSamples);
}
@@ -2221,8 +2290,10 @@ status_t MPEG4Writer::Track::threadEntry() {
if (mNumSamples == 1) {
lastDurationUs = 0; // A single sample's duration
lastDurationTicks = 0;
+ lastCttsDurTicks = 0;
} else {
++sampleCount; // Count for the last sample
+ ++cttsSampleCount;
}
if (mNumSamples <= 2) {
@@ -2234,6 +2305,7 @@ status_t MPEG4Writer::Track::threadEntry() {
addOneSttsTableEntry(sampleCount, lastDurationTicks);
}
+ addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
mTrackDurationUs += lastDurationUs;
mReachedEOS = true;
@@ -2432,6 +2504,7 @@ void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
}
mOwner->endBox(); // stsd
writeSttsBox();
+ writeCttsBox();
if (!mIsAudio) {
writeStssBox();
}
@@ -2782,13 +2855,49 @@ void MPEG4Writer::Track::writeSttsBox() {
int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
mOwner->writeInt32(dur + it->sampleDuration);
+ int64_t totalCount = 1;
while (++it != mSttsTableEntries.end()) {
mOwner->writeInt32(it->sampleCount);
mOwner->writeInt32(it->sampleDuration);
+ totalCount += it->sampleCount;
}
+ CHECK(totalCount == mNumSamples);
mOwner->endBox(); // stts
}
+void MPEG4Writer::Track::writeCttsBox() {
+ if (mIsAudio) { // ctts is not for audio
+ return;
+ }
+
+ // Do not write ctts box when there is no need to have it.
+ if ((mNumCttsTableEntries == 1 &&
+ mCttsTableEntries.begin()->sampleDuration == 0) ||
+ mNumCttsTableEntries == 0) {
+ return;
+ }
+
+ LOGV("ctts box has %d entries", mNumCttsTableEntries);
+
+ mOwner->beginBox("ctts");
+ if (mHasNegativeCttsDeltaDuration) {
+ mOwner->writeInt32(0x00010000); // version=1, flags=0
+ } else {
+ mOwner->writeInt32(0); // version=0, flags=0
+ }
+ mOwner->writeInt32(mNumCttsTableEntries);
+
+ int64_t totalCount = 0;
+ for (List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
+ it != mCttsTableEntries.end(); ++it) {
+ mOwner->writeInt32(it->sampleCount);
+ mOwner->writeInt32(it->sampleDuration);
+ totalCount += it->sampleCount;
+ }
+ CHECK(totalCount == mNumSamples);
+ mOwner->endBox(); // ctts
+}
+
void MPEG4Writer::Track::writeStssBox() {
mOwner->beginBox("stss");
mOwner->writeInt32(0); // version=0, flags=0