Merge "Provide progress status report during authoring" into gingerbread

This commit is contained in:
James Dong
2010-06-25 16:40:47 -07:00
committed by Android (Google) Code Review
7 changed files with 174 additions and 31 deletions

View File

@@ -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,
};
// ----------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;