Adding support for parallel recording sessions.

- Added setOutputFileAuxiliary to pass the auxiliary file descriptor. The java
interface through JNI will be checked in next.

- renamed setupCameraSource to setupCamera as the function just sets the camera.
- Added setupCameraSource which sets up the camera source. This functionality
  was in setupVideoEncoder before.
- setupVideoEncoder now takes in a cameraSource instead of creating it on it
  own.

- Refactored startMPEG4Recording() to use setupMPEG4Recording,
  setupMPEG4MetaData.
    - setupMPEG4Recording() takes in file descriptor, bitrates to setup a mpeg4
      writer. This function can be called multiple times to setup multiple
      writers.
    - Added setupMPEG4MetaData() for setting up the meta data for mpeg4 writer.
  startMPEG4Recording() now calls setupMPEG4Recording, setupMPEG4MetaData for
  each recording session.

Change-Id: I07f5334a1ff8e12a36f58e94129fcfa6add2208b
This commit is contained in:
Nipun Kwatra
2010-08-26 17:05:18 -07:00
parent 6b2a75751d
commit d7e7a3f98f
3 changed files with 198 additions and 36 deletions

View File

@@ -25,6 +25,7 @@
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MediaSourceSplitter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
@@ -46,8 +47,8 @@
namespace android {
StagefrightRecorder::StagefrightRecorder()
: mWriter(NULL),
mOutputFd(-1) {
: mWriter(NULL), mWriterAux(NULL),
mOutputFd(-1), mOutputFdAux(-1) {
LOGV("Constructor");
reset();
@@ -235,6 +236,24 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng
return OK;
}
status_t StagefrightRecorder::setOutputFileAuxiliary(int fd) {
LOGV("setOutputFileAuxiliary: %d", fd);
if (fd < 0) {
LOGE("Invalid file descriptor: %d", fd);
return -EBADF;
}
mCaptureAuxVideo = true;
if (mOutputFdAux >= 0) {
::close(mOutputFdAux);
}
mOutputFdAux = dup(fd);
return OK;
}
// Attempt to parse an int64 literal optionally surrounded by whitespace,
// returns true on success, false otherwise.
static bool safe_strtoi64(const char *s, int64_t *val) {
@@ -842,7 +861,14 @@ status_t StagefrightRecorder::startRTPRecording() {
if (mAudioSource != AUDIO_SOURCE_LIST_END) {
source = createAudioSource();
} else {
status_t err = setupVideoEncoder(&source);
sp<CameraSource> cameraSource;
status_t err = setupCameraSource(&cameraSource);
if (err != OK) {
return err;
}
err = setupVideoEncoder(cameraSource, mVideoBitRate, &source);
if (err != OK) {
return err;
}
@@ -906,7 +932,7 @@ void StagefrightRecorder::clipVideoFrameWidth() {
}
}
status_t StagefrightRecorder::setupCameraSource() {
status_t StagefrightRecorder::setupCamera() {
if (!mCaptureTimeLapse) {
// Dont clip for time lapse capture as encoder will have enough
// time to encode because of slow capture rate of time lapse.
@@ -989,20 +1015,27 @@ void StagefrightRecorder::clipVideoFrameHeight() {
}
}
status_t StagefrightRecorder::setupVideoEncoder(sp<MediaSource> *source) {
source->clear();
status_t err = setupCameraSource();
status_t StagefrightRecorder::setupCameraSource(sp<CameraSource> *cameraSource) {
status_t err = setupCamera();
if (err != OK) return err;
sp<CameraSource> cameraSource = (mCaptureTimeLapse) ?
*cameraSource = (mCaptureTimeLapse) ?
CameraSourceTimeLapse::CreateFromCamera(mCamera, mUseStillCameraForTimeLapse,
mTimeBetweenTimeLapseFrameCaptureUs, mVideoWidth, mVideoHeight, mFrameRate):
CameraSource::CreateFromCamera(mCamera);
CHECK(cameraSource != NULL);
CHECK(*cameraSource != NULL);
return OK;
}
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
int32_t videoBitRate,
sp<MediaSource> *source) {
source->clear();
sp<MetaData> enc_meta = new MetaData;
enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
enc_meta->setInt32(kKeyBitRate, videoBitRate);
enc_meta->setInt32(kKeySampleRate, mFrameRate);
switch (mVideoEncoder) {
@@ -1087,51 +1120,128 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
return OK;
}
status_t StagefrightRecorder::startMPEG4Recording() {
int32_t totalBitRate = 0;
status_t StagefrightRecorder::setupMPEG4Recording(
bool useSplitCameraSource,
int outputFd, int32_t audioBitRate, int32_t videoBitRate,
int32_t *totalBitRate,
sp<MediaWriter> *mediaWriter) {
mediaWriter->clear();
*totalBitRate = 0;
status_t err = OK;
sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
sp<MediaWriter> writer = new MPEG4Writer(dup(outputFd));
// Add audio source first if it exists
if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_LIST_END)) {
err = setupAudioEncoder(writer);
if (err != OK) return err;
totalBitRate += mAudioBitRate;
*totalBitRate += audioBitRate;
}
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
sp<MediaSource> cameraMediaSource;
if (useSplitCameraSource) {
LOGV("Using Split camera source");
cameraMediaSource = mCameraSourceSplitter->createClient();
} else {
sp<CameraSource> cameraSource;
err = setupCameraSource(&cameraSource);
cameraMediaSource = cameraSource;
}
if (err != OK) {
return err;
}
sp<MediaSource> encoder;
err = setupVideoEncoder(&encoder);
if (err != OK) return err;
err = setupVideoEncoder(cameraMediaSource, videoBitRate, &encoder);
if (err != OK) {
return err;
}
writer->addSource(encoder);
totalBitRate += mVideoBitRate;
*totalBitRate += videoBitRate;
}
if (mInterleaveDurationUs > 0) {
reinterpret_cast<MPEG4Writer *>(writer.get())->
setInterleaveDuration(mInterleaveDurationUs);
}
if (mMaxFileDurationUs != 0) {
writer->setMaxFileDuration(mMaxFileDurationUs);
}
if (mMaxFileSizeBytes != 0) {
writer->setMaxFileSize(mMaxFileSizeBytes);
}
sp<MetaData> meta = new MetaData;
meta->setInt64(kKeyTime, systemTime() / 1000);
meta->setInt32(kKeyFileType, mOutputFormat);
meta->setInt32(kKeyBitRate, totalBitRate);
meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
writer->setListener(mListener);
*mediaWriter = writer;
return OK;
}
void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
sp<MetaData> *meta) {
(*meta)->setInt64(kKeyTime, startTimeUs);
(*meta)->setInt32(kKeyFileType, mOutputFormat);
(*meta)->setInt32(kKeyBitRate, totalBitRate);
(*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
if (mMovieTimeScale > 0) {
meta->setInt32(kKeyTimeScale, mMovieTimeScale);
(*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
}
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
(*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
writer->setListener(mListener);
mWriter = writer;
return mWriter->start(meta.get());
}
status_t StagefrightRecorder::startMPEG4Recording() {
if (mCaptureAuxVideo) {
LOGV("Creating MediaSourceSplitter");
sp<CameraSource> cameraSource;
status_t err = setupCameraSource(&cameraSource);
if (err != OK) {
return err;
}
mCameraSourceSplitter = new MediaSourceSplitter(cameraSource);
} else {
mCameraSourceSplitter = NULL;
}
int32_t totalBitRate;
status_t err = setupMPEG4Recording(mCaptureAuxVideo,
mOutputFd, mAudioBitRate, mVideoBitRate, &totalBitRate, &mWriter);
if (err != OK) {
return err;
}
int64_t startTimeUs = systemTime() / 1000;
sp<MetaData> meta = new MetaData;
setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
err = mWriter->start(meta.get());
if (err != OK) {
return err;
}
if (mCaptureAuxVideo) {
CHECK(mOutputFdAux >= 0);
if (mWriterAux != NULL) {
LOGE("Auxiliary File writer is not avaialble");
return UNKNOWN_ERROR;
}
int32_t totalBitrateAux;
err = setupMPEG4Recording(mCaptureAuxVideo,
mOutputFdAux, mAudioBitRateAux, mVideoBitRateAux, &totalBitrateAux, &mWriterAux);
if (err != OK) {
return err;
}
sp<MetaData> metaAux = new MetaData;
setupMPEG4MetaData(startTimeUs, totalBitrateAux, &metaAux);
return mWriterAux->start(metaAux.get());
}
return OK;
}
status_t StagefrightRecorder::pause() {
@@ -1140,12 +1250,28 @@ status_t StagefrightRecorder::pause() {
return UNKNOWN_ERROR;
}
mWriter->pause();
if (mCaptureAuxVideo) {
if (mWriterAux == NULL) {
return UNKNOWN_ERROR;
}
mWriterAux->pause();
}
return OK;
}
status_t StagefrightRecorder::stop() {
LOGV("stop");
status_t err = OK;
if (mCaptureAuxVideo) {
if (mWriterAux != NULL) {
mWriterAux->stop();
mWriterAux.clear();
}
}
if (mWriter != NULL) {
err = mWriter->stop();
mWriter.clear();
@@ -1169,6 +1295,13 @@ status_t StagefrightRecorder::stop() {
mOutputFd = -1;
}
if (mCaptureAuxVideo) {
if (mOutputFdAux >= 0) {
::close(mOutputFdAux);
mOutputFdAux = -1;
}
}
return err;
}
@@ -1195,9 +1328,11 @@ status_t StagefrightRecorder::reset() {
mVideoHeight = 144;
mFrameRate = 20;
mVideoBitRate = 192000;
mVideoBitRateAux = 20000000;
mSampleRate = 8000;
mAudioChannels = 1;
mAudioBitRate = 12200;
mAudioBitRateAux = 12200;
mInterleaveDurationUs = 0;
mIFramesIntervalSec = 1;
mAudioSourceNode = 0;
@@ -1214,9 +1349,12 @@ status_t StagefrightRecorder::reset() {
mCaptureTimeLapse = false;
mUseStillCameraForTimeLapse = true;
mTimeBetweenTimeLapseFrameCaptureUs = -1;
mCaptureAuxVideo = false;
mCameraSourceSplitter = NULL;
mEncoderProfiles = MediaProfiles::getInstance();
mOutputFd = -1;
mOutputFdAux = -1;
mFlags = 0;
return OK;
@@ -1254,6 +1392,8 @@ status_t StagefrightRecorder::dump(
snprintf(buffer, SIZE, " Recorder: %p\n", this);
snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
result.append(buffer);
snprintf(buffer, SIZE, " Output file Auxiliary (fd %d):\n", mOutputFdAux);
result.append(buffer);
snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
result.append(buffer);
snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
@@ -1274,6 +1414,8 @@ status_t StagefrightRecorder::dump(
result.append(buffer);
snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
result.append(buffer);
snprintf(buffer, SIZE, " Bit rate auxiliary (bps): %d\n", mAudioBitRateAux);
result.append(buffer);
snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
result.append(buffer);
snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
@@ -1302,6 +1444,8 @@ status_t StagefrightRecorder::dump(
result.append(buffer);
snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
result.append(buffer);
snprintf(buffer, SIZE, " Bit rate Auxiliary (bps): %d\n", mVideoBitRateAux);
result.append(buffer);
::write(fd, result.string(), result.size());
return OK;
}

View File

@@ -24,8 +24,11 @@
namespace android {
class Camera;
class CameraSource;
class MediaSourceSplitter;
struct MediaSource;
struct MediaWriter;
class MetaData;
struct AudioSource;
class MediaProfiles;
@@ -45,6 +48,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t setPreviewSurface(const sp<Surface>& surface);
virtual status_t setOutputFile(const char *path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setOutputFileAuxiliary(int fd);
virtual status_t setParameters(const String8& params);
virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
virtual status_t prepare();
@@ -65,7 +69,7 @@ private:
sp<Camera> mCamera;
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter;
sp<MediaWriter> mWriter, mWriterAux;
sp<AudioSource> mAudioSourceNode;
audio_source mAudioSource;
@@ -76,8 +80,8 @@ private:
bool mUse64BitFileOffset;
int32_t mVideoWidth, mVideoHeight;
int32_t mFrameRate;
int32_t mVideoBitRate;
int32_t mAudioBitRate;
int32_t mVideoBitRate, mVideoBitRateAux;
int32_t mAudioBitRate, mAudioBitRateAux;
int32_t mAudioChannels;
int32_t mSampleRate;
int32_t mInterleaveDurationUs;
@@ -95,21 +99,34 @@ private:
bool mCaptureTimeLapse;
bool mUseStillCameraForTimeLapse;
int64_t mTimeBetweenTimeLapseFrameCaptureUs;
bool mCaptureAuxVideo;
sp<MediaSourceSplitter> mCameraSourceSplitter;
String8 mParams;
int mOutputFd;
int mOutputFd, mOutputFdAux;
int32_t mFlags;
MediaProfiles *mEncoderProfiles;
status_t setupMPEG4Recording(
bool useAuxiliaryCameraSource,
int outputFd, int32_t audioBitRate, int32_t videoBitRate,
int32_t *totalBitRate,
sp<MediaWriter> *mediaWriter);
void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
sp<MetaData> *meta);
status_t startMPEG4Recording();
status_t startAMRRecording();
status_t startAACRecording();
status_t startRTPRecording();
sp<MediaSource> createAudioSource();
status_t setupCameraSource();
status_t setupCamera();
status_t setupCameraSource(sp<CameraSource> *cameraSource);
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
status_t setupVideoEncoder(sp<MediaSource> *source);
status_t setupVideoEncoder(
sp<MediaSource> cameraSource,
int32_t videoBitRate,
sp<MediaSource> *source);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);

View File

@@ -10,7 +10,7 @@ LOCAL_SRC_FILES:= \
AudioSource.cpp \
AwesomePlayer.cpp \
CameraSource.cpp \
CameraSourceTimeLapse.cpp \
CameraSourceTimeLapse.cpp \
DataSource.cpp \
ESDS.cpp \
FileSource.cpp \
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \
MediaDefs.cpp \
MediaExtractor.cpp \
MediaSource.cpp \
MediaSourceSplitter.cpp \
MetaData.cpp \
NuCachedSource2.cpp \
NuHTTPDataSource.cpp \