Merge "Provide progress status report during authoring" into gingerbread
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user