Loading include/media/IOMX.h +1 −0 Original line number Diff line number Diff line Loading @@ -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, Loading include/media/mediarecorder.h +1 −1 Original line number Diff line number Diff line Loading @@ -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 }; Loading include/media/stagefright/ACodec.h +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading include/media/stagefright/MediaCodecSource.h 0 → 100644 +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_ */ media/libmediaplayerservice/StagefrightRecorder.cpp +168 −162 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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> Loading Loading @@ -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(); Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -1036,7 +1079,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() { mWriter = writer; return mWriter->start(); return OK; } void StagefrightRecorder::clipVideoFrameRate() { Loading Loading @@ -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; Loading Loading @@ -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: Loading @@ -1408,6 +1414,7 @@ status_t StagefrightRecorder::setupVideoEncoder( break; } if (cameraSource != NULL) { sp<MetaData> meta = cameraSource->getFormat(); int32_t width, height, stride, sliceHeight, colorFormat; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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. Loading @@ -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) { Loading @@ -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); Loading @@ -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); Loading @@ -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) { Loading Loading @@ -1628,6 +1632,8 @@ status_t StagefrightRecorder::stop() { mWriter.clear(); } mGraphicBufferProducer.clear(); if (mOutputFd >= 0) { ::close(mOutputFd); mOutputFd = -1; Loading @@ -1647,7 +1653,6 @@ status_t StagefrightRecorder::stop() { addBatteryData(params); } return err; } Loading Loading @@ -1699,6 +1704,7 @@ status_t StagefrightRecorder::reset() { mRotationDegrees = 0; mLatitudex10000 = -3600000; mLongitudex10000 = -3600000; mTotalBitRate = 0; mOutputFd = -1; Loading Loading
include/media/IOMX.h +1 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
include/media/mediarecorder.h +1 −1 Original line number Diff line number Diff line Loading @@ -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 }; Loading
include/media/stagefright/ACodec.h +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
include/media/stagefright/MediaCodecSource.h 0 → 100644 +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_ */
media/libmediaplayerservice/StagefrightRecorder.cpp +168 −162 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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> Loading Loading @@ -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(); Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -1036,7 +1079,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() { mWriter = writer; return mWriter->start(); return OK; } void StagefrightRecorder::clipVideoFrameRate() { Loading Loading @@ -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; Loading Loading @@ -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: Loading @@ -1408,6 +1414,7 @@ status_t StagefrightRecorder::setupVideoEncoder( break; } if (cameraSource != NULL) { sp<MetaData> meta = cameraSource->getFormat(); int32_t width, height, stride, sliceHeight, colorFormat; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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. Loading @@ -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) { Loading @@ -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); Loading @@ -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); Loading @@ -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) { Loading Loading @@ -1628,6 +1632,8 @@ status_t StagefrightRecorder::stop() { mWriter.clear(); } mGraphicBufferProducer.clear(); if (mOutputFd >= 0) { ::close(mOutputFd); mOutputFd = -1; Loading @@ -1647,7 +1653,6 @@ status_t StagefrightRecorder::stop() { addBatteryData(params); } return err; } Loading Loading @@ -1699,6 +1704,7 @@ status_t StagefrightRecorder::reset() { mRotationDegrees = 0; mLatitudex10000 = -3600000; mLongitudex10000 = -3600000; mTotalBitRate = 0; mOutputFd = -1; Loading