am 46e63b34: Merge "Better file size estimate" into gingerbread
Merge commit '46e63b346770efa14451b8e67b7f7636c4e5a76c' into gingerbread-plus-aosp * commit '46e63b346770efa14451b8e67b7f7636c4e5a76c': Better file size estimate
This commit is contained in:
@@ -144,6 +144,7 @@ private:
|
||||
|
||||
inline size_t write(const void *ptr, size_t size, size_t nmemb, FILE* stream);
|
||||
bool exceedsFileSizeLimit();
|
||||
bool use32BitFileOffset() const;
|
||||
bool exceedsFileDurationLimit();
|
||||
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
static const int64_t kMax32BitFileSize = 0x007fffffffLL;
|
||||
static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
|
||||
static const uint8_t kNalUnitTypePicParamSet = 0x08;
|
||||
|
||||
@@ -59,7 +60,7 @@ public:
|
||||
bool isAvc() const { return mIsAvc; }
|
||||
bool isAudio() const { return mIsAudio; }
|
||||
bool isMPEG4() const { return mIsMPEG4; }
|
||||
void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); }
|
||||
void addChunkOffset(off_t offset);
|
||||
status_t dump(int fd, const Vector<String16>& args) const;
|
||||
|
||||
private:
|
||||
@@ -79,7 +80,7 @@ private:
|
||||
bool mIsRealTimeRecording;
|
||||
int64_t mMaxTimeStampUs;
|
||||
int64_t mEstimatedTrackSizeBytes;
|
||||
int64_t mMaxWriteTimeUs;
|
||||
int64_t mMdatSizeBytes;
|
||||
int32_t mTimeScale;
|
||||
|
||||
pthread_t mThread;
|
||||
@@ -92,8 +93,11 @@ private:
|
||||
bool mSamplesHaveSameSize;
|
||||
|
||||
List<MediaBuffer *> mChunkSamples;
|
||||
|
||||
size_t mNumStcoTableEntries;
|
||||
List<off_t> mChunkOffsets;
|
||||
|
||||
size_t mNumStscTableEntries;
|
||||
struct StscTableEntry {
|
||||
|
||||
StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
|
||||
@@ -107,9 +111,11 @@ private:
|
||||
};
|
||||
List<StscTableEntry> mStscTableEntries;
|
||||
|
||||
size_t mNumStssTableEntries;
|
||||
List<int32_t> mStssTableEntries;
|
||||
List<int64_t> mChunkDurations;
|
||||
|
||||
size_t mNumSttsTableEntries;
|
||||
struct SttsTableEntry {
|
||||
|
||||
SttsTableEntry(uint32_t count, uint32_t durationUs)
|
||||
@@ -178,6 +184,11 @@ private:
|
||||
// Simple validation on the codec specific data
|
||||
status_t checkCodecSpecificData() const;
|
||||
|
||||
void updateTrackSizeEstimate();
|
||||
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
|
||||
void addOneStssTableEntry(size_t sampleId);
|
||||
void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
|
||||
|
||||
Track(const Track &);
|
||||
Track &operator=(const Track &);
|
||||
};
|
||||
@@ -211,9 +222,11 @@ MPEG4Writer::MPEG4Writer(int fd)
|
||||
MPEG4Writer::~MPEG4Writer() {
|
||||
stop();
|
||||
|
||||
for (List<Track *>::iterator it = mTracks.begin();
|
||||
it != mTracks.end(); ++it) {
|
||||
while (!mTracks.empty()) {
|
||||
List<Track *>::iterator it = mTracks.begin();
|
||||
delete *it;
|
||||
(*it) = NULL;
|
||||
mTracks.erase(it);
|
||||
}
|
||||
mTracks.clear();
|
||||
}
|
||||
@@ -332,6 +345,21 @@ status_t MPEG4Writer::start(MetaData *param) {
|
||||
mUse32BitOffset = false;
|
||||
}
|
||||
|
||||
if (mUse32BitOffset) {
|
||||
// Implicit 32 bit file size limit
|
||||
if (mMaxFileSizeLimitBytes == 0) {
|
||||
mMaxFileSizeLimitBytes = kMax32BitFileSize;
|
||||
}
|
||||
|
||||
// If file size is set to be larger than the 32 bit file
|
||||
// size limit, treat it as an error.
|
||||
if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
|
||||
LOGE("32-bit file size limit too big: %lld bytes",
|
||||
mMaxFileSizeLimitBytes);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// System property can overwrite the file offset bits parameter
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
if (property_get("media.stagefright.record-64bits", value, NULL)
|
||||
@@ -413,6 +441,10 @@ status_t MPEG4Writer::start(MetaData *param) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool MPEG4Writer::use32BitFileOffset() const {
|
||||
return mUse32BitOffset;
|
||||
}
|
||||
|
||||
status_t MPEG4Writer::pause() {
|
||||
if (mFile == NULL) {
|
||||
return OK;
|
||||
@@ -739,7 +771,8 @@ bool MPEG4Writer::exceedsFileSizeLimit() {
|
||||
it != mTracks.end(); ++it) {
|
||||
nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
|
||||
}
|
||||
return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
|
||||
|
||||
return (nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes);
|
||||
}
|
||||
|
||||
bool MPEG4Writer::exceedsFileDurationLimit() {
|
||||
@@ -819,6 +852,48 @@ MPEG4Writer::Track::Track(
|
||||
setTimeScale();
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::updateTrackSizeEstimate() {
|
||||
|
||||
int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
|
||||
? mNumStcoTableEntries * 4
|
||||
: mNumStcoTableEntries * 8;
|
||||
|
||||
int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
|
||||
|
||||
mEstimatedTrackSizeBytes = mMdatSizeBytes + // media data size
|
||||
mNumStscTableEntries * 12 + // stsc box size
|
||||
mNumStssTableEntries * 4 + // stss box size
|
||||
mNumSttsTableEntries * 8 + // stts box size
|
||||
stcoBoxSizeBytes + // stco box size
|
||||
stszBoxSizeBytes; // stsz box size
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::addOneStscTableEntry(
|
||||
size_t chunkId, size_t sampleId) {
|
||||
|
||||
StscTableEntry stscEntry(chunkId, sampleId, 1);
|
||||
mStscTableEntries.push_back(stscEntry);
|
||||
++mNumStscTableEntries;
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
|
||||
mStssTableEntries.push_back(sampleId);
|
||||
++mNumStssTableEntries;
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::addOneSttsTableEntry(
|
||||
size_t sampleCount, int64_t durationUs) {
|
||||
|
||||
SttsTableEntry sttsEntry(sampleCount, durationUs);
|
||||
mSttsTableEntries.push_back(sttsEntry);
|
||||
++mNumSttsTableEntries;
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::addChunkOffset(off_t offset) {
|
||||
++mNumStcoTableEntries;
|
||||
mChunkOffsets.push_back(offset);
|
||||
}
|
||||
|
||||
void MPEG4Writer::Track::setTimeScale() {
|
||||
LOGV("setTimeScale");
|
||||
// Default time scale
|
||||
@@ -1039,6 +1114,7 @@ status_t MPEG4Writer::startWriterThread() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
status_t MPEG4Writer::Track::start(MetaData *params) {
|
||||
if (!mDone && mPaused) {
|
||||
mPaused = false;
|
||||
@@ -1077,6 +1153,11 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
|
||||
mTrackDurationUs = 0;
|
||||
mReachedEOS = false;
|
||||
mEstimatedTrackSizeBytes = 0;
|
||||
mNumStcoTableEntries = 0;
|
||||
mNumStssTableEntries = 0;
|
||||
mNumStscTableEntries = 0;
|
||||
mNumSttsTableEntries = 0;
|
||||
mMdatSizeBytes = 0;
|
||||
|
||||
pthread_create(&mThread, &attr, ThreadWrapper, this);
|
||||
pthread_attr_destroy(&attr);
|
||||
@@ -1434,7 +1515,6 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
bool collectStats = collectStatisticalData();
|
||||
|
||||
mNumSamples = 0;
|
||||
mMaxWriteTimeUs = 0;
|
||||
status_t err = OK;
|
||||
MediaBuffer *buffer;
|
||||
while (!mDone && (err = mSource->read(&buffer)) == OK) {
|
||||
@@ -1505,7 +1585,9 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
: copy->range_length();
|
||||
|
||||
// Max file size or duration handling
|
||||
mEstimatedTrackSizeBytes += sampleSize;
|
||||
mMdatSizeBytes += sampleSize;
|
||||
updateTrackSizeEstimate();
|
||||
|
||||
if (mOwner->exceedsFileSizeLimit()) {
|
||||
mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
|
||||
break;
|
||||
@@ -1587,8 +1669,7 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
(lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
|
||||
|
||||
if (currDurationTicks != lastDurationTicks) {
|
||||
SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
|
||||
mSttsTableEntries.push_back(sttsEntry);
|
||||
addOneSttsTableEntry(sampleCount, lastDurationUs);
|
||||
sampleCount = 1;
|
||||
} else {
|
||||
++sampleCount;
|
||||
@@ -1611,7 +1692,7 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
}
|
||||
|
||||
if (isSync != 0) {
|
||||
mStssTableEntries.push_back(mNumSamples);
|
||||
addOneStssTableEntry(mNumSamples);
|
||||
}
|
||||
|
||||
if (mTrackingProgressStatus) {
|
||||
@@ -1624,7 +1705,7 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
|
||||
: mOwner->addSample_l(copy);
|
||||
if (mChunkOffsets.empty()) {
|
||||
mChunkOffsets.push_back(offset);
|
||||
addChunkOffset(offset);
|
||||
}
|
||||
copy->release();
|
||||
copy = NULL;
|
||||
@@ -1633,8 +1714,7 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
|
||||
mChunkSamples.push_back(copy);
|
||||
if (interleaveDurationUs == 0) {
|
||||
StscTableEntry stscEntry(++nChunks, 1, 1);
|
||||
mStscTableEntries.push_back(stscEntry);
|
||||
addOneStscTableEntry(++nChunks, 1);
|
||||
bufferChunk(timestampUs);
|
||||
} else {
|
||||
if (chunkTimestampUs == 0) {
|
||||
@@ -1648,9 +1728,7 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
if (nChunks == 1 || // First chunk
|
||||
(--(mStscTableEntries.end()))->samplesPerChunk !=
|
||||
mChunkSamples.size()) {
|
||||
StscTableEntry stscEntry(nChunks,
|
||||
mChunkSamples.size(), 1);
|
||||
mStscTableEntries.push_back(stscEntry);
|
||||
addOneStscTableEntry(nChunks, mChunkSamples.size());
|
||||
}
|
||||
bufferChunk(timestampUs);
|
||||
chunkTimestampUs = timestampUs;
|
||||
@@ -1669,12 +1747,9 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
|
||||
// Last chunk
|
||||
if (mOwner->numTracks() == 1) {
|
||||
StscTableEntry stscEntry(1, mNumSamples, 1);
|
||||
mStscTableEntries.push_back(stscEntry);
|
||||
addOneStscTableEntry(1, mNumSamples);
|
||||
} else if (!mChunkSamples.empty()) {
|
||||
++nChunks;
|
||||
StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
|
||||
mStscTableEntries.push_back(stscEntry);
|
||||
addOneStscTableEntry(++nChunks, mChunkSamples.size());
|
||||
bufferChunk(timestampUs);
|
||||
}
|
||||
|
||||
@@ -1686,12 +1761,11 @@ status_t MPEG4Writer::Track::threadEntry() {
|
||||
} else {
|
||||
++sampleCount; // Count for the last sample
|
||||
}
|
||||
SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
|
||||
mSttsTableEntries.push_back(sttsEntry);
|
||||
addOneSttsTableEntry(sampleCount, lastDurationUs);
|
||||
mTrackDurationUs += lastDurationUs;
|
||||
mReachedEOS = true;
|
||||
LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s",
|
||||
count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video");
|
||||
LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
|
||||
count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
|
||||
|
||||
logStatisticalData(mIsAudio);
|
||||
if (err == ERROR_END_OF_STREAM) {
|
||||
@@ -1855,14 +1929,9 @@ int64_t MPEG4Writer::getDriftTimeUs() {
|
||||
void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
|
||||
LOGV("bufferChunk");
|
||||
|
||||
int64_t startTimeUs = systemTime() / 1000;
|
||||
Chunk chunk(this, timestampUs, mChunkSamples);
|
||||
mOwner->bufferChunk(chunk);
|
||||
mChunkSamples.clear();
|
||||
int64_t endTimeUs = systemTime() / 1000;
|
||||
if (mMaxWriteTimeUs < endTimeUs - startTimeUs) {
|
||||
mMaxWriteTimeUs = endTimeUs - startTimeUs;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t MPEG4Writer::Track::getDurationUs() const {
|
||||
@@ -2215,7 +2284,7 @@ void MPEG4Writer::Track::writeTrackHeader(
|
||||
|
||||
mOwner->beginBox("stts");
|
||||
mOwner->writeInt32(0); // version=0, flags=0
|
||||
mOwner->writeInt32(mSttsTableEntries.size());
|
||||
mOwner->writeInt32(mNumSttsTableEntries);
|
||||
int64_t prevTimestampUs = 0;
|
||||
for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
|
||||
it != mSttsTableEntries.end(); ++it) {
|
||||
@@ -2235,7 +2304,7 @@ void MPEG4Writer::Track::writeTrackHeader(
|
||||
if (!mIsAudio) {
|
||||
mOwner->beginBox("stss");
|
||||
mOwner->writeInt32(0); // version=0, flags=0
|
||||
mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames
|
||||
mOwner->writeInt32(mNumStssTableEntries); // number of sync frames
|
||||
for (List<int32_t>::iterator it = mStssTableEntries.begin();
|
||||
it != mStssTableEntries.end(); ++it) {
|
||||
mOwner->writeInt32(*it);
|
||||
@@ -2262,7 +2331,7 @@ void MPEG4Writer::Track::writeTrackHeader(
|
||||
|
||||
mOwner->beginBox("stsc");
|
||||
mOwner->writeInt32(0); // version=0, flags=0
|
||||
mOwner->writeInt32(mStscTableEntries.size());
|
||||
mOwner->writeInt32(mNumStscTableEntries);
|
||||
for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
|
||||
it != mStscTableEntries.end(); ++it) {
|
||||
mOwner->writeInt32(it->firstChunk);
|
||||
@@ -2272,7 +2341,7 @@ void MPEG4Writer::Track::writeTrackHeader(
|
||||
mOwner->endBox(); // stsc
|
||||
mOwner->beginBox(use32BitOffset? "stco": "co64");
|
||||
mOwner->writeInt32(0); // version=0, flags=0
|
||||
mOwner->writeInt32(mChunkOffsets.size());
|
||||
mOwner->writeInt32(mNumStcoTableEntries);
|
||||
for (List<off_t>::iterator it = mChunkOffsets.begin();
|
||||
it != mChunkOffsets.end(); ++it) {
|
||||
if (use32BitOffset) {
|
||||
|
||||
Reference in New Issue
Block a user