Allowing setting of time lapse parameters through MediaRecorder.java

added setTimeLapseParameters() to MediaRecorder.java and SetParameter support
in StagefrightRecorder to allow enabling time lapse and setting the corresponding
parameters.

Change-Id: I509040aa71f8d3fc37337b0894a81d9c0fd7a40a
This commit is contained in:
Nipun Kwatra
2010-07-20 21:33:31 -07:00
parent 9c9d0684a0
commit d01371bf69
5 changed files with 96 additions and 15 deletions

View File

@@ -33,11 +33,13 @@ class CameraSourceTimeLapse : public CameraSource {
public:
static CameraSourceTimeLapse *Create(bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate);
static CameraSourceTimeLapse *CreateFromCamera(const sp<Camera> &camera,
bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate);
virtual ~CameraSourceTimeLapse();
@@ -70,6 +72,7 @@ private:
CameraSourceTimeLapse(const sp<Camera> &camera,
bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate);
// For still camera case starts a thread which calls camera's takePicture()

View File

@@ -278,6 +278,23 @@ public class MediaRecorder
setAudioEncoder(profile.audioCodec);
}
/**
* Enables/Disables time lapse capture and sets its parameters. This method should
* be called after setProfile().
*
* @param enableTimeLapse Pass true to enable time lapse capture, false to disable it.
* @param timeBetweenTimeLapseFrameCaptureMs time between two captures of time lapse frames.
* @param encoderLevel the video encoder level.
*/
public void setTimeLapseParameters(boolean enableTimeLapse,
int timeBetweenTimeLapseFrameCaptureMs, int encoderLevel) {
setParameter(String.format("time-lapse-enable=%d",
(enableTimeLapse) ? 1 : 0));
setParameter(String.format("time-between-time-lapse-frame-capture=%d",
timeBetweenTimeLapseFrameCaptureMs));
setVideoEncoderLevel(encoderLevel);
}
/**
* Sets the format of the output file produced during recording. Call this
* after setAudioSource()/setVideoSource() but before prepare().
@@ -444,6 +461,15 @@ public class MediaRecorder
setParameter(String.format("video-param-encoding-bitrate=%d", bitRate));
}
/**
* Sets the level of the encoder. Call this before prepare().
*
* @param encoderLevel the video encoder level.
*/
public void setVideoEncoderLevel(int encoderLevel) {
setParameter(String.format("video-param-encoder-level=%d", encoderLevel));
}
/**
* Pass in the file descriptor of the file to be written. Call this after
* setOutputFormat() but before prepare().

View File

@@ -473,6 +473,32 @@ status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
return OK;
}
status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
if(timeLapseEnable == 0) {
mCaptureTimeLapse = false;
} else if (timeLapseEnable == 1) {
mCaptureTimeLapse = true;
} else {
return BAD_VALUE;
}
return OK;
}
status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
// Not allowing time more than a day
if (timeUs <= 0 || timeUs > 86400*1E6) {
LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
return BAD_VALUE;
}
mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
return OK;
}
status_t StagefrightRecorder::setParameter(
const String8 &key, const String8 &value) {
LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
@@ -556,6 +582,17 @@ status_t StagefrightRecorder::setParameter(
if (safe_strtoi32(value.string(), &timeScale)) {
return setParamVideoTimeScale(timeScale);
}
} else if (key == "time-lapse-enable") {
int32_t timeLapseEnable;
if (safe_strtoi32(value.string(), &timeLapseEnable)) {
return setParamTimeLapseEnable(timeLapseEnable);
}
} else if (key == "time-between-time-lapse-frame-capture") {
int64_t timeBetweenTimeLapseFrameCaptureMs;
if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
return setParamTimeBetweenTimeLapseFrameCapture(
1000LL * timeBetweenTimeLapseFrameCaptureMs);
}
} else {
LOGE("setParameter: failed to find key %s", key.string());
}
@@ -813,10 +850,14 @@ void StagefrightRecorder::clipVideoFrameWidth() {
}
status_t StagefrightRecorder::setupCameraSource() {
clipVideoBitRate();
clipVideoFrameRate();
clipVideoFrameWidth();
clipVideoFrameHeight();
if(!mCaptureTimeLapse) {
// Dont clip for time lapse capture as encoder will have enough
// time to encode because of slow capture rate of time lapse.
clipVideoBitRate();
clipVideoFrameRate();
clipVideoFrameWidth();
clipVideoFrameHeight();
}
int64_t token = IPCThreadState::self()->clearCallingIdentity();
if (mCamera == 0) {
@@ -831,7 +872,13 @@ status_t StagefrightRecorder::setupCameraSource() {
// Set the actual video recording frame size
CameraParameters params(mCamera->getParameters());
params.setPreviewSize(mVideoWidth, mVideoHeight);
// dont change the preview size for time lapse as mVideoWidth, mVideoHeight
// may correspond to HD resolution not supported by video camera.
if (!mCaptureTimeLapse) {
params.setPreviewSize(mVideoWidth, mVideoHeight);
}
params.setPreviewFrameRate(mFrameRate);
String8 s = params.flatten();
CHECK_EQ(OK, mCamera->setParameters(s));
@@ -840,8 +887,9 @@ status_t StagefrightRecorder::setupCameraSource() {
// Check on video frame size
int frameWidth = 0, frameHeight = 0;
newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
if (frameWidth < 0 || frameWidth != mVideoWidth ||
frameHeight < 0 || frameHeight != mVideoHeight) {
if (!mCaptureTimeLapse &&
(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);
@@ -882,7 +930,8 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
if (err != OK) return err;
sp<CameraSource> cameraSource = (mCaptureTimeLapse) ?
CameraSourceTimeLapse::CreateFromCamera(mCamera, true, 3E6, mFrameRate):
CameraSourceTimeLapse::CreateFromCamera(mCamera, true,
mTimeBetweenTimeLapseFrameCaptureUs, mVideoWidth, mVideoHeight, mFrameRate):
CameraSource::CreateFromCamera(mCamera);
CHECK(cameraSource != NULL);
@@ -934,6 +983,7 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
OMXClient client;
CHECK_EQ(client.connect(), OK);
// Use software codec for time lapse
uint32_t encoder_flags = (mCaptureTimeLapse) ? OMXCodec::kPreferSoftwareCodecs : 0;
sp<MediaSource> encoder = OMXCodec::Create(
client.interface(), enc_meta,
@@ -1081,6 +1131,7 @@ status_t StagefrightRecorder::reset() {
mMaxFileSizeBytes = 0;
mTrackEveryTimeDurationUs = 0;
mCaptureTimeLapse = false;
mTimeBetweenTimeLapseFrameCaptureUs = -1;
mEncoderProfiles = MediaProfiles::getInstance();
mOutputFd = -1;

View File

@@ -93,6 +93,7 @@ private:
int64_t mTrackEveryTimeDurationUs;
bool mCaptureTimeLapse;
int64_t mTimeBetweenTimeLapseFrameCaptureUs;
String8 mParams;
int mOutputFd;
@@ -114,6 +115,8 @@ private:
status_t setParamAudioNumberOfChannels(int32_t channles);
status_t setParamAudioSamplingRate(int32_t sampleRate);
status_t setParamAudioTimeScale(int32_t timeScale);
status_t setParamTimeLapseEnable(int32_t timeLapseEnable);
status_t setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs);
status_t setParamVideoEncodingBitRate(int32_t bitRate);
status_t setParamVideoIFramesInterval(int32_t seconds);
status_t setParamVideoEncoderProfile(int32_t profile);

View File

@@ -33,6 +33,7 @@ namespace android {
// static
CameraSourceTimeLapse *CameraSourceTimeLapse::Create(bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate) {
sp<Camera> camera = Camera::connect(0);
@@ -41,25 +42,27 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::Create(bool useStillCameraForTimeL
}
return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse,
timeBetweenTimeLapseFrameCaptureUs, videoFrameRate);
timeBetweenTimeLapseFrameCaptureUs, width, height, videoFrameRate);
}
// static
CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera,
bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate) {
if (camera.get() == NULL) {
return NULL;
}
return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse,
timeBetweenTimeLapseFrameCaptureUs, videoFrameRate);
timeBetweenTimeLapseFrameCaptureUs, width, height, videoFrameRate);
}
CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera,
bool useStillCameraForTimeLapse,
int64_t timeBetweenTimeLapseFrameCaptureUs,
int32_t width, int32_t height,
int32_t videoFrameRate)
: CameraSource(camera),
mUseStillCameraForTimeLapse(useStillCameraForTimeLapse),
@@ -70,11 +73,6 @@ CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera,
LOGV("starting time lapse mode");
if(mUseStillCameraForTimeLapse) {
// Currently hardcoded the picture size. Will need to choose
// automatically or pass in from the app.
int32_t width, height;
width = 1024;
height = 768;
mMeta->setInt32(kKeyWidth, width);
mMeta->setInt32(kKeyHeight, height);
}