am d6ec2175: am 65c83b90: Merge "Refactor Stagefright::StartMPEG4Recording()" into gingerbread

Merge commit 'd6ec21751b26a35fc8c912940a2c4720bdbf1083'

* commit 'd6ec21751b26a35fc8c912940a2c4720bdbf1083':
  Refactor Stagefright::StartMPEG4Recording()
This commit is contained in:
James Dong
2010-07-01 14:15:00 -07:00
committed by Android Git Automerger
2 changed files with 193 additions and 159 deletions

View File

@@ -69,6 +69,7 @@ status_t StagefrightRecorder::setAudioSource(audio_source as) {
LOGV("setAudioSource: %d", as);
if (as < AUDIO_SOURCE_DEFAULT ||
as >= AUDIO_SOURCE_LIST_END) {
LOGE("Invalid audio source: %d", as);
return BAD_VALUE;
}
@@ -85,6 +86,7 @@ status_t StagefrightRecorder::setVideoSource(video_source vs) {
LOGV("setVideoSource: %d", vs);
if (vs < VIDEO_SOURCE_DEFAULT ||
vs >= VIDEO_SOURCE_LIST_END) {
LOGE("Invalid video source: %d", vs);
return BAD_VALUE;
}
@@ -101,6 +103,7 @@ status_t StagefrightRecorder::setOutputFormat(output_format of) {
LOGV("setOutputFormat: %d", of);
if (of < OUTPUT_FORMAT_DEFAULT ||
of >= OUTPUT_FORMAT_LIST_END) {
LOGE("Invalid output format: %d", of);
return BAD_VALUE;
}
@@ -117,6 +120,7 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
LOGV("setAudioEncoder: %d", ae);
if (ae < AUDIO_ENCODER_DEFAULT ||
ae >= AUDIO_ENCODER_LIST_END) {
LOGE("Invalid audio encoder: %d", ae);
return BAD_VALUE;
}
@@ -133,6 +137,7 @@ status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
LOGV("setVideoEncoder: %d", ve);
if (ve < VIDEO_ENCODER_DEFAULT ||
ve >= VIDEO_ENCODER_LIST_END) {
LOGE("Invalid video encoder: %d", ve);
return BAD_VALUE;
}
@@ -176,7 +181,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
LOGV("setCamera");
if (camera == 0) {
LOGE("camera is NULL");
return UNKNOWN_ERROR;
return BAD_VALUE;
}
int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -185,7 +190,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
if (mCamera == 0) {
LOGE("Unable to connect to camera");
IPCThreadState::self()->restoreCallingIdentity(token);
return UNKNOWN_ERROR;
return -EBUSY;
}
LOGV("Connected to camera");
@@ -206,11 +211,11 @@ status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
}
status_t StagefrightRecorder::setOutputFile(const char *path) {
LOGE("setOutputFile(const char*) should not be called");
LOGE("setOutputFile(const char*) must not be called");
// We don't actually support this at all, as the media_server process
// no longer has permissions to create files.
return UNKNOWN_ERROR;
return -EPERM;
}
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
@@ -219,6 +224,11 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng
CHECK_EQ(offset, 0);
CHECK_EQ(length, 0);
if (fd < 0) {
LOGE("Invalid file descriptor: %d", fd);
return -EBADF;
}
if (mOutputFd >= 0) {
::close(mOutputFd);
}
@@ -294,6 +304,7 @@ status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
LOGV("setParamAudioNumberOfChannels: %d", channels);
if (channels <= 0 || channels >= 3) {
LOGE("Invalid number of audio channels: %d", channels);
return BAD_VALUE;
}
// Additional check on the number of channels will be performed later.
@@ -331,21 +342,23 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
return OK;
}
status_t StagefrightRecorder::setParamMaxDurationOrFileSize(int64_t limit,
bool limit_is_duration) {
LOGV("setParamMaxDurationOrFileSize: limit (%lld) for %s",
limit, limit_is_duration?"duration":"size");
if (limit_is_duration) { // limit is in ms
if (limit <= 1000) { // XXX: 1 second
LOGE("Max file duration is too short: %lld us", limit);
}
mMaxFileDurationUs = limit * 1000LL;
} else {
if (limit <= 1024) { // XXX: 1 kB
LOGE("Max file size is too small: %lld bytes", limit);
}
mMaxFileSizeBytes = limit;
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
if (timeUs <= 1000000LL) { // XXX: 1 second
LOGE("Max file duration is too short: %lld us", timeUs);
return BAD_VALUE;
}
mMaxFileDurationUs = timeUs;
return OK;
}
status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
if (bytes <= 1024) { // XXX: 1 kB
LOGE("Max file size is too small: %lld bytes", bytes);
return BAD_VALUE;
}
mMaxFileSizeBytes = bytes;
return OK;
}
@@ -370,7 +383,7 @@ 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
// 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;
@@ -396,6 +409,7 @@ status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) {
LOGV("setParamTrackFrameStatus: %d", nFrames);
if (nFrames <= 0) {
LOGE("Invalid number of frames to track: %d", nFrames);
return BAD_VALUE;
}
mTrackEveryNumberOfFrames = nFrames;
@@ -405,6 +419,7 @@ status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) {
status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
LOGE("Tracking time duration too short: %lld us", timeDurationUs);
return BAD_VALUE;
}
mTrackEveryTimeDurationUs = timeDurationUs;
@@ -417,14 +432,12 @@ status_t StagefrightRecorder::setParameter(
if (key == "max-duration") {
int64_t max_duration_ms;
if (safe_strtoi64(value.string(), &max_duration_ms)) {
return setParamMaxDurationOrFileSize(
max_duration_ms, true /* limit_is_duration */);
return setParamMaxFileDurationUs(1000LL * max_duration_ms);
}
} else if (key == "max-filesize") {
int64_t max_filesize_bytes;
if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
return setParamMaxDurationOrFileSize(
max_filesize_bytes, false /* limit is filesize */);
return setParamMaxFileSizeBytes(max_filesize_bytes);
}
} else if (key == "interleave-duration-us") {
int32_t durationUs;
@@ -528,7 +541,10 @@ status_t StagefrightRecorder::prepare() {
}
status_t StagefrightRecorder::start() {
CHECK(mOutputFd >= 0);
if (mWriter != NULL) {
LOGE("File writer is not avaialble");
return UNKNOWN_ERROR;
}
@@ -547,6 +563,7 @@ status_t StagefrightRecorder::start() {
return startAACRecording();
default:
LOGE("Unsupported output file format: %d", mOutputFormat);
return UNKNOWN_ERROR;
}
}
@@ -610,7 +627,6 @@ status_t StagefrightRecorder::startAACRecording() {
CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
CHECK(mOutputFd >= 0);
CHECK(0 == "AACWriter is not implemented yet");
@@ -626,34 +642,34 @@ status_t StagefrightRecorder::startAMRRecording() {
mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
LOGE("Invalid encoder %d used for AMRNB recording",
mAudioEncoder);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
if (mSampleRate != 8000) {
LOGE("Invalid sampling rate %d used for AMRNB recording",
mSampleRate);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
} else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
LOGE("Invlaid encoder %d used for AMRWB recording",
mAudioEncoder);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
if (mSampleRate != 16000) {
LOGE("Invalid sample rate %d used for AMRWB recording",
mSampleRate);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
}
if (mAudioChannels != 1) {
LOGE("Invalid number of audio channels %d used for amr recording",
mAudioChannels);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
LOGE("Invalid audio source: %d", mAudioSource);
return UNKNOWN_ERROR;
return BAD_VALUE;
}
sp<MediaSource> audioEncoder = createAudioSource();
@@ -662,7 +678,6 @@ status_t StagefrightRecorder::startAMRRecording() {
return UNKNOWN_ERROR;
}
CHECK(mOutputFd >= 0);
mWriter = new AMRWriter(dup(mOutputFd));
mWriter->addSource(audioEncoder);
@@ -729,6 +744,54 @@ void StagefrightRecorder::clipVideoFrameWidth() {
}
}
status_t StagefrightRecorder::setupCameraSource() {
clipVideoBitRate();
clipVideoFrameRate();
clipVideoFrameWidth();
clipVideoFrameHeight();
int64_t token = IPCThreadState::self()->clearCallingIdentity();
if (mCamera == 0) {
mCamera = Camera::connect(mCameraId);
if (mCamera == 0) {
LOGE("Camera connection could not be established.");
return -EBUSY;
}
mFlags &= ~FLAGS_HOT_CAMERA;
mCamera->lock();
}
// Set the actual video recording frame size
CameraParameters params(mCamera->getParameters());
params.setPreviewSize(mVideoWidth, mVideoHeight);
params.setPreviewFrameRate(mFrameRate);
String8 s = params.flatten();
CHECK_EQ(OK, mCamera->setParameters(s));
CameraParameters newCameraParams(mCamera->getParameters());
// Check on video frame size
int frameWidth = 0, frameHeight = 0;
newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
if (frameWidth < 0 || frameWidth != mVideoWidth ||
frameHeight < 0 || frameHeight != mVideoHeight) {
LOGE("Failed to set the video frame size to %dx%d",
mVideoWidth, mVideoHeight);
IPCThreadState::self()->restoreCallingIdentity(token);
return UNKNOWN_ERROR;
}
// Check on video frame rate
int frameRate = newCameraParams.getPreviewFrameRate();
if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
LOGE("Failed to set frame rate to %d fps. The actual "
"frame rate is %d", mFrameRate, frameRate);
}
CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
IPCThreadState::self()->restoreCallingIdentity(token);
return OK;
}
void StagefrightRecorder::clipVideoFrameHeight() {
LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
@@ -746,146 +809,110 @@ void StagefrightRecorder::clipVideoFrameHeight() {
}
}
status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
status_t err = setupCameraSource();
if (err != OK) return err;
sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera);
CHECK(cameraSource != NULL);
sp<MetaData> enc_meta = new MetaData;
enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
enc_meta->setInt32(kKeySampleRate, mFrameRate);
switch (mVideoEncoder) {
case VIDEO_ENCODER_H263:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
break;
case VIDEO_ENCODER_MPEG_4_SP:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
break;
case VIDEO_ENCODER_H264:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
break;
default:
CHECK(!"Should not be here, unsupported video encoding.");
break;
}
sp<MetaData> meta = cameraSource->getFormat();
int32_t width, height, stride, sliceHeight;
CHECK(meta->findInt32(kKeyWidth, &width));
CHECK(meta->findInt32(kKeyHeight, &height));
CHECK(meta->findInt32(kKeyStride, &stride));
CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
enc_meta->setInt32(kKeyStride, stride);
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
OMXClient client;
CHECK_EQ(client.connect(), OK);
sp<MediaSource> encoder = OMXCodec::Create(
client.interface(), enc_meta,
true /* createEncoder */, cameraSource);
if (encoder == NULL) {
return UNKNOWN_ERROR;
}
writer->addSource(encoder);
return OK;
}
status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
sp<MediaSource> audioEncoder;
switch(mAudioEncoder) {
case AUDIO_ENCODER_AMR_NB:
case AUDIO_ENCODER_AMR_WB:
case AUDIO_ENCODER_AAC:
audioEncoder = createAudioSource();
break;
default:
LOGE("Unsupported audio encoder: %d", mAudioEncoder);
return UNKNOWN_ERROR;
}
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
writer->addSource(audioEncoder);
return OK;
}
status_t StagefrightRecorder::startMPEG4Recording() {
mWriter = new MPEG4Writer(dup(mOutputFd));
int32_t totalBitRate = 0;
status_t err = OK;
sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
// Add audio source first if it exists
if (mAudioSource != AUDIO_SOURCE_LIST_END) {
sp<MediaSource> audioEncoder;
switch(mAudioEncoder) {
case AUDIO_ENCODER_AMR_NB:
case AUDIO_ENCODER_AMR_WB:
case AUDIO_ENCODER_AAC:
audioEncoder = createAudioSource();
break;
default:
LOGE("Unsupported audio encoder: %d", mAudioEncoder);
return UNKNOWN_ERROR;
}
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
err = setupAudioEncoder(writer);
if (err != OK) return err;
totalBitRate += mAudioBitRate;
mWriter->addSource(audioEncoder);
}
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
clipVideoBitRate();
clipVideoFrameRate();
clipVideoFrameWidth();
clipVideoFrameHeight();
int64_t token = IPCThreadState::self()->clearCallingIdentity();
if (mCamera == 0) {
mCamera = Camera::connect(mCameraId);
if (mCamera == 0) {
LOGE("Camera connection could not be established.");
return -EBUSY;
}
mFlags &= ~FLAGS_HOT_CAMERA;
mCamera->lock();
}
// Set the actual video recording frame size
CameraParameters params(mCamera->getParameters());
params.setPreviewSize(mVideoWidth, mVideoHeight);
params.setPreviewFrameRate(mFrameRate);
String8 s = params.flatten();
CHECK_EQ(OK, mCamera->setParameters(s));
CameraParameters newCameraParams(mCamera->getParameters());
// Check on video frame size
int frameWidth = 0, frameHeight = 0;
newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
if (frameWidth < 0 || frameWidth != mVideoWidth ||
frameHeight < 0 || frameHeight != mVideoHeight) {
LOGE("Failed to set the video frame size to %dx%d",
mVideoWidth, mVideoHeight);
IPCThreadState::self()->restoreCallingIdentity(token);
return UNKNOWN_ERROR;
}
// Check on video frame rate
int frameRate = newCameraParams.getPreviewFrameRate();
if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
LOGE("Failed to set frame rate to %d fps. The actual "
"frame rate is %d", mFrameRate, frameRate);
}
CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
IPCThreadState::self()->restoreCallingIdentity(token);
sp<CameraSource> cameraSource =
CameraSource::CreateFromCamera(mCamera);
CHECK(cameraSource != NULL);
sp<MetaData> enc_meta = new MetaData;
enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
enc_meta->setInt32(kKeySampleRate, mFrameRate);
switch (mVideoEncoder) {
case VIDEO_ENCODER_H263:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
break;
case VIDEO_ENCODER_MPEG_4_SP:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
break;
case VIDEO_ENCODER_H264:
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
break;
default:
CHECK(!"Should not be here, unsupported video encoding.");
break;
}
sp<MetaData> meta = cameraSource->getFormat();
int32_t width, height, stride, sliceHeight;
CHECK(meta->findInt32(kKeyWidth, &width));
CHECK(meta->findInt32(kKeyHeight, &height));
CHECK(meta->findInt32(kKeyStride, &stride));
CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
enc_meta->setInt32(kKeyStride, stride);
enc_meta->setInt32(kKeySliceHeight, sliceHeight);
OMXClient client;
CHECK_EQ(client.connect(), OK);
sp<MediaSource> encoder =
OMXCodec::Create(
client.interface(), enc_meta,
true /* createEncoder */, cameraSource);
CHECK(mOutputFd >= 0);
err = setupVideoEncoder(writer);
if (err != OK) return err;
totalBitRate += mVideoBitRate;
mWriter->addSource(encoder);
}
{
// MPEGWriter specific handling
MPEG4Writer *writer = ((MPEG4Writer *) mWriter.get());
writer->setInterleaveDuration(mInterleaveDurationUs);
}
reinterpret_cast<MPEG4Writer *>(writer.get())->
setInterleaveDuration(mInterleaveDurationUs);
if (mMaxFileDurationUs != 0) {
mWriter->setMaxFileDuration(mMaxFileDurationUs);
writer->setMaxFileDuration(mMaxFileDurationUs);
}
if (mMaxFileSizeBytes != 0) {
mWriter->setMaxFileSize(mMaxFileSizeBytes);
writer->setMaxFileSize(mMaxFileSizeBytes);
}
mWriter->setListener(mListener);
sp<MetaData> meta = new MetaData;
meta->setInt64(kKeyTime, systemTime() / 1000);
meta->setInt32(kKeyFileType, mOutputFormat);
@@ -897,8 +924,9 @@ status_t StagefrightRecorder::startMPEG4Recording() {
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
mWriter->start(meta.get());
return OK;
writer->setListener(mListener);
mWriter = writer;
return mWriter->start(meta.get());
}
status_t StagefrightRecorder::pause() {
@@ -914,7 +942,7 @@ status_t StagefrightRecorder::stop() {
LOGV("stop");
if (mWriter != NULL) {
mWriter->stop();
mWriter = NULL;
mWriter.clear();
}
if (mCamera != 0) {
@@ -925,7 +953,7 @@ status_t StagefrightRecorder::stop() {
mCamera->stopPreview();
}
mCamera->unlock();
mCamera = NULL;
mCamera.clear();
IPCThreadState::self()->restoreCallingIdentity(token);
mFlags = 0;
}

View File

@@ -97,6 +97,11 @@ private:
status_t startAMRRecording();
status_t startAACRecording();
sp<MediaSource> createAudioSource();
status_t setupCameraSource();
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
status_t setupVideoEncoder(const sp<MediaWriter>& writer);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
status_t setParamAudioEncodingBitRate(int32_t bitRate);
status_t setParamAudioNumberOfChannels(int32_t channles);
@@ -108,7 +113,8 @@ private:
status_t setParamTrackFrameStatus(int32_t nFrames);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration);
status_t setParamMaxFileDurationUs(int64_t timeUs);
status_t setParamMaxFileSizeBytes(int64_t bytes);
void clipVideoBitRate();
void clipVideoFrameRate();
void clipVideoFrameWidth();