am 9afc1b3e: Merge "Fixed some meta data issues in the recorded mp4 file" into gingerbread

Merge commit '9afc1b3ed3eb8dbfb440600495d92def88934f54' into gingerbread-plus-aosp

* commit '9afc1b3ed3eb8dbfb440600495d92def88934f54':
  Fixed some meta data issues in the recorded mp4 file
This commit is contained in:
James Dong
2010-06-23 15:16:25 -07:00
committed by Android Git Automerger
2 changed files with 69 additions and 31 deletions

View File

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

View File

@@ -48,7 +48,7 @@ public:
int64_t getDurationUs() const; int64_t getDurationUs() const;
int64_t getEstimatedTrackSizeBytes() const; int64_t getEstimatedTrackSizeBytes() const;
void writeTrackHeader(int32_t trackID); void writeTrackHeader(int32_t trackID, bool use32BitOffset = true);
private: private:
MPEG4Writer *mOwner; MPEG4Writer *mOwner;
@@ -123,6 +123,7 @@ private:
MPEG4Writer::MPEG4Writer(const char *filename) MPEG4Writer::MPEG4Writer(const char *filename)
: mFile(fopen(filename, "wb")), : mFile(fopen(filename, "wb")),
mUse32BitOffset(true),
mPaused(false), mPaused(false),
mStarted(false), mStarted(false),
mOffset(0), mOffset(0),
@@ -134,6 +135,7 @@ MPEG4Writer::MPEG4Writer(const char *filename)
MPEG4Writer::MPEG4Writer(int fd) MPEG4Writer::MPEG4Writer(int fd)
: mFile(fdopen(fd, "wb")), : mFile(fdopen(fd, "wb")),
mUse32BitOffset(true),
mPaused(false), mPaused(false),
mStarted(false), mStarted(false),
mOffset(0), mOffset(0),
@@ -218,7 +220,11 @@ status_t MPEG4Writer::start() {
mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize; mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
mOffset = mMdatOffset; mOffset = mMdatOffset;
fseeko(mFile, mMdatOffset, SEEK_SET); 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(); status_t err = startTracks();
if (err != OK) { if (err != OK) {
@@ -257,10 +263,16 @@ void MPEG4Writer::stop() {
// Fix up the size of the 'mdat' chunk. // Fix up the size of the 'mdat' chunk.
fseeko(mFile, mMdatOffset + 8, SEEK_SET); if (mUse32BitOffset) {
int64_t size = mOffset - mMdatOffset; fseeko(mFile, mMdatOffset, SEEK_SET);
size = hton64(size); int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
fwrite(&size, 1, 8, mFile); 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); fseeko(mFile, mOffset, SEEK_SET);
time_t now = time(NULL); time_t now = time(NULL);
@@ -269,6 +281,8 @@ void MPEG4Writer::stop() {
mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
mMoovBoxBufferOffset = 0; mMoovBoxBufferOffset = 0;
CHECK(mMoovBoxBuffer != NULL); CHECK(mMoovBoxBuffer != NULL);
int32_t timeScale = 1000;
int32_t duration = max_duration / timeScale;
beginBox("moov"); beginBox("moov");
@@ -276,9 +290,9 @@ void MPEG4Writer::stop() {
writeInt32(0); // version=0, flags=0 writeInt32(0); // version=0, flags=0
writeInt32(now); // creation time writeInt32(now); // creation time
writeInt32(now); // modification time writeInt32(now); // modification time
writeInt32(1000); // timescale writeInt32(timeScale); // timescale
writeInt32(max_duration / 1000); writeInt32(duration);
writeInt32(0x10000); // rate writeInt32(0x10000); // rate: 1.0
writeInt16(0x100); // volume writeInt16(0x100); // volume
writeInt16(0); // reserved writeInt16(0); // reserved
writeInt32(0); // reserved writeInt32(0); // reserved
@@ -304,7 +318,7 @@ void MPEG4Writer::stop() {
int32_t id = 1; int32_t id = 1;
for (List<Track *>::iterator it = mTracks.begin(); for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it, ++id) { it != mTracks.end(); ++it, ++id) {
(*it)->writeTrackHeader(id); (*it)->writeTrackHeader(id, mUse32BitOffset);
} }
endBox(); // moov endBox(); // moov
@@ -415,7 +429,8 @@ size_t MPEG4Writer::write(
const size_t bytes = size * nmemb; const size_t bytes = size * nmemb;
if (mWriteMoovBoxToMemory) { if (mWriteMoovBoxToMemory) {
if (8 + mMoovBoxBufferOffset + bytes > mEstimatedMoovBoxSize) { off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
if (moovBoxSize > mEstimatedMoovBoxSize) {
for (List<off_t>::iterator it = mBoxes.begin(); for (List<off_t>::iterator it = mBoxes.begin();
it != mBoxes.end(); ++it) { it != mBoxes.end(); ++it) {
(*it) += mOffset; (*it) += mOffset;
@@ -1162,24 +1177,29 @@ int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
return mEstimatedTrackSizeBytes; return mEstimatedTrackSizeBytes;
} }
void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) { void MPEG4Writer::Track::writeTrackHeader(
int32_t trackID, bool use32BitOffset) {
const char *mime; const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime); bool success = mMeta->findCString(kKeyMIMEType, &mime);
CHECK(success); CHECK(success);
bool is_audio = !strncasecmp(mime, "audio/", 6); bool is_audio = !strncasecmp(mime, "audio/", 6);
int32_t timeScale = 1000;
int32_t duration = getDurationUs() / timeScale;
time_t now = time(NULL); time_t now = time(NULL);
mOwner->beginBox("trak"); mOwner->beginBox("trak");
mOwner->beginBox("tkhd"); 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); // creation time
mOwner->writeInt32(now); // modification time mOwner->writeInt32(now); // modification time
mOwner->writeInt32(trackID); mOwner->writeInt32(trackID);
mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved
mOwner->writeInt32(getDurationUs() / 1000); mOwner->writeInt32(duration);
mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved
mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved
mOwner->writeInt16(0); // layer mOwner->writeInt16(0); // layer
@@ -1214,15 +1234,17 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
int64_t moovStartTimeUs = mOwner->getStartTimestampUs(); int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
if (mStartTimestampUs != moovStartTimeUs) { if (mStartTimestampUs != moovStartTimeUs) {
mOwner->beginBox("edts"); mOwner->beginBox("edts");
mOwner->writeInt32(0); // version=0, flags=0
mOwner->beginBox("elst"); mOwner->beginBox("elst");
mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(0); // version=0, flags=0: 32-bit time
mOwner->writeInt32(1); // a single entry mOwner->writeInt32(2); // never ends with an empty list
int64_t durationMs = int64_t durationMs =
(mStartTimestampUs - moovStartTimeUs) / 1000; (mStartTimestampUs - moovStartTimeUs) / 1000;
mOwner->writeInt32(durationMs); // edit duration mOwner->writeInt32(durationMs); // edit duration
mOwner->writeInt32(-1); // empty edit box to signal starting time offset 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();
mOwner->endBox(); mOwner->endBox();
} }
@@ -1233,9 +1255,14 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // creation time
mOwner->writeInt32(now); // modification time mOwner->writeInt32(now); // modification time
mOwner->writeInt32(1000); // timescale mOwner->writeInt32(timeScale); // timescale
mOwner->writeInt32(getDurationUs() / 1000); mOwner->writeInt32(duration); // duration
mOwner->writeInt16(0); // language code XXX // 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->writeInt16(0); // predefined
mOwner->endBox(); 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->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->endBox();
mOwner->beginBox("minf"); mOwner->beginBox("minf");
@@ -1258,7 +1286,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->endBox(); mOwner->endBox();
} else { } else {
mOwner->beginBox("vmhd"); 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); // graphics mode
mOwner->writeInt16(0); // opcolor mOwner->writeInt16(0); // opcolor
mOwner->writeInt16(0); mOwner->writeInt16(0);
@@ -1269,15 +1297,15 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->beginBox("dinf"); mOwner->beginBox("dinf");
mOwner->beginBox("dref"); mOwner->beginBox("dref");
mOwner->writeInt32(0); // version=0, flags=0 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->beginBox("url ");
mOwner->writeInt32(1); // version=0, flags=1 mOwner->writeInt32(1); // version=0, flags=1 (self-contained)
mOwner->endBox(); // url mOwner->endBox(); // url
mOwner->endBox(); // dref mOwner->endBox(); // dref
mOwner->endBox(); // dinf mOwner->endBox(); // dinf
mOwner->endBox(); // minf
mOwner->beginBox("stbl"); mOwner->beginBox("stbl");
mOwner->beginBox("stsd"); mOwner->beginBox("stsd");
@@ -1361,7 +1389,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved
mOwner->writeInt16(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); // predefined
mOwner->writeInt16(0); // reserved mOwner->writeInt16(0); // reserved
mOwner->writeInt32(0); // predefined mOwner->writeInt32(0); // predefined
@@ -1435,6 +1463,11 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->endBox(); // avcC 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(); // mp4v, s263 or avc1
} }
mOwner->endBox(); // stsd mOwner->endBox(); // stsd
@@ -1487,17 +1520,21 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->writeInt32(it->sampleDescriptionId); mOwner->writeInt32(it->sampleDescriptionId);
} }
mOwner->endBox(); // stsc mOwner->endBox(); // stsc
mOwner->beginBox(use32BitOffset? "stco": "co64");
mOwner->beginBox("co64");
mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(mChunkOffsets.size()); mOwner->writeInt32(mChunkOffsets.size());
for (List<off_t>::iterator it = mChunkOffsets.begin(); for (List<off_t>::iterator it = mChunkOffsets.begin();
it != mChunkOffsets.end(); ++it) { 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(); // co64
mOwner->endBox(); // stbl mOwner->endBox(); // stbl
mOwner->endBox(); // minf
mOwner->endBox(); // mdia mOwner->endBox(); // mdia
mOwner->endBox(); // trak mOwner->endBox(); // trak
} }