Merge "Fixed some meta data issues in the recorded mp4 file" into gingerbread

This commit is contained in:
James Dong
2010-06-23 15:13:55 -07:00
committed by Android (Google) Code Review
2 changed files with 69 additions and 31 deletions

View File

@@ -60,6 +60,7 @@ private:
class Track;
FILE *mFile;
bool mUse32BitOffset;
bool mPaused;
bool mStarted;
off_t mOffset;

View File

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