diff options
author | James Dong <jdong@google.com> | 2010-06-23 00:18:40 -0700 |
---|---|---|
committer | James Dong <jdong@google.com> | 2010-06-23 14:09:18 -0700 |
commit | 1acfe8649f8169caf2ff098c2dc2de880d9a3760 (patch) | |
tree | bed86c364188e3cedfb45228c13605784b4f934f /media/libstagefright/MPEG4Writer.cpp | |
parent | dadd0d1e7d5fbb88fd3420438c590a0bb4c18af5 (diff) | |
download | frameworks_av-1acfe8649f8169caf2ff098c2dc2de880d9a3760.zip frameworks_av-1acfe8649f8169caf2ff098c2dc2de880d9a3760.tar.gz frameworks_av-1acfe8649f8169caf2ff098c2dc2de880d9a3760.tar.bz2 |
Fixed some meta data issues in the recorded mp4 file
- Mainly correcting the location of stbl box which should be a child of minf box.
This resolved the issue where the mis-muxed encoded file could not be played by QT/VLC.
- Enabled the the recorded tracks by setting the flags to 0x07 by default
- Allows for encoding either 32-bit or 64-bit offsets. By default encoding
32-bit offsets to reduce the metadata overhead
- Fixed a edts box issue where an empty elst box was used at the end
Change-Id: I570621a26714a81dc9400271aa5d3a07b483172f
Diffstat (limited to 'media/libstagefright/MPEG4Writer.cpp')
-rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 99 |
1 files changed, 68 insertions, 31 deletions
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index cd20ec7..4242d36 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -48,7 +48,7 @@ public: int64_t getDurationUs() const; int64_t getEstimatedTrackSizeBytes() const; - void writeTrackHeader(int32_t trackID); + void writeTrackHeader(int32_t trackID, bool use32BitOffset = true); private: MPEG4Writer *mOwner; @@ -123,6 +123,7 @@ private: MPEG4Writer::MPEG4Writer(const char *filename) : mFile(fopen(filename, "wb")), + mUse32BitOffset(true), mPaused(false), mStarted(false), mOffset(0), @@ -134,6 +135,7 @@ MPEG4Writer::MPEG4Writer(const char *filename) MPEG4Writer::MPEG4Writer(int fd) : mFile(fdopen(fd, "wb")), + mUse32BitOffset(true), mPaused(false), mStarted(false), mOffset(0), @@ -218,7 +220,11 @@ status_t MPEG4Writer::start() { mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; mOffset = mMdatOffset; fseeko(mFile, mMdatOffset, SEEK_SET); - write("\x00\x00\x00\x01mdat????????", 16); + if (mUse32BitOffset) { + write("????mdat", 8); + } else { + write("\x00\x00\x00\x01mdat????????", 16); + } status_t err = startTracks(); if (err != OK) { @@ -257,10 +263,16 @@ void MPEG4Writer::stop() { // Fix up the size of the 'mdat' chunk. - fseeko(mFile, mMdatOffset + 8, SEEK_SET); - int64_t size = mOffset - mMdatOffset; - size = hton64(size); - fwrite(&size, 1, 8, mFile); + if (mUse32BitOffset) { + fseeko(mFile, mMdatOffset, SEEK_SET); + int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset)); + fwrite(&size, 1, 4, mFile); + } else { + fseeko(mFile, mMdatOffset + 8, SEEK_SET); + int64_t size = mOffset - mMdatOffset; + size = hton64(size); + fwrite(&size, 1, 8, mFile); + } fseeko(mFile, mOffset, SEEK_SET); time_t now = time(NULL); @@ -269,6 +281,8 @@ void MPEG4Writer::stop() { mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); mMoovBoxBufferOffset = 0; CHECK(mMoovBoxBuffer != NULL); + int32_t timeScale = 1000; + int32_t duration = max_duration / timeScale; beginBox("moov"); @@ -276,9 +290,9 @@ void MPEG4Writer::stop() { writeInt32(0); // version=0, flags=0 writeInt32(now); // creation time writeInt32(now); // modification time - writeInt32(1000); // timescale - writeInt32(max_duration / 1000); - writeInt32(0x10000); // rate + writeInt32(timeScale); // timescale + writeInt32(duration); + writeInt32(0x10000); // rate: 1.0 writeInt16(0x100); // volume writeInt16(0); // reserved writeInt32(0); // reserved @@ -304,7 +318,7 @@ void MPEG4Writer::stop() { int32_t id = 1; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it, ++id) { - (*it)->writeTrackHeader(id); + (*it)->writeTrackHeader(id, mUse32BitOffset); } endBox(); // moov @@ -415,7 +429,8 @@ size_t MPEG4Writer::write( const size_t bytes = size * nmemb; if (mWriteMoovBoxToMemory) { - if (8 + mMoovBoxBufferOffset + bytes > mEstimatedMoovBoxSize) { + off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes; + if (moovBoxSize > mEstimatedMoovBoxSize) { for (List<off_t>::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { (*it) += mOffset; @@ -1162,24 +1177,29 @@ int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const { return mEstimatedTrackSizeBytes; } -void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { +void MPEG4Writer::Track::writeTrackHeader( + int32_t trackID, bool use32BitOffset) { const char *mime; bool success = mMeta->findCString(kKeyMIMEType, &mime); CHECK(success); bool is_audio = !strncasecmp(mime, "audio/", 6); + int32_t timeScale = 1000; + int32_t duration = getDurationUs() / timeScale; time_t now = time(NULL); mOwner->beginBox("trak"); mOwner->beginBox("tkhd"); - mOwner->writeInt32(0); // version=0, flags=0 + // Flags = 7 to indicate that the track is enabled, and + // part of the presentation + mOwner->writeInt32(0x07); // version=0, flags=7 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time mOwner->writeInt32(trackID); mOwner->writeInt32(0); // reserved - mOwner->writeInt32(getDurationUs() / 1000); + mOwner->writeInt32(duration); mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved mOwner->writeInt16(0); // layer @@ -1214,15 +1234,17 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); if (mStartTimestampUs != moovStartTimeUs) { mOwner->beginBox("edts"); - mOwner->writeInt32(0); // version=0, flags=0 mOwner->beginBox("elst"); - mOwner->writeInt32(0); // version=0, flags=0 - mOwner->writeInt32(1); // a single entry + mOwner->writeInt32(0); // version=0, flags=0: 32-bit time + mOwner->writeInt32(2); // never ends with an empty list int64_t durationMs = (mStartTimestampUs - moovStartTimeUs) / 1000; mOwner->writeInt32(durationMs); // edit duration mOwner->writeInt32(-1); // empty edit box to signal starting time offset - mOwner->writeInt32(1); // x1 rate + mOwner->writeInt32(1 << 16); // x1 rate + mOwner->writeInt32(duration); + mOwner->writeInt32(0); + mOwner->writeInt32(1 << 16); mOwner->endBox(); mOwner->endBox(); } @@ -1233,9 +1255,14 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time - mOwner->writeInt32(1000); // timescale - mOwner->writeInt32(getDurationUs() / 1000); - mOwner->writeInt16(0); // language code XXX + mOwner->writeInt32(timeScale); // timescale + mOwner->writeInt32(duration); // duration + // Language follows the three letter standard ISO-639-2/T + // 'e', 'n', 'g' for "English", for instance. + // Each character is packed as the difference between its ASCII value and 0x60. + // For "English", these are 00101, 01110, 00111. + // XXX: Where is the padding bit located: 0x15C7? + mOwner->writeInt16(0); // language code mOwner->writeInt16(0); // predefined mOwner->endBox(); @@ -1246,7 +1273,8 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved - mOwner->writeCString(is_audio ? "SoundHandler": ""); // name + // Removing "r" for the name string just makes the string 4 byte aligned + mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle"); // name mOwner->endBox(); mOwner->beginBox("minf"); @@ -1258,7 +1286,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->endBox(); } else { mOwner->beginBox("vmhd"); - mOwner->writeInt32(0x00000001); // version=0, flags=1 + mOwner->writeInt32(0x01); // version=0, flags=1 mOwner->writeInt16(0); // graphics mode mOwner->writeInt16(0); // opcolor mOwner->writeInt16(0); @@ -1269,15 +1297,15 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->beginBox("dinf"); mOwner->beginBox("dref"); mOwner->writeInt32(0); // version=0, flags=0 - mOwner->writeInt32(1); + mOwner->writeInt32(1); // entry count (either url or urn) + // The table index here refers to the sample description index + // in the sample table entries. mOwner->beginBox("url "); - mOwner->writeInt32(1); // version=0, flags=1 + mOwner->writeInt32(1); // version=0, flags=1 (self-contained) mOwner->endBox(); // url mOwner->endBox(); // dref mOwner->endBox(); // dinf - mOwner->endBox(); // minf - mOwner->beginBox("stbl"); mOwner->beginBox("stsd"); @@ -1361,7 +1389,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->writeInt32(0); // reserved mOwner->writeInt16(0); // reserved - mOwner->writeInt16(0); // data ref index + mOwner->writeInt16(1); // data ref index mOwner->writeInt16(0); // predefined mOwner->writeInt16(0); // reserved mOwner->writeInt32(0); // predefined @@ -1435,6 +1463,11 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->endBox(); // avcC } + mOwner->beginBox("pasp"); + // This is useful if the pixel is not square + mOwner->writeInt32(1 << 16); // hspacing + mOwner->writeInt32(1 << 16); // vspacing + mOwner->endBox(); // pasp mOwner->endBox(); // mp4v, s263 or avc1 } mOwner->endBox(); // stsd @@ -1487,17 +1520,21 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { mOwner->writeInt32(it->sampleDescriptionId); } mOwner->endBox(); // stsc - - mOwner->beginBox("co64"); + mOwner->beginBox(use32BitOffset? "stco": "co64"); mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(mChunkOffsets.size()); for (List<off_t>::iterator it = mChunkOffsets.begin(); it != mChunkOffsets.end(); ++it) { - mOwner->writeInt64((*it)); + if (use32BitOffset) { + mOwner->writeInt32(static_cast<int32_t>(*it)); + } else { + mOwner->writeInt64((*it)); + } } mOwner->endBox(); // co64 mOwner->endBox(); // stbl + mOwner->endBox(); // minf mOwner->endBox(); // mdia mOwner->endBox(); // trak } |