diff options
author | James Dong <jdong@google.com> | 2010-07-15 11:54:10 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-07-15 11:54:10 -0700 |
commit | 892681e56ee6da6e8d4fb9ec41e75e814ae9e099 (patch) | |
tree | ba88dfd4766ae1063d814797c7d691427651a1e3 /media | |
parent | dcd077179c853e54498e9127526a8f2984c0dda0 (diff) | |
parent | b068b47c6d0214256116a0c661740bddf7acc18c (diff) | |
download | frameworks_base-892681e56ee6da6e8d4fb9ec41e75e814ae9e099.zip frameworks_base-892681e56ee6da6e8d4fb9ec41e75e814ae9e099.tar.gz frameworks_base-892681e56ee6da6e8d4fb9ec41e75e814ae9e099.tar.bz2 |
am b068b47c: am d6a85a21: Merge "Support user-supplied timescales for authoring" into gingerbread
Merge commit 'b068b47c6d0214256116a0c661740bddf7acc18c'
* commit 'b068b47c6d0214256116a0c661740bddf7acc18c':
Support user-supplied timescales for authoring
Diffstat (limited to 'media')
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 84 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 10 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 102 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 6 |
4 files changed, 149 insertions, 53 deletions
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 3beae7f..24b0e7b 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -381,12 +381,12 @@ status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) { return OK; } -// If interval < 0, only the first frame is I frame, and rest are all P frames -// If interval == 0, all frames are encoded as I frames. No P frames -// If interval > 0, it is the time spacing (seconds) between 2 neighboring I frames -status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) { - LOGV("setParamVideoIFramesInterval: %d seconds", interval); - mIFramesInterval = interval; +// If seconds < 0, only the first frame is I frame, and rest are all P frames +// If seconds == 0, all frames are encoded as I frames. No P frames +// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames +status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) { + LOGV("setParamVideoIFramesInterval: %d seconds", seconds); + mIFramesIntervalSec = seconds; return OK; } @@ -444,6 +444,44 @@ status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) { return OK; } +status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) { + LOGV("setParamMovieTimeScale: %d", timeScale); + + // The range is set to be the same as the audio's time scale range + // since audio's time scale has a wider range. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mMovieTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) { + LOGV("setParamVideoTimeScale: %d", timeScale); + + // 60000 is chosen to make sure that each video frame from a 60-fps + // video has 1000 ticks. + if (timeScale < 600 || timeScale > 60000) { + LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale); + return BAD_VALUE; + } + mVideoTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) { + LOGV("setParamAudioTimeScale: %d", timeScale); + + // 96000 Hz is the highest sampling rate support in AAC. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mAudioTimeScale = timeScale; + return OK; +} + status_t StagefrightRecorder::setParameter( const String8 &key, const String8 &value) { LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); @@ -462,6 +500,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &durationUs)) { return setParamInterleaveDuration(durationUs); } + } else if (key == "param-movie-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamMovieTimeScale(timeScale); + } } else if (key == "param-use-64bit-offset") { int32_t use64BitOffset; if (safe_strtoi32(value.string(), &use64BitOffset)) { @@ -492,15 +535,20 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &audio_bitrate)) { return setParamAudioEncodingBitRate(audio_bitrate); } + } else if (key == "audio-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamAudioTimeScale(timeScale); + } } else if (key == "video-param-encoding-bitrate") { int32_t video_bitrate; if (safe_strtoi32(value.string(), &video_bitrate)) { return setParamVideoEncodingBitRate(video_bitrate); } } else if (key == "video-param-i-frames-interval") { - int32_t interval; - if (safe_strtoi32(value.string(), &interval)) { - return setParamVideoIFramesInterval(interval); + int32_t seconds; + if (safe_strtoi32(value.string(), &seconds)) { + return setParamVideoIFramesInterval(seconds); } } else if (key == "video-param-encoder-profile") { int32_t profile; @@ -517,6 +565,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &cameraId)) { return setParamVideoCameraId(cameraId); } + } else if (key == "video-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamVideoTimeScale(timeScale); + } } else { LOGE("setParameter: failed to find key %s", key.string()); } @@ -637,6 +690,7 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { encMeta->setInt32(kKeyChannelCount, mAudioChannels); encMeta->setInt32(kKeySampleRate, mSampleRate); encMeta->setInt32(kKeyBitRate, mAudioBitRate); + encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); OMXClient client; CHECK_EQ(client.connect(), OK); @@ -880,10 +934,11 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) { enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval); + enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); enc_meta->setInt32(kKeyStride, stride); enc_meta->setInt32(kKeySliceHeight, sliceHeight); enc_meta->setInt32(kKeyColorFormat, colorFormat); + enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); if (mVideoEncoderProfile != -1) { enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); } @@ -921,6 +976,7 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { if (audioEncoder == NULL) { return UNKNOWN_ERROR; } + writer->addSource(audioEncoder); return OK; } @@ -957,6 +1013,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { meta->setInt32(kKeyFileType, mOutputFormat); meta->setInt32(kKeyBitRate, totalBitRate); meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + meta->setInt32(kKeyTimeScale, mMovieTimeScale); if (mTrackEveryNumberOfFrames > 0) { meta->setInt32(kKeyTrackFrameStatus, mTrackEveryNumberOfFrames); } @@ -1027,9 +1084,12 @@ status_t StagefrightRecorder::reset() { mAudioChannels = 1; mAudioBitRate = 12200; mInterleaveDurationUs = 0; - mIFramesInterval = 1; + mIFramesIntervalSec = 1; mAudioSourceNode = 0; mUse64BitFileOffset = false; + mMovieTimeScale = 1000; + mAudioTimeScale = 1000; + mVideoTimeScale = 1000; mCameraId = 0; mVideoEncoderProfile = -1; mVideoEncoderLevel = -1; @@ -1112,7 +1172,7 @@ status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const { result.append(buffer); snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel); result.append(buffer); - snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesInterval); + snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec); result.append(buffer); snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight); result.append(buffer); diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 58f0031..f51d7f8 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -81,10 +81,13 @@ private: int32_t mAudioChannels; int32_t mSampleRate; int32_t mInterleaveDurationUs; - int32_t mIFramesInterval; + int32_t mIFramesIntervalSec; int32_t mCameraId; int32_t mVideoEncoderProfile; int32_t mVideoEncoderLevel; + int32_t mMovieTimeScale; + int32_t mVideoTimeScale; + int32_t mAudioTimeScale; int64_t mMaxFileSizeBytes; int64_t mMaxFileDurationUs; int32_t mTrackEveryNumberOfFrames; @@ -111,17 +114,20 @@ private: status_t setParamAudioEncodingBitRate(int32_t bitRate); status_t setParamAudioNumberOfChannels(int32_t channles); status_t setParamAudioSamplingRate(int32_t sampleRate); + status_t setParamAudioTimeScale(int32_t timeScale); status_t setParamVideoEncodingBitRate(int32_t bitRate); - status_t setParamVideoIFramesInterval(int32_t interval); + status_t setParamVideoIFramesInterval(int32_t seconds); status_t setParamVideoEncoderProfile(int32_t profile); status_t setParamVideoEncoderLevel(int32_t level); status_t setParamVideoCameraId(int32_t cameraId); + status_t setParamVideoTimeScale(int32_t timeScale); status_t setParamTrackTimeStatus(int64_t timeDurationUs); status_t setParamTrackFrameStatus(int32_t nFrames); status_t setParamInterleaveDuration(int32_t durationUs); status_t setParam64BitFileOffset(bool use64BitFileOffset); status_t setParamMaxFileDurationUs(int64_t timeUs); status_t setParamMaxFileSizeBytes(int64_t bytes); + status_t setParamMovieTimeScale(int32_t timeScale); void clipVideoBitRate(); void clipVideoFrameRate(); void clipVideoFrameWidth(); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 6a4a131..b7388bb 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -41,6 +41,7 @@ namespace android { class MPEG4Writer::Track { public: Track(MPEG4Writer *owner, const sp<MediaSource> &source); + ~Track(); status_t start(MetaData *params); @@ -61,12 +62,13 @@ private: volatile bool mResumed; int64_t mMaxTimeStampUs; int64_t mEstimatedTrackSizeBytes; + int32_t mTimeScale; pthread_t mThread; struct SampleInfo { size_t size; - int64_t timestamp; + int64_t timestampUs; }; List<SampleInfo> mSampleInfos; bool mSamplesHaveSameSize; @@ -92,11 +94,11 @@ private: struct SttsTableEntry { - SttsTableEntry(uint32_t count, uint32_t duration) - : sampleCount(count), sampleDuration(duration) {} + SttsTableEntry(uint32_t count, uint32_t durationUs) + : sampleCount(count), sampleDurationUs(durationUs) {} uint32_t sampleCount; - uint32_t sampleDuration; + uint32_t sampleDurationUs; }; List<SttsTableEntry> mSttsTableEntries; @@ -270,6 +272,13 @@ status_t MPEG4Writer::start(MetaData *param) { return OK; } + if (!param || + !param->findInt32(kKeyTimeScale, &mTimeScale)) { + mTimeScale = 1000; + } + CHECK(mTimeScale > 0); + LOGV("movie time scale: %d", mTimeScale); + mStreamableFile = true; mWriteMoovBoxToMemory = false; mMoovBoxBuffer = NULL; @@ -336,14 +345,14 @@ void MPEG4Writer::stop() { return; } - int64_t max_duration = 0; + int64_t maxDurationUs = 0; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { (*it)->stop(); - int64_t duration = (*it)->getDurationUs(); - if (duration > max_duration) { - max_duration = duration; + int64_t durationUs = (*it)->getDurationUs(); + if (durationUs > maxDurationUs) { + maxDurationUs = durationUs; } } @@ -367,8 +376,7 @@ void MPEG4Writer::stop() { mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); mMoovBoxBufferOffset = 0; CHECK(mMoovBoxBuffer != NULL); - int32_t timeScale = 1000; - int32_t duration = max_duration / timeScale; + int32_t duration = (maxDurationUs * mTimeScale) / 1E6; beginBox("moov"); @@ -376,7 +384,7 @@ void MPEG4Writer::stop() { writeInt32(0); // version=0, flags=0 writeInt32(now); // creation time writeInt32(now); // modification time - writeInt32(timeScale); // timescale + writeInt32(mTimeScale); // mvhd timescale writeInt32(duration); writeInt32(0x10000); // rate: 1.0 writeInt16(0x100); // volume @@ -655,7 +663,6 @@ void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { } int64_t MPEG4Writer::getStartTimestampUs() { - LOGI("getStartTimestampUs: %lld", mStartTimestampUs); Mutex::Autolock autoLock(mLock); return mStartTimestampUs; } @@ -683,6 +690,11 @@ MPEG4Writer::Track::Track( mGotAllCodecSpecificData(false), mReachedEOS(false) { getCodecSpecificDataFromInputFormatIfPossible(); + + if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) { + mTimeScale = 1000; + } + CHECK(mTimeScale > 0); } void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { @@ -927,9 +939,9 @@ void MPEG4Writer::Track::threadEntry() { int64_t chunkTimestampUs = 0; int32_t nChunks = 0; int32_t nZeroLengthFrames = 0; - int64_t lastTimestamp = 0; // Timestamp of the previous sample - int64_t lastDuration = 0; // Time spacing between the previous two samples - int32_t sampleCount = 1; // Sample count in the current stts table entry + int64_t lastTimestampUs = 0; // Previous sample time stamp in ms + int64_t lastDurationUs = 0; // Between the previous two samples in ms + int32_t sampleCount = 1; // Sample count in the current stts table entry uint32_t previousSampleSize = 0; // Size of the previous sample int64_t previousPausedDurationUs = 0; sp<MetaData> meta_data; @@ -1113,7 +1125,7 @@ void MPEG4Writer::Track::threadEntry() { } if (mResumed) { - previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration); + previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - lastDurationUs); mResumed = false; } @@ -1124,12 +1136,11 @@ void MPEG4Writer::Track::threadEntry() { mMaxTimeStampUs = timestampUs; } - // Our timestamp is in ms. - info.timestamp = (timestampUs + 500) / 1000; + info.timestampUs = timestampUs; mSampleInfos.push_back(info); if (mSampleInfos.size() > 2) { - if (lastDuration != info.timestamp - lastTimestamp) { - SttsTableEntry sttsEntry(sampleCount, lastDuration); + if (lastDurationUs != info.timestampUs - lastTimestampUs) { + SttsTableEntry sttsEntry(sampleCount, lastDurationUs); mSttsTableEntries.push_back(sttsEntry); sampleCount = 1; } else { @@ -1142,8 +1153,8 @@ void MPEG4Writer::Track::threadEntry() { } previousSampleSize = info.size; } - lastDuration = info.timestamp - lastTimestamp; - lastTimestamp = info.timestamp; + lastDurationUs = info.timestampUs - lastTimestampUs; + lastTimestampUs = info.timestampUs; if (isSync != 0) { mStssTableEntries.push_back(mSampleInfos.size()); @@ -1213,11 +1224,11 @@ void MPEG4Writer::Track::threadEntry() { // there is no frame time after it, just repeat the previous // frame's duration. if (mSampleInfos.size() == 1) { - lastDuration = 0; // A single sample's duration + lastDurationUs = 0; // A single sample's duration } else { ++sampleCount; // Count for the last sample } - SttsTableEntry sttsEntry(sampleCount, lastDuration); + SttsTableEntry sttsEntry(sampleCount, lastDurationUs); mSttsTableEntries.push_back(sttsEntry); mReachedEOS = true; LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s", @@ -1249,12 +1260,13 @@ void MPEG4Writer::Track::trackProgressStatus(int32_t nFrames, int64_t timeUs) { void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( int32_t *min, int32_t *avg, int32_t *max) { CHECK(!mSampleInfos.empty()); - int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000/ mSampleInfos.size(); + int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mSampleInfos.size(); int32_t minSampleDurationMs = 0x7FFFFFFF; int32_t maxSampleDurationMs = 0; for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); it != mSttsTableEntries.end(); ++it) { - int32_t sampleDurationMs = static_cast<int32_t>(it->sampleDuration); + int32_t sampleDurationMs = + (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; if (sampleDurationMs > maxSampleDurationMs) { maxSampleDurationMs = sampleDurationMs; } else if (sampleDurationMs < minSampleDurationMs) { @@ -1370,10 +1382,13 @@ void MPEG4Writer::Track::writeTrackHeader( CHECK(success); bool is_audio = !strncasecmp(mime, "audio/", 6); - int32_t timeScale = 1000; - int32_t duration = getDurationUs() / timeScale; + LOGV("%s track time scale: %d", + is_audio? "Audio": "Video", mTimeScale); + time_t now = time(NULL); + int32_t mvhdTimeScale = mOwner->getTimeScale(); + int64_t trakDurationUs = getDurationUs(); mOwner->beginBox("trak"); @@ -1385,7 +1400,9 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt32(now); // modification time mOwner->writeInt32(trackID); mOwner->writeInt32(0); // reserved - mOwner->writeInt32(duration); + int32_t tkhdDuration = + (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(tkhdDuration); // in mvhd timescale mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved mOwner->writeInt16(0); // layer @@ -1423,12 +1440,17 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->beginBox("elst"); 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 << 16); // x1 rate - mOwner->writeInt32(duration); + + // First elst entry: specify the starting time offset + int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; + int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(seg); // in mvhd timecale + mOwner->writeInt32(-1); // starting time offset + mOwner->writeInt32(1 << 16); // rate = 1.0 + + // Second elst entry: specify the track duration + seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(seg); // in mvhd timescale mOwner->writeInt32(0); mOwner->writeInt32(1 << 16); mOwner->endBox(); @@ -1441,8 +1463,9 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time - mOwner->writeInt32(timeScale); // timescale - mOwner->writeInt32(duration); // duration + mOwner->writeInt32(mTimeScale); // media timescale + int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; + mOwner->writeInt32(mdhdDuration); // use media timescale // 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. @@ -1664,7 +1687,8 @@ void MPEG4Writer::Track::writeTrackHeader( for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); it != mSttsTableEntries.end(); ++it) { mOwner->writeInt32(it->sampleCount); - mOwner->writeInt32(it->sampleDuration); + int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6; + mOwner->writeInt32(dur); } mOwner->endBox(); // stts @@ -1717,7 +1741,7 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt64((*it)); } } - mOwner->endBox(); // co64 + mOwner->endBox(); // stco or co64 mOwner->endBox(); // stbl mOwner->endBox(); // minf diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 077e123..157897b 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -3212,6 +3212,12 @@ void OMXCodec::dumpPortStatus(OMX_U32 portIndex) { void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { mOutputFormat = new MetaData; mOutputFormat->setCString(kKeyDecoderComponent, mComponentName); + if (mIsEncoder) { + int32_t timeScale; + if (inputFormat->findInt32(kKeyTimeScale, &timeScale)) { + mOutputFormat->setInt32(kKeyTimeScale, timeScale); + } + } OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); |