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

Commit 7ca6e73b authored by Chong Zhang's avatar Chong Zhang Committed by Android (Google) Code Review
Browse files

Merge "Change StagefrightRecorder to use MediaCodec"

parents 96f84363 72cecca1
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