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

Commit 72cecca1 authored by Chong Zhang's avatar Chong Zhang
Browse files

Change StagefrightRecorder to use MediaCodec

Bug: 12305192
Change-Id: I72d7cb571be5bd348b58ad650f3269d24c15d350
parent 412d4744
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ public:
        INTERNAL_OPTION_SUSPEND,  // data is a bool
        INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
        INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
        INTERNAL_OPTION_START_TIME, // data is an int64_t
    };
    virtual status_t setInternalOption(
            node_id node,
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ typedef void (*media_completion_f)(status_t status, void *cookie);
enum video_source {
    VIDEO_SOURCE_DEFAULT = 0,
    VIDEO_SOURCE_CAMERA = 1,
    VIDEO_SOURCE_GRALLOC_BUFFER = 2,
    VIDEO_SOURCE_SURFACE = 2,

    VIDEO_SOURCE_LIST_END  // must be last - used to validate audio source type
};
+2 −0
Original line number Diff line number Diff line
@@ -207,6 +207,8 @@ private:
    int64_t mRepeatFrameDelayUs;
    int64_t mMaxPtsGapUs;

    bool mCreateInputBuffersSuspended;

    status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
    status_t allocateBuffersOnPort(OMX_U32 portIndex);
    status_t freeBuffersOnPort(OMX_U32 portIndex);
+134 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MediaCodecSource_H_
#define MediaCodecSource_H_

#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/MediaSource.h>

namespace android {

class ALooper;
class AMessage;
class IGraphicBufferProducer;
class MediaCodec;
class MetaData;

struct MediaCodecSource : public MediaSource,
                          public MediaBufferObserver {
    enum FlagBits {
        FLAG_USE_SURFACE_INPUT      = 1,
        FLAG_USE_METADATA_INPUT     = 2,
    };

    static sp<MediaCodecSource> Create(
            const sp<ALooper> &looper,
            const sp<AMessage> &format,
            const sp<MediaSource> &source,
            uint32_t flags = 0);

    bool isVideo() const { return mIsVideo; }
    sp<IGraphicBufferProducer> getGraphicBufferProducer();

    // MediaSource
    virtual status_t start(MetaData *params = NULL);
    virtual status_t stop();
    virtual status_t pause();
    virtual sp<MetaData> getFormat() { return mMeta; }
    virtual status_t read(
            MediaBuffer **buffer,
            const ReadOptions *options = NULL);

    // MediaBufferObserver
    virtual void signalBufferReturned(MediaBuffer *buffer);

    // for AHandlerReflector
    void onMessageReceived(const sp<AMessage> &msg);

protected:
    virtual ~MediaCodecSource();

private:
    struct Puller;

    enum {
        kWhatPullerNotify,
        kWhatEncoderActivity,
        kWhatStart,
        kWhatStop,
        kWhatPause,
    };

    MediaCodecSource(
            const sp<ALooper> &looper,
            const sp<AMessage> &outputFormat,
            const sp<MediaSource> &source,
            uint32_t flags = 0);

    status_t onStart(MetaData *params);
    status_t init();
    status_t initEncoder();
    void releaseEncoder();
    status_t feedEncoderInputBuffers();
    void scheduleDoMoreWork();
    status_t doMoreWork();
    void suspend();
    void resume(int64_t skipFramesBeforeUs = -1ll);
    void signalEOS(status_t err = ERROR_END_OF_STREAM);
    bool reachedEOS();
    status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);

    sp<ALooper> mLooper;
    sp<ALooper> mCodecLooper;
    sp<AHandlerReflector<MediaCodecSource> > mReflector;
    sp<AMessage> mOutputFormat;
    sp<MetaData> mMeta;
    sp<Puller> mPuller;
    sp<MediaCodec> mEncoder;
    uint32_t mFlags;
    List<uint32_t> mStopReplyIDQueue;
    bool mIsVideo;
    bool mStarted;
    bool mStopping;
    bool mDoMoreWorkPending;
    bool mPullerReachedEOS;
    sp<AMessage> mEncoderActivityNotify;
    sp<IGraphicBufferProducer> mGraphicBufferProducer;
    Vector<sp<ABuffer> > mEncoderInputBuffers;
    Vector<sp<ABuffer> > mEncoderOutputBuffers;
    List<MediaBuffer *> mInputBufferQueue;
    List<size_t> mAvailEncoderInputIndices;
    List<int64_t> mDecodingTimeQueue; // decoding time (us) for video

    // audio drift time
    int64_t mFirstSampleTimeUs;
    List<int64_t> mDriftTimeQueue;

    // following variables are protected by mOutputBufferLock
    Mutex mOutputBufferLock;
    Condition mOutputBufferCond;
    List<MediaBuffer*> mOutputBufferQueue;
    bool mEncodedReachedEOS;
    status_t mErrorCode;

    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource);
};

} // namespace android

#endif /* MediaCodecSource_H_ */
+168 −162
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@
#include <binder/IServiceManager.h>

#include <media/IMediaPlayerService.h>
#include <media/openmax/OMX_Audio.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
@@ -35,13 +37,12 @@
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/SurfaceMediaSource.h>
#include <media/MediaProfiles.h>
#include <camera/ICamera.h>
#include <camera/CameraParameters.h>
#include <gui/Surface.h>

#include <utils/Errors.h>
#include <sys/types.h>
@@ -71,8 +72,7 @@ StagefrightRecorder::StagefrightRecorder()
      mAudioSource(AUDIO_SOURCE_CNT),
      mVideoSource(VIDEO_SOURCE_LIST_END),
      mCaptureTimeLapse(false),
      mStarted(false),
      mSurfaceMediaSource(NULL) {
      mStarted(false) {

    ALOGV("Constructor");
    reset();
@@ -81,10 +81,19 @@ StagefrightRecorder::StagefrightRecorder()
StagefrightRecorder::~StagefrightRecorder() {
    ALOGV("Destructor");
    stop();

    if (mLooper != NULL) {
        mLooper->stop();
    }
}

status_t StagefrightRecorder::init() {
    ALOGV("init");

    mLooper = new ALooper;
    mLooper->setName("recorder_looper");
    mLooper->start();

    return OK;
}

@@ -93,7 +102,7 @@ status_t StagefrightRecorder::init() {
// while encoding GL Frames
sp<IGraphicBufferProducer> StagefrightRecorder::querySurfaceMediaSource() const {
    ALOGV("Get SurfaceMediaSource");
    return mSurfaceMediaSource->getBufferQueue();
    return mGraphicBufferProducer;
}

status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
@@ -739,18 +748,14 @@ status_t StagefrightRecorder::setClientName(const String16& clientName) {
}

status_t StagefrightRecorder::prepare() {
    return OK;
    ALOGV("prepare");
    if (mOutputFd < 0) {
        ALOGE("Output file descriptor is invalid");
        return INVALID_OPERATION;
    }

status_t StagefrightRecorder::start() {
    CHECK_GE(mOutputFd, 0);

    // Get UID here for permission checking
    mClientUid = IPCThreadState::self()->getCallingUid();
    if (mWriter != NULL) {
        ALOGE("File writer is not avaialble");
        return UNKNOWN_ERROR;
    }

    status_t status = OK;

@@ -758,32 +763,86 @@ status_t StagefrightRecorder::start() {
        case OUTPUT_FORMAT_DEFAULT:
        case OUTPUT_FORMAT_THREE_GPP:
        case OUTPUT_FORMAT_MPEG_4:
            status = startMPEG4Recording();
            status = setupMPEG4Recording();
            break;

        case OUTPUT_FORMAT_AMR_NB:
        case OUTPUT_FORMAT_AMR_WB:
            status = startAMRRecording();
            status = setupAMRRecording();
            break;

        case OUTPUT_FORMAT_AAC_ADIF:
        case OUTPUT_FORMAT_AAC_ADTS:
            status = startAACRecording();
            status = setupAACRecording();
            break;

        case OUTPUT_FORMAT_RTP_AVP:
            status = startRTPRecording();
            status = setupRTPRecording();
            break;

        case OUTPUT_FORMAT_MPEG2TS:
            status = setupMPEG2TSRecording();
            break;

        default:
            ALOGE("Unsupported output file format: %d", mOutputFormat);
            status = UNKNOWN_ERROR;
            break;
    }

    return status;
}

status_t StagefrightRecorder::start() {
    ALOGV("start");
    if (mOutputFd < 0) {
        ALOGE("Output file descriptor is invalid");
        return INVALID_OPERATION;
    }

    // Get UID here for permission checking
    mClientUid = IPCThreadState::self()->getCallingUid();
    if (mWriter == NULL) {
        ALOGE("File writer is not avaialble");
        return UNKNOWN_ERROR;
    }

    status_t status = OK;

    switch (mOutputFormat) {
        case OUTPUT_FORMAT_DEFAULT:
        case OUTPUT_FORMAT_THREE_GPP:
        case OUTPUT_FORMAT_MPEG_4:
        {
            sp<MetaData> meta = new MetaData;
            setupMPEG4MetaData(&meta);
            status = mWriter->start(meta.get());
            break;
        }

        case OUTPUT_FORMAT_AMR_NB:
        case OUTPUT_FORMAT_AMR_WB:
        case OUTPUT_FORMAT_AAC_ADIF:
        case OUTPUT_FORMAT_AAC_ADTS:
        case OUTPUT_FORMAT_RTP_AVP:
        case OUTPUT_FORMAT_MPEG2TS:
            status = startMPEG2TSRecording();
        {
            status = mWriter->start();
            break;
        }

        default:
        {
            ALOGE("Unsupported output file format: %d", mOutputFormat);
            status = UNKNOWN_ERROR;
            break;
        }
    }

    if (status != OK) {
        mWriter.clear();
        mWriter = NULL;
    }

    if ((status == OK) && (!mStarted)) {
        mStarted = true;
@@ -816,58 +875,54 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
        return NULL;
    }

    sp<MetaData> encMeta = new MetaData;
    sp<AMessage> format = new AMessage;
    const char *mime;
    switch (mAudioEncoder) {
        case AUDIO_ENCODER_AMR_NB:
        case AUDIO_ENCODER_DEFAULT:
            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
            break;
        case AUDIO_ENCODER_AMR_WB:
            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB);
            break;
        case AUDIO_ENCODER_AAC:
            mime = MEDIA_MIMETYPE_AUDIO_AAC;
            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC);
            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
            format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
            break;
        case AUDIO_ENCODER_HE_AAC:
            mime = MEDIA_MIMETYPE_AUDIO_AAC;
            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE);
            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
            format->setInt32("aac-profile", OMX_AUDIO_AACObjectHE);
            break;
        case AUDIO_ENCODER_AAC_ELD:
            mime = MEDIA_MIMETYPE_AUDIO_AAC;
            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
            format->setInt32("aac-profile", OMX_AUDIO_AACObjectELD);
            break;

        default:
            ALOGE("Unknown audio encoder: %d", mAudioEncoder);
            return NULL;
    }
    encMeta->setCString(kKeyMIMEType, mime);

    int32_t maxInputSize;
    CHECK(audioSource->getFormat()->findInt32(
                kKeyMaxInputSize, &maxInputSize));

    encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
    encMeta->setInt32(kKeySampleRate, mSampleRate);
    encMeta->setInt32(kKeyBitRate, mAudioBitRate);
    format->setInt32("max-input-size", maxInputSize);
    format->setInt32("channel-count", mAudioChannels);
    format->setInt32("sample-rate", mSampleRate);
    format->setInt32("bitrate", mAudioBitRate);
    if (mAudioTimeScale > 0) {
        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
        format->setInt32("time-scale", mAudioTimeScale);
    }

    OMXClient client;
    CHECK_EQ(client.connect(), (status_t)OK);
    sp<MediaSource> audioEncoder =
        OMXCodec::Create(client.interface(), encMeta,
                         true /* createEncoder */, audioSource);
            MediaCodecSource::Create(mLooper, format, audioSource);
    mAudioSourceNode = audioSource;

    return audioEncoder;
}

status_t StagefrightRecorder::startAACRecording() {
status_t StagefrightRecorder::setupAACRecording() {
    // FIXME:
    // Add support for OUTPUT_FORMAT_AAC_ADIF
    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
@@ -878,16 +933,10 @@ status_t StagefrightRecorder::startAACRecording() {
    CHECK(mAudioSource != AUDIO_SOURCE_CNT);

    mWriter = new AACWriter(mOutputFd);
    status_t status = startRawAudioRecording();
    if (status != OK) {
        mWriter.clear();
        mWriter = NULL;
    return setupRawAudioRecording();
}

    return status;
}

status_t StagefrightRecorder::startAMRRecording() {
status_t StagefrightRecorder::setupAMRRecording() {
    CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
          mOutputFormat == OUTPUT_FORMAT_AMR_WB);

@@ -907,15 +956,10 @@ status_t StagefrightRecorder::startAMRRecording() {
    }

    mWriter = new AMRWriter(mOutputFd);
    status_t status = startRawAudioRecording();
    if (status != OK) {
        mWriter.clear();
        mWriter = NULL;
    }
    return status;
    return setupRawAudioRecording();
}

status_t StagefrightRecorder::startRawAudioRecording() {
status_t StagefrightRecorder::setupRawAudioRecording() {
    if (mAudioSource >= AUDIO_SOURCE_CNT) {
        ALOGE("Invalid audio source: %d", mAudioSource);
        return BAD_VALUE;
@@ -941,12 +985,11 @@ status_t StagefrightRecorder::startRawAudioRecording() {
        mWriter->setMaxFileSize(mMaxFileSizeBytes);
    }
    mWriter->setListener(mListener);
    mWriter->start();

    return OK;
}

status_t StagefrightRecorder::startRTPRecording() {
status_t StagefrightRecorder::setupRTPRecording() {
    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);

    if ((mAudioSource != AUDIO_SOURCE_CNT
@@ -983,10 +1026,10 @@ status_t StagefrightRecorder::startRTPRecording() {
    mWriter->addSource(source);
    mWriter->setListener(mListener);

    return mWriter->start();
    return OK;
}

status_t StagefrightRecorder::startMPEG2TSRecording() {
status_t StagefrightRecorder::setupMPEG2TSRecording() {
    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);

    sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
@@ -1036,7 +1079,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() {

    mWriter = writer;

    return mWriter->start();
    return OK;
}

void StagefrightRecorder::clipVideoFrameRate() {
@@ -1277,49 +1320,14 @@ status_t StagefrightRecorder::setupMediaSource(
            return err;
        }
        *mediaSource = cameraSource;
    } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
        // If using GRAlloc buffers, setup surfacemediasource.
        // Later a handle to that will be passed
        // to the client side when queried
        status_t err = setupSurfaceMediaSource();
        if (err != OK) {
            return err;
        }
        *mediaSource = mSurfaceMediaSource;
    } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
        *mediaSource = NULL;
    } else {
        return INVALID_OPERATION;
    }
    return OK;
}

// setupSurfaceMediaSource creates a source with the given
// width and height and framerate.
// TODO: This could go in a static function inside SurfaceMediaSource
// similar to that in CameraSource
status_t StagefrightRecorder::setupSurfaceMediaSource() {
    status_t err = OK;
    mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight);
    if (mSurfaceMediaSource == NULL) {
        return NO_INIT;
    }

    if (mFrameRate == -1) {
        int32_t frameRate = 0;
        CHECK (mSurfaceMediaSource->getFormat()->findInt32(
                                        kKeyFrameRate, &frameRate));
        ALOGI("Frame rate is not explicitly set. Use the current frame "
             "rate (%d fps)", frameRate);
        mFrameRate = frameRate;
    } else {
        err = mSurfaceMediaSource->setFrameRate(mFrameRate);
    }
    CHECK(mFrameRate != -1);

    mIsMetaDataStoredInVideoBuffers =
        mSurfaceMediaSource->isMetaDataStoredInVideoBuffers();
    return err;
}

status_t StagefrightRecorder::setupCameraSource(
        sp<CameraSource> *cameraSource) {
    status_t err = OK;
@@ -1386,21 +1394,19 @@ status_t StagefrightRecorder::setupVideoEncoder(
        sp<MediaSource> *source) {
    source->clear();

    sp<MetaData> enc_meta = new MetaData;
    enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
    enc_meta->setInt32(kKeyFrameRate, mFrameRate);
    sp<AMessage> format = new AMessage();

    switch (mVideoEncoder) {
        case VIDEO_ENCODER_H263:
            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
            format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
            break;

        case VIDEO_ENCODER_MPEG_4_SP:
            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
            format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
            break;

        case VIDEO_ENCODER_H264:
            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
            format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
            break;

        default:
@@ -1408,6 +1414,7 @@ status_t StagefrightRecorder::setupVideoEncoder(
            break;
    }

    if (cameraSource != NULL) {
        sp<MetaData> meta = cameraSource->getFormat();

        int32_t width, height, stride, sliceHeight, colorFormat;
@@ -1417,50 +1424,59 @@ status_t StagefrightRecorder::setupVideoEncoder(
        CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
        CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));

    enc_meta->setInt32(kKeyWidth, width);
    enc_meta->setInt32(kKeyHeight, height);
    enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
    enc_meta->setInt32(kKeyStride, stride);
    enc_meta->setInt32(kKeySliceHeight, sliceHeight);
    enc_meta->setInt32(kKeyColorFormat, colorFormat);
        format->setInt32("width", width);
        format->setInt32("height", height);
        format->setInt32("stride", stride);
        format->setInt32("slice-height", sliceHeight);
        format->setInt32("color-format", colorFormat);
    } else {
        format->setInt32("width", mVideoWidth);
        format->setInt32("height", mVideoHeight);
        format->setInt32("stride", mVideoWidth);
        format->setInt32("slice-height", mVideoWidth);
        format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
    }

    format->setInt32("bitrate", mVideoBitRate);
    format->setInt32("frame-rate", mFrameRate);
    format->setInt32("i-frame-interval", mIFramesIntervalSec);

    if (mVideoTimeScale > 0) {
        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
        format->setInt32("time-scale", mVideoTimeScale);
    }
    if (mVideoEncoderProfile != -1) {
        enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
        format->setInt32("profile", mVideoEncoderProfile);
    }
    if (mVideoEncoderLevel != -1) {
        enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
        format->setInt32("level", mVideoEncoderLevel);
    }

    OMXClient client;
    CHECK_EQ(client.connect(), (status_t)OK);

    uint32_t encoder_flags = 0;
    uint32_t flags = 0;
    if (mIsMetaDataStoredInVideoBuffers) {
        encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
        flags |= MediaCodecSource::FLAG_USE_METADATA_INPUT;
    }

    // Do not wait for all the input buffers to become available.
    // This give timelapse video recording faster response in
    // receiving output from video encoder component.
    if (mCaptureTimeLapse) {
        encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
    if (cameraSource == NULL) {
        flags |= MediaCodecSource::FLAG_USE_SURFACE_INPUT;
    }

    sp<MediaSource> encoder = OMXCodec::Create(
            client.interface(), enc_meta,
            true /* createEncoder */, cameraSource,
            NULL, encoder_flags);
    sp<MediaCodecSource> encoder =
            MediaCodecSource::Create(mLooper, format, cameraSource, flags);
    if (encoder == NULL) {
        ALOGW("Failed to create the encoder");
        // When the encoder fails to be created, we need
        // release the camera source due to the camera's lock
        // and unlock mechanism.
        if (cameraSource != NULL) {
            cameraSource->stop();
        }
        return UNKNOWN_ERROR;
    }

    if (cameraSource == NULL) {
        mGraphicBufferProducer = encoder->getGraphicBufferProducer();
    }

    *source = encoder;

    return OK;
@@ -1494,9 +1510,10 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
    return OK;
}

status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) {
status_t StagefrightRecorder::setupMPEG4Recording() {
    mWriter.clear();
    *totalBitRate = 0;
    mTotalBitRate = 0;

    status_t err = OK;
    sp<MediaWriter> writer = new MPEG4Writer(mOutputFd);

@@ -1515,7 +1532,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) {
        }

        writer->addSource(encoder);
        *totalBitRate += mVideoBitRate;
        mTotalBitRate += mVideoBitRate;
    }

    // Audio source is added at the end if it exists.
@@ -1524,7 +1541,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) {
    if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
        err = setupAudioEncoder(writer);
        if (err != OK) return err;
        *totalBitRate += mAudioBitRate;
        mTotalBitRate += mAudioBitRate;
    }

    if (mInterleaveDurationUs > 0) {
@@ -1542,7 +1559,13 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) {
        writer->setMaxFileSize(mMaxFileSizeBytes);
    }

    if (mVideoSource == VIDEO_SOURCE_DEFAULT
            || mVideoSource == VIDEO_SOURCE_CAMERA) {
        mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
    } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
        // surface source doesn't need large initial delay
        mStartTimeOffsetMs = 200;
    }
    if (mStartTimeOffsetMs > 0) {
        reinterpret_cast<MPEG4Writer *>(writer.get())->
            setStartTimeOffsetMs(mStartTimeOffsetMs);
@@ -1553,11 +1576,11 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) {
    return OK;
}

void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
        sp<MetaData> *meta) {
void StagefrightRecorder::setupMPEG4MetaData(sp<MetaData> *meta) {
    int64_t startTimeUs = systemTime() / 1000;
    (*meta)->setInt64(kKeyTime, startTimeUs);
    (*meta)->setInt32(kKeyFileType, mOutputFormat);
    (*meta)->setInt32(kKeyBitRate, totalBitRate);
    (*meta)->setInt32(kKeyBitRate, mTotalBitRate);
    (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
    if (mMovieTimeScale > 0) {
        (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
@@ -1570,25 +1593,6 @@ void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalB
    }
}

status_t StagefrightRecorder::startMPEG4Recording() {
    int32_t totalBitRate;
    status_t err = setupMPEG4Recording(&totalBitRate);
    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;
    }

    return OK;
}

status_t StagefrightRecorder::pause() {
    ALOGV("pause");
    if (mWriter == NULL) {
@@ -1628,6 +1632,8 @@ status_t StagefrightRecorder::stop() {
        mWriter.clear();
    }

    mGraphicBufferProducer.clear();

    if (mOutputFd >= 0) {
        ::close(mOutputFd);
        mOutputFd = -1;
@@ -1647,7 +1653,6 @@ status_t StagefrightRecorder::stop() {
        addBatteryData(params);
    }


    return err;
}

@@ -1699,6 +1704,7 @@ status_t StagefrightRecorder::reset() {
    mRotationDegrees = 0;
    mLatitudex10000 = -3600000;
    mLongitudex10000 = -3600000;
    mTotalBitRate = 0;

    mOutputFd = -1;

Loading