diff options
| author | 2010-06-20 08:20:54 -0700 | |
|---|---|---|
| committer | 2010-06-25 10:24:35 -0700 | |
| commit | 6feaa46496bae85adbe10e84611592612f898081 (patch) | |
| tree | 47300b5ee67684405f2c5bea5d5642f50455d072 | |
| parent | 5a905ceb063bd31170d3d869efcd051cbd8e4e13 (diff) | |
Enable passing parameters to the MediaWriter at runtime (at start() call).
- estimate the moov box size for mp4 file writer based on the file
size/duration limit and target bit rate.
- can switch to use 64 bit file offset at runtime
rebased
Change-Id: Ibbe1f57e91ab2605820d5d96e8048d11e5559c53
| -rw-r--r-- | include/media/stagefright/AMRWriter.h | 3 | ||||
| -rw-r--r-- | include/media/stagefright/MPEG4Writer.h | 3 | ||||
| -rw-r--r-- | include/media/stagefright/MediaWriter.h | 3 | ||||
| -rw-r--r-- | include/media/stagefright/MetaData.h | 3 | ||||
| -rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 26 | ||||
| -rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 2 | ||||
| -rw-r--r-- | media/libstagefright/AMRWriter.cpp | 2 | ||||
| -rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 76 |
8 files changed, 103 insertions, 15 deletions
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h index b0eaba407a24..813dd43f0a34 100644 --- a/include/media/stagefright/AMRWriter.h +++ b/include/media/stagefright/AMRWriter.h @@ -26,6 +26,7 @@ namespace android { struct MediaSource; +struct MetaData; struct AMRWriter : public MediaWriter { AMRWriter(const char *filename); @@ -35,7 +36,7 @@ struct AMRWriter : public MediaWriter { virtual status_t addSource(const sp<MediaSource> &source); virtual bool reachedEOS(); - virtual status_t start(); + virtual status_t start(MetaData *params = NULL); virtual void stop(); virtual void pause(); diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 39d0ea19b083..7a2de1ecbb1d 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -36,7 +36,7 @@ public: MPEG4Writer(int fd); virtual status_t addSource(const sp<MediaSource> &source); - virtual status_t start(); + virtual status_t start(MetaData *param = NULL); virtual bool reachedEOS(); virtual void stop(); virtual void pause(); @@ -83,6 +83,7 @@ private: int64_t getStartTimestampUs(); // Not const status_t startTracks(); size_t numTracks(); + int64_t estimateMoovBoxSize(int32_t bitRate); void lock(); void unlock(); diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h index 8528203363e4..46aaf7cad84d 100644 --- a/include/media/stagefright/MediaWriter.h +++ b/include/media/stagefright/MediaWriter.h @@ -24,13 +24,14 @@ namespace android { struct MediaSource; +struct MetaData; struct MediaWriter : public RefBase { MediaWriter() {} virtual status_t addSource(const sp<MediaSource> &source) = 0; virtual bool reachedEOS() = 0; - virtual status_t start() = 0; + virtual status_t start(MetaData *params = NULL) = 0; virtual void stop() = 0; virtual void pause() = 0; virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; } diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 6a2060271731..d28d1ca7db1c 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -36,13 +36,14 @@ enum { kKeyStride = 'strd', // int32_t kKeySliceHeight = 'slht', // int32_t kKeyChannelCount = '#chn', // int32_t - kKeySampleRate = 'srte', // int32_t + kKeySampleRate = 'srte', // int32_t (also video frame rate) kKeyBitRate = 'brte', // int32_t (bps) kKeyESDS = 'esds', // raw data kKeyAVCC = 'avcc', // raw data kKeyVorbisInfo = 'vinf', // raw data kKeyVorbisBooks = 'vboo', // raw data kKeyWantsNALFragments = 'NALf', + kKey64BitFileOffset = 'fobt', // int32_t (bool) kKeyIsSyncFrame = 'sync', // int32_t (bool) kKeyIsCodecConfig = 'conf', // int32_t (bool) kKeyTime = 'time', // int64_t (usecs) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index ba04d1b3b856..68344917a679 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -316,6 +316,13 @@ status_t StagefrightRecorder::setParamIFramesInterval(int32_t interval) { return OK; } +status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) { + LOGV("setParam64BitFileOffset: %s", + use64Bit? "use 64 bit file offset": "use 32 bit file offset"); + mUse64BitFileOffset = use64Bit; + return OK; +} + status_t StagefrightRecorder::setParameter( const String8 &key, const String8 &value) { LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); @@ -361,6 +368,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &interval)) { return setParamIFramesInterval(interval); } + } else if (key == "param-use-64bit-offset") { + int32_t use64BitOffset; + if (safe_strtoi32(value.string(), &use64BitOffset)) { + return setParam64BitFileOffset(use64BitOffset != 0); + } } else { LOGE("setParameter: failed to find key %s", key.string()); } @@ -633,6 +645,7 @@ void StagefrightRecorder::clipVideoFrameHeight() { status_t StagefrightRecorder::startMPEG4Recording() { mWriter = new MPEG4Writer(dup(mOutputFd)); + int32_t totalBitRate = 0; // Add audio source first if it exists if (mAudioSource != AUDIO_SOURCE_LIST_END) { @@ -651,7 +664,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { if (audioEncoder == NULL) { return UNKNOWN_ERROR; } - + totalBitRate += mAudioBitRate; mWriter->addSource(audioEncoder); } if (mVideoSource == VIDEO_SOURCE_DEFAULT @@ -704,7 +717,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { sp<MetaData> enc_meta = new MetaData; enc_meta->setInt32(kKeyBitRate, mVideoBitRate); - enc_meta->setInt32(kKeySampleRate, mFrameRate); // XXX: kKeySampleRate? + enc_meta->setInt32(kKeySampleRate, mFrameRate); switch (mVideoEncoder) { case VIDEO_ENCODER_H263: @@ -747,12 +760,13 @@ status_t StagefrightRecorder::startMPEG4Recording() { true /* createEncoder */, cameraSource); CHECK(mOutputFd >= 0); + totalBitRate += mVideoBitRate; mWriter->addSource(encoder); } { // MPEGWriter specific handling - MPEG4Writer *writer = ((MPEG4Writer *) mWriter.get()); // mWriter is an MPEGWriter + MPEG4Writer *writer = ((MPEG4Writer *) mWriter.get()); writer->setInterleaveDuration(mInterleaveDurationUs); } @@ -763,7 +777,10 @@ status_t StagefrightRecorder::startMPEG4Recording() { mWriter->setMaxFileSize(mMaxFileSizeBytes); } mWriter->setListener(mListener); - mWriter->start(); + sp<MetaData> meta = new MetaData; + meta->setInt32(kKeyBitRate, totalBitRate); + meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + mWriter->start(meta.get()); return OK; } @@ -824,6 +841,7 @@ status_t StagefrightRecorder::reset() { mInterleaveDurationUs = 0; mIFramesInterval = 1; mAudioSourceNode = 0; + mUse64BitFileOffset = false; mEncoderProfiles = MediaProfiles::getInstance(); mOutputFd = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 6eedf0cbd6f8..2943e97f9f02 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -72,6 +72,7 @@ private: output_format mOutputFormat; audio_encoder mAudioEncoder; video_encoder mVideoEncoder; + bool mUse64BitFileOffset; int32_t mVideoWidth, mVideoHeight; int32_t mFrameRate; int32_t mVideoBitRate; @@ -100,6 +101,7 @@ private: status_t setParamAudioSamplingRate(int32_t sampleRate); status_t setParamInterleaveDuration(int32_t durationUs); status_t setParamIFramesInterval(int32_t interval); + status_t setParam64BitFileOffset(bool use64BitFileOffset); status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration); void clipVideoBitRate(); void clipVideoFrameRate(); diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 8951f5b5d8e8..6d1dd1607067 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -97,7 +97,7 @@ status_t AMRWriter::addSource(const sp<MediaSource> &source) { return OK; } -status_t AMRWriter::start() { +status_t AMRWriter::start(MetaData *params) { if (mInitCheck != OK) { return mInitCheck; } diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index f16b225870c8..65d109b7cf06 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -180,11 +180,72 @@ status_t MPEG4Writer::startTracks() { return OK; } -status_t MPEG4Writer::start() { +int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { + // This implementation is highly experimental/heurisitic. + // + // Statistical analysis shows that metadata usually accounts + // for a small portion of the total file size, usually < 0.6%. + // Currently, lets set to 0.4% for now. + + // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB, + // where 1MB is the common file size limit for MMS application. + // The default MAX _MOOV_BOX_SIZE value is based on about 4 + // minute video recording with a bit rate about 3 Mbps, because + // statistics also show that most of the video captured are going + // to be less than 3 minutes. + + // If the estimation is wrong, we will pay the price of wasting + // some reserved space. This should not happen so often statistically. + static const int32_t factor = mUse32BitOffset? 1: 2; + static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024; // 4 KB + static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); + int64_t size = MIN_MOOV_BOX_SIZE; + + if (mMaxFileSizeLimitBytes != 0) { + size = mMaxFileSizeLimitBytes * 4 / 1000; + } else if (mMaxFileDurationLimitUs != 0) { + if (bitRate <= 0) { + // We could not estimate the file size since bitRate is not set. + size = MIN_MOOV_BOX_SIZE; + } else { + size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000); + } + } + if (size < MIN_MOOV_BOX_SIZE) { + size = MIN_MOOV_BOX_SIZE; + } + + // Any long duration recording will be probably end up with + // non-streamable mp4 file. + if (size > MAX_MOOV_BOX_SIZE) { + size = MAX_MOOV_BOX_SIZE; + } + + LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" + " moov size %lld bytes", + mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); + return factor * size; +} + +status_t MPEG4Writer::start(MetaData *param) { if (mFile == NULL) { return UNKNOWN_ERROR; } + int32_t use64BitOffset; + if (param && + param->findInt32(kKey64BitFileOffset, &use64BitOffset) && + use64BitOffset) { + mUse32BitOffset = false; + } + + // System property can overwrite the file offset bits parameter + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.record-64bits", value, NULL) + && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { + mUse32BitOffset = false; + } + mStartTimestampUs = -1; if (mStarted) { if (mPaused) { @@ -208,9 +269,11 @@ status_t MPEG4Writer::start() { mFreeBoxOffset = mOffset; if (mEstimatedMoovBoxSize == 0) { - // XXX: Estimate the moov box size - // based on max file size or duration limit - mEstimatedMoovBoxSize = 0x0F00; + int32_t bitRate = -1; + if (param) { + param->findInt32(kKeyBitRate, &bitRate); + } + mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate); } CHECK(mEstimatedMoovBoxSize >= 8); fseeko(mFile, mFreeBoxOffset, SEEK_SET); @@ -332,8 +395,7 @@ void MPEG4Writer::stop() { write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile); // Free box - mFreeBoxOffset = mStreamableFile? mOffset: mFreeBoxOffset; - fseeko(mFile, mFreeBoxOffset, SEEK_SET); + fseeko(mFile, mOffset, SEEK_SET); writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset); write("free", 4); @@ -341,6 +403,8 @@ void MPEG4Writer::stop() { free(mMoovBoxBuffer); mMoovBoxBuffer = NULL; mMoovBoxBufferOffset = 0; + } else { + LOGI("The mp4 file will not be streamable."); } CHECK(mBoxes.empty()); |