Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7e7a3f9 authored by Nipun Kwatra's avatar Nipun Kwatra
Browse files

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
parent 6b2a7575
Loading
Loading
Loading
Loading
+173 −29
Original line number Diff line number Diff line
@@ -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;
}
+23 −6
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \
        MediaDefs.cpp                     \
        MediaExtractor.cpp                \
        MediaSource.cpp                   \
        MediaSourceSplitter.cpp           \
        MetaData.cpp                      \
        NuCachedSource2.cpp               \
        NuHTTPDataSource.cpp              \