diff options
| -rw-r--r-- | include/media/mediarecorder.h | 4 | ||||
| -rw-r--r-- | include/media/stagefright/MPEG4Writer.h | 2 | ||||
| -rw-r--r-- | include/media/stagefright/MetaData.h | 16 | ||||
| -rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 81 | ||||
| -rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 10 | ||||
| -rw-r--r-- | media/libstagefright/AMRWriter.cpp | 2 | ||||
| -rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 90 |
7 files changed, 174 insertions, 31 deletions
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h index eead1663753e..4f4ec43ef7b0 100644 --- a/include/media/mediarecorder.h +++ b/include/media/mediarecorder.h @@ -136,7 +136,9 @@ enum media_recorder_info_type { MEDIA_RECORDER_INFO_UNKNOWN = 1, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801, - MEDIA_RECORDER_INFO_STOP_PREMATURELY = 802 + MEDIA_RECORDER_INFO_COMPLETION_STATUS = 802, + MEDIA_RECORDER_INFO_PROGRESS_FRAME_STATUS = 803, + MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS = 804, }; // ---------------------------------------------------------------------------- diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 7a2de1ecbb1d..962b38beddb8 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -81,7 +81,7 @@ private: void setStartTimestampUs(int64_t timeUs); int64_t getStartTimestampUs(); // Not const - status_t startTracks(); + status_t startTracks(MetaData *params); size_t numTracks(); int64_t estimateMoovBoxSize(int32_t bitRate); diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index d28d1ca7db1c..95fe6f6e987d 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -43,7 +43,6 @@ enum { 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) @@ -69,6 +68,21 @@ enum { kKeyDiscNumber = 'dnum', // cstring kKeyDate = 'date', // cstring kKeyWriter = 'writ', // cstring + + // Set this key to enable authoring files in 64-bit offset + kKey64BitFileOffset = 'fobt', // int32_t (bool) + + // Identify the file output format for authoring + // Please see <media/mediarecorder.h> for the supported + // file output formats. + kKeyFileType = 'ftyp', // int32_t + + // Track authoring progress status + // kKeyTrackTimeStatus is used to track progress in elapsed time + // kKeyTrackFrameStatus is used to track progress in authored frames + kKeyTrackFrameStatus = 'tkfm', // int32_t + kKeyTrackTimeStatus = 'tktm', // int64_t + }; enum { diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 68344917a679..1e20f7e59bc7 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -310,8 +310,8 @@ status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) { // 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 between 2 neighboring I frames -status_t StagefrightRecorder::setParamIFramesInterval(int32_t interval) { - LOGV("setParamIFramesInterval: %d seconds", interval); +status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) { + LOGV("setParamVideoIFramesInterval: %d seconds", interval); mIFramesInterval = interval; return OK; } @@ -323,6 +323,33 @@ status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) { return OK; } +status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) { + LOGV("setParamVideoCameraId: %d", cameraId); + if (cameraId < 0) { + return BAD_VALUE; + } + mCameraId = cameraId; + return OK; +} + +status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) { + LOGV("setParamTrackFrameStatus: %d", nFrames); + if (nFrames <= 0) { + return BAD_VALUE; + } + mTrackEveryNumberOfFrames = nFrames; + return OK; +} + +status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) { + LOGV("setParamTrackTimeStatus: %lld", timeDurationUs); + if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms? + return BAD_VALUE; + } + mTrackEveryTimeDurationUs = timeDurationUs; + return OK; +} + status_t StagefrightRecorder::setParameter( const String8 &key, const String8 &value) { LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); @@ -338,6 +365,26 @@ status_t StagefrightRecorder::setParameter( return setParamMaxDurationOrFileSize( max_filesize_bytes, false /* limit is filesize */); } + } else if (key == "interleave-duration-us") { + int32_t durationUs; + if (safe_strtoi32(value.string(), &durationUs)) { + return setParamInterleaveDuration(durationUs); + } + } else if (key == "param-use-64bit-offset") { + int32_t use64BitOffset; + if (safe_strtoi32(value.string(), &use64BitOffset)) { + return setParam64BitFileOffset(use64BitOffset != 0); + } + } else if (key == "param-track-frame-status") { + int32_t nFrames; + if (safe_strtoi32(value.string(), &nFrames)) { + return setParamTrackFrameStatus(nFrames); + } + } else if (key == "param-track-time-status") { + int64_t timeDurationUs; + if (safe_strtoi64(value.string(), &timeDurationUs)) { + return setParamTrackTimeStatus(timeDurationUs); + } } else if (key == "audio-param-sampling-rate") { int32_t sampling_rate; if (safe_strtoi32(value.string(), &sampling_rate)) { @@ -358,20 +405,15 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &video_bitrate)) { return setParamVideoEncodingBitRate(video_bitrate); } - } else if (key == "param-interleave-duration-us") { - int32_t durationUs; - if (safe_strtoi32(value.string(), &durationUs)) { - return setParamInterleaveDuration(durationUs); - } - } else if (key == "param-i-frames-interval") { + } else if (key == "video-param-i-frames-interval") { int32_t interval; if (safe_strtoi32(value.string(), &interval)) { - return setParamIFramesInterval(interval); + return setParamVideoIFramesInterval(interval); } - } else if (key == "param-use-64bit-offset") { - int32_t use64BitOffset; - if (safe_strtoi32(value.string(), &use64BitOffset)) { - return setParam64BitFileOffset(use64BitOffset != 0); + } else if (key == "video-param-camera-id") { + int32_t cameraId; + if (safe_strtoi32(value.string(), &cameraId)) { + return setParamVideoCameraId(cameraId); } } else { LOGE("setParameter: failed to find key %s", key.string()); @@ -677,7 +719,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { int64_t token = IPCThreadState::self()->clearCallingIdentity(); if (mCamera == 0) { - mCamera = Camera::connect(0); + mCamera = Camera::connect(mCameraId); mCamera->lock(); } @@ -778,8 +820,16 @@ status_t StagefrightRecorder::startMPEG4Recording() { } mWriter->setListener(mListener); sp<MetaData> meta = new MetaData; + meta->setInt64(kKeyTime, systemTime() / 1000); + meta->setInt32(kKeyFileType, mOutputFormat); meta->setInt32(kKeyBitRate, totalBitRate); meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + if (mTrackEveryNumberOfFrames > 0) { + meta->setInt32(kKeyTrackFrameStatus, mTrackEveryNumberOfFrames); + } + if (mTrackEveryTimeDurationUs > 0) { + meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); + } mWriter->start(meta.get()); return OK; } @@ -842,6 +892,9 @@ status_t StagefrightRecorder::reset() { mIFramesInterval = 1; mAudioSourceNode = 0; mUse64BitFileOffset = false; + mCameraId = 0; + mTrackEveryNumberOfFrames = 0; + mTrackEveryTimeDurationUs = 0; mEncoderProfiles = MediaProfiles::getInstance(); mOutputFd = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 2943e97f9f02..9fb7e8f75e33 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -81,8 +81,11 @@ private: int32_t mSampleRate; int32_t mInterleaveDurationUs; int32_t mIFramesInterval; + int32_t mCameraId; int64_t mMaxFileSizeBytes; int64_t mMaxFileDurationUs; + int32_t mTrackEveryNumberOfFrames; + int64_t mTrackEveryTimeDurationUs; String8 mParams; int mOutputFd; @@ -95,12 +98,15 @@ private: status_t startAACRecording(); sp<MediaSource> createAudioSource(); status_t setParameter(const String8 &key, const String8 &value); - status_t setParamVideoEncodingBitRate(int32_t bitRate); status_t setParamAudioEncodingBitRate(int32_t bitRate); status_t setParamAudioNumberOfChannels(int32_t channles); status_t setParamAudioSamplingRate(int32_t sampleRate); + status_t setParamVideoEncodingBitRate(int32_t bitRate); + status_t setParamVideoIFramesInterval(int32_t interval); + status_t setParamVideoCameraId(int32_t cameraId); + status_t setParamTrackTimeStatus(int64_t timeDurationUs); + status_t setParamTrackFrameStatus(int32_t nFrames); 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(); diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 6d1dd1607067..c71743ef717b 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -253,7 +253,7 @@ void AMRWriter::threadFunc() { } if (stoppedPrematurely) { - notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0); + notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_COMPLETION_STATUS, UNKNOWN_ERROR); } fflush(mFile); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 65d109b7cf06..b3e1a0189ce9 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -41,7 +41,7 @@ public: Track(MPEG4Writer *owner, const sp<MediaSource> &source); ~Track(); - status_t start(int64_t startTimeUs); + status_t start(MetaData *params); void stop(); void pause(); bool reachedEOS(); @@ -101,9 +101,13 @@ private: void *mCodecSpecificData; size_t mCodecSpecificDataSize; bool mGotAllCodecSpecificData; + bool mTrackingProgressStatus; bool mReachedEOS; int64_t mStartTimestampUs; + int64_t mPreviousTrackTimeUs; + int64_t mTrackEveryTimeDurationUs; + int32_t mTrackEveryNumberOfFrames; static void *ThreadWrapper(void *me); void threadEntry(); @@ -114,6 +118,8 @@ private: void logStatisticalData(bool isAudio); void findMinMaxFrameRates(float *minFps, float *maxFps); void findMinMaxChunkDurations(int64_t *min, int64_t *max); + void trackProgressStatus(int32_t nFrames, int64_t timeUs); + void initTrackingProgressStatus(MetaData *params); Track(const Track &); Track &operator=(const Track &); @@ -162,11 +168,10 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { return OK; } -status_t MPEG4Writer::startTracks() { - int64_t startTimeUs = systemTime() / 1000; +status_t MPEG4Writer::startTracks(MetaData *params) { for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { - status_t err = (*it)->start(startTimeUs); + status_t err = (*it)->start(params); if (err != OK) { for (List<Track *>::iterator it2 = mTracks.begin(); @@ -247,10 +252,11 @@ status_t MPEG4Writer::start(MetaData *param) { } mStartTimestampUs = -1; + if (mStarted) { if (mPaused) { mPaused = false; - return startTracks(); + return startTracks(param); } return OK; } @@ -261,9 +267,18 @@ status_t MPEG4Writer::start(MetaData *param) { mMoovBoxBufferOffset = 0; beginBox("ftyp"); - writeFourcc("isom"); + { + int32_t fileType; + if (param && param->findInt32(kKeyFileType, &fileType) && + fileType != OUTPUT_FORMAT_MPEG_4) { + writeFourcc("3gp4"); + } else { + writeFourcc("isom"); + } + } writeInt32(0); writeFourcc("isom"); + writeFourcc("3gp4"); endBox(); mFreeBoxOffset = mOffset; @@ -288,8 +303,7 @@ status_t MPEG4Writer::start(MetaData *param) { } else { write("\x00\x00\x00\x01mdat????????", 16); } - - status_t err = startTracks(); + status_t err = startTracks(param); if (err != OK) { return err; } @@ -670,13 +684,41 @@ MPEG4Writer::Track::~Track() { } } -status_t MPEG4Writer::Track::start(int64_t startTimeUs) { +void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { + LOGV("initTrackingProgressStatus"); + mPreviousTrackTimeUs = -1; + mTrackingProgressStatus = false; + mTrackEveryTimeDurationUs = 0; + mTrackEveryNumberOfFrames = 0; + { + int64_t timeUs; + if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { + LOGV("Receive request to track progress status for every %lld us", timeUs); + mTrackEveryTimeDurationUs = timeUs; + mTrackingProgressStatus = true; + } + } + { + int32_t nFrames; + if (params && params->findInt32(kKeyTrackFrameStatus, &nFrames)) { + LOGV("Receive request to track progress status for every %d frames", nFrames); + mTrackEveryNumberOfFrames = nFrames; + mTrackingProgressStatus = true; + } + } +} + +status_t MPEG4Writer::Track::start(MetaData *params) { if (!mDone && mPaused) { mPaused = false; mResumed = true; return OK; } + int64_t startTimeUs; + CHECK(params && params->findInt64(kKeyTime, &startTimeUs)); + initTrackingProgressStatus(params); + sp<MetaData> meta = new MetaData; meta->setInt64(kKeyTime, startTimeUs); status_t err = mSource->start(meta.get()); @@ -848,8 +890,9 @@ void MPEG4Writer::Track::threadEntry() { int64_t previousPausedDurationUs = 0; sp<MetaData> meta_data; + status_t err = OK; MediaBuffer *buffer; - while (!mDone && mSource->read(&buffer) == OK) { + while (!mDone && (err = mSource->read(&buffer)) == OK) { if (buffer->range_length() == 0) { buffer->release(); buffer = NULL; @@ -1062,6 +1105,12 @@ void MPEG4Writer::Track::threadEntry() { mStssTableEntries.push_back(mSampleInfos.size()); } + if (mTrackingProgressStatus) { + if (mPreviousTrackTimeUs <= 0) { + mPreviousTrackTimeUs = mStartTimestampUs; + } + trackProgressStatus(mSampleInfos.size(), timestampUs); + } if (mOwner->numTracks() == 1) { off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy) : mOwner->addSample_l(copy); @@ -1101,8 +1150,9 @@ void MPEG4Writer::Track::threadEntry() { } if (mSampleInfos.empty()) { - mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0); + err = UNKNOWN_ERROR; } + mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_COMPLETION_STATUS, err); // Last chunk if (mOwner->numTracks() == 1) { @@ -1132,6 +1182,24 @@ void MPEG4Writer::Track::threadEntry() { logStatisticalData(is_audio); } +void MPEG4Writer::Track::trackProgressStatus(int32_t nFrames, int64_t timeUs) { + LOGV("trackProgressStatus: %d frames and %lld us", nFrames, timeUs); + if (nFrames % mTrackEveryNumberOfFrames == 0) { + LOGV("Fire frame tracking progress status at frame %d", nFrames); + mOwner->notify(MEDIA_RECORDER_EVENT_INFO, + MEDIA_RECORDER_INFO_PROGRESS_FRAME_STATUS, + nFrames); + } + + if (timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { + LOGV("Fire time tracking progress status at %lld us", timeUs); + mOwner->notify(MEDIA_RECORDER_EVENT_INFO, + MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS, + timeUs / 1000); + mPreviousTrackTimeUs = timeUs; + } +} + void MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) { int32_t minSampleDuration = 0x7FFFFFFF; int32_t maxSampleDuration = 0; |