diff options
-rw-r--r-- | include/media/stagefright/CameraSource.h | 50 | ||||
-rw-r--r-- | include/media/stagefright/CameraSourceTimeLapse.h | 129 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 8 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/CameraSource.cpp | 83 | ||||
-rw-r--r-- | media/libstagefright/CameraSourceTimeLapse.cpp | 223 |
6 files changed, 412 insertions, 82 deletions
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index fd30ba5..ed5f09f 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -22,7 +22,6 @@ #include <media/stagefright/MediaSource.h> #include <utils/List.h> #include <utils/RefBase.h> -#include <utils/threads.h> namespace android { @@ -35,10 +34,6 @@ public: static CameraSource *Create(); static CameraSource *CreateFromCamera(const sp<Camera> &camera); - void enableTimeLapseMode( - int64_t timeBetweenTimeLapseFrameCaptureUs, int32_t videoFrameRate); - void disableTimeLapseMode(); - virtual ~CameraSource(); virtual status_t start(MetaData *params = NULL); @@ -51,12 +46,34 @@ public: virtual void signalBufferReturned(MediaBuffer* buffer); -private: - friend class CameraSourceListener; - +protected: sp<Camera> mCamera; sp<MetaData> mMeta; + int64_t mStartTimeUs; + int32_t mNumFramesReceived; + int64_t mLastFrameTimestampUs; + bool mStarted; + + CameraSource(const sp<Camera> &camera); + + virtual void startCameraRecording(); + virtual void stopCameraRecording(); + virtual void releaseRecordingFrame(const sp<IMemory>& frame); + + // Returns true if need to skip the current frame. + // Called from dataCallbackTimestamp. + virtual bool skipCurrentFrame(int64_t timestampUs) {return false;} + + // Callback called when still camera raw data is available. + virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {} + + virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, + const sp<IMemory> &data); + +private: + friend class CameraSourceListener; + Mutex mLock; Condition mFrameAvailableCondition; Condition mFrameCompleteCondition; @@ -64,29 +81,12 @@ private: List<sp<IMemory> > mFramesBeingEncoded; List<int64_t> mFrameTimes; - int64_t mStartTimeUs; int64_t mFirstFrameTimeUs; - int64_t mLastFrameTimestampUs; - int32_t mNumFramesReceived; int32_t mNumFramesEncoded; int32_t mNumFramesDropped; int32_t mNumGlitches; int64_t mGlitchDurationThresholdUs; bool mCollectStats; - bool mStarted; - - // Time between capture of two frames during time lapse recording - // Negative value indicates that timelapse is disabled. - int64_t mTimeBetweenTimeLapseFrameCaptureUs; - // Time between two frames in final video (1/frameRate) - int64_t mTimeBetweenTimeLapseVideoFramesUs; - // Real timestamp of the last encoded time lapse frame - int64_t mLastTimeLapseFrameRealTimestampUs; - - CameraSource(const sp<Camera> &camera); - - void dataCallbackTimestamp( - int64_t timestampUs, int32_t msgType, const sp<IMemory> &data); void releaseQueuedFrames(); void releaseOneRecordingFrame(const sp<IMemory>& frame); diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h new file mode 100644 index 0000000..3c96e56 --- /dev/null +++ b/include/media/stagefright/CameraSourceTimeLapse.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 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 CAMERA_SOURCE_TIME_LAPSE_H_ + +#define CAMERA_SOURCE_TIME_LAPSE_H_ + +#include <pthread.h> + +#include <utils/RefBase.h> +#include <utils/threads.h> + +namespace android { + +class ICamera; +class IMemory; +class ISurface; +class Camera; + +class CameraSourceTimeLapse : public CameraSource { +public: + static CameraSourceTimeLapse *Create(bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate); + + static CameraSourceTimeLapse *CreateFromCamera(const sp<Camera> &camera, + bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate); + + virtual ~CameraSourceTimeLapse(); + +private: + // If true, will use still camera takePicture() for time lapse frames + // If false, will use the videocamera frames instead. + bool mUseStillCameraForTimeLapse; + + // Time between capture of two frames during time lapse recording + // Negative value indicates that timelapse is disabled. + int64_t mTimeBetweenTimeLapseFrameCaptureUs; + + // Time between two frames in final video (1/frameRate) + int64_t mTimeBetweenTimeLapseVideoFramesUs; + + // Real timestamp of the last encoded time lapse frame + int64_t mLastTimeLapseFrameRealTimestampUs; + + // Thread id of thread which takes still picture and sleeps in a loop. + pthread_t mThreadTimeLapse; + + // Variable set in dataCallbackTimestamp() to help skipCurrentFrame() + // to know if current frame needs to be skipped. + bool mSkipCurrentFrame; + + CameraSourceTimeLapse(const sp<Camera> &camera, + bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate); + + // For still camera case starts a thread which calls camera's takePicture() + // in a loop. For video camera case, just starts the camera's video recording. + virtual void startCameraRecording(); + + // For still camera case joins the thread created in startCameraRecording(). + // For video camera case, just stops the camera's video recording. + virtual void stopCameraRecording(); + + // For still camera case don't need to do anything as memory is locally + // allocated with refcounting. + // For video camera case just tell the camera to release the frame. + virtual void releaseRecordingFrame(const sp<IMemory>& frame); + + // mSkipCurrentFrame is set to true in dataCallbackTimestamp() if the current + // frame needs to be skipped and this function just returns the value of mSkipCurrentFrame. + virtual bool skipCurrentFrame(int64_t timestampUs); + + // Handles the callback to handle raw frame data from the still camera. + // Creates a copy of the frame data as the camera can reuse the frame memory + // once this callback returns. The function also sets a new timstamp corresponding + // to one frame time ahead of the last encoded frame's time stamp. It then + // calls dataCallbackTimestamp() of the base class with the copied data and the + // modified timestamp, which will think that it recieved the frame from a video + // camera and proceed as usual. + virtual void dataCallback(int32_t msgType, const sp<IMemory> &data); + + // In the video camera case calls skipFrameAndModifyTimeStamp() to modify + // timestamp and set mSkipCurrentFrame. + // Then it calls the base CameraSource::dataCallbackTimestamp() + virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, + const sp<IMemory> &data); + + // When video camera is used for time lapse capture, returns true + // until enough time has passed for the next time lapse frame. When + // the frame needs to be encoded, it returns false and also modifies + // the time stamp to be one frame time ahead of the last encoded + // frame's time stamp. + bool skipFrameAndModifyTimeStamp(int64_t *timestampUs); + + // Wrapper to enter threadTimeLapseEntry() + static void *ThreadTimeLapseWrapper(void *me); + + // Runs a loop which sleeps until a still picture is required + // and then calls mCamera->takePicture() to take the still picture. + // Used only in the case mUseStillCameraForTimeLapse = true. + void threadTimeLapseEntry(); + + // Creates a copy of source_data into a new memory of final type MemoryBase. + sp<IMemory> createIMemoryCopy(const sp<IMemory> &source_data); + + CameraSourceTimeLapse(const CameraSourceTimeLapse &); + CameraSourceTimeLapse &operator=(const CameraSourceTimeLapse &); +}; + +} // namespace android + +#endif // CAMERA_SOURCE_TIME_LAPSE_H_ diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 24b0e7b..6ac29d8 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -24,6 +24,7 @@ #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/CameraSource.h> +#include <media/stagefright/CameraSourceTimeLapse.h> #include <media/stagefright/MPEG4Writer.h> #include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> @@ -895,11 +896,10 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) { status_t err = setupCameraSource(); if (err != OK) return err; - sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera); + sp<CameraSource> cameraSource = (mCaptureTimeLapse) ? + CameraSourceTimeLapse::CreateFromCamera(mCamera, true, 3E6, mFrameRate): + CameraSource::CreateFromCamera(mCamera); CHECK(cameraSource != NULL); - if(mCaptureTimeLapse) { - cameraSource->enableTimeLapseMode(1E6, mFrameRate); - } sp<MetaData> enc_meta = new MetaData; enc_meta->setInt32(kKeyBitRate, mVideoBitRate); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 89bfc1f..bf5643d 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ AudioSource.cpp \ AwesomePlayer.cpp \ CameraSource.cpp \ + CameraSourceTimeLapse.cpp \ DataSource.cpp \ ESDS.cpp \ FileSource.cpp \ diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index bb53d97..aa0893c 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -65,6 +65,11 @@ void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) { LOGV("postData(%d, ptr:%p, size:%d)", msgType, dataPtr->pointer(), dataPtr->size()); + + sp<CameraSource> source = mSource.promote(); + if (source.get() != NULL) { + source->dataCallback(msgType, dataPtr); + } } void CameraSourceListener::postDataTimestamp( @@ -116,33 +121,17 @@ CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) { return new CameraSource(camera); } -void CameraSource::enableTimeLapseMode( - int64_t timeBetweenTimeLapseFrameCaptureUs, int32_t videoFrameRate) { - LOGV("starting time lapse mode"); - mTimeBetweenTimeLapseFrameCaptureUs = timeBetweenTimeLapseFrameCaptureUs; - mTimeBetweenTimeLapseVideoFramesUs = (1E6/videoFrameRate); -} - -void CameraSource::disableTimeLapseMode() { - LOGV("stopping time lapse mode"); - mTimeBetweenTimeLapseFrameCaptureUs = -1; - mTimeBetweenTimeLapseVideoFramesUs = 0; -} - CameraSource::CameraSource(const sp<Camera> &camera) : mCamera(camera), - mFirstFrameTimeUs(0), - mLastFrameTimestampUs(0), mNumFramesReceived(0), + mLastFrameTimestampUs(0), + mStarted(false), + mFirstFrameTimeUs(0), mNumFramesEncoded(0), mNumFramesDropped(0), mNumGlitches(0), mGlitchDurationThresholdUs(200000), - mCollectStats(false), - mStarted(false), - mTimeBetweenTimeLapseFrameCaptureUs(-1), - mTimeBetweenTimeLapseVideoFramesUs(0), - mLastTimeLapseFrameRealTimestampUs(0) { + mCollectStats(false) { int64_t token = IPCThreadState::self()->clearCallingIdentity(); String8 s = mCamera->getParameters(); @@ -177,7 +166,6 @@ CameraSource::CameraSource(const sp<Camera> &camera) mMeta->setInt32(kKeyHeight, height); mMeta->setInt32(kKeyStride, stride); mMeta->setInt32(kKeySliceHeight, sliceHeight); - } CameraSource::~CameraSource() { @@ -186,6 +174,10 @@ CameraSource::~CameraSource() { } } +void CameraSource::startCameraRecording() { + CHECK_EQ(OK, mCamera->startRecording()); +} + status_t CameraSource::start(MetaData *meta) { CHECK(!mStarted); @@ -203,13 +195,17 @@ status_t CameraSource::start(MetaData *meta) { int64_t token = IPCThreadState::self()->clearCallingIdentity(); mCamera->setListener(new CameraSourceListener(this)); - CHECK_EQ(OK, mCamera->startRecording()); + startCameraRecording(); IPCThreadState::self()->restoreCallingIdentity(token); mStarted = true; return OK; } +void CameraSource::stopCameraRecording() { + mCamera->stopRecording(); +} + status_t CameraSource::stop() { LOGV("stop"); Mutex::Autolock autoLock(mLock); @@ -218,7 +214,7 @@ status_t CameraSource::stop() { int64_t token = IPCThreadState::self()->clearCallingIdentity(); mCamera->setListener(NULL); - mCamera->stopRecording(); + stopCameraRecording(); releaseQueuedFrames(); while (!mFramesBeingEncoded.empty()) { LOGI("Waiting for outstanding frames being encoded: %d", @@ -238,11 +234,15 @@ status_t CameraSource::stop() { return OK; } +void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) { + mCamera->releaseRecordingFrame(frame); +} + void CameraSource::releaseQueuedFrames() { List<sp<IMemory> >::iterator it; while (!mFramesReceived.empty()) { it = mFramesReceived.begin(); - mCamera->releaseRecordingFrame(*it); + releaseRecordingFrame(*it); mFramesReceived.erase(it); ++mNumFramesDropped; } @@ -254,7 +254,7 @@ sp<MetaData> CameraSource::getFormat() { void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) { int64_t token = IPCThreadState::self()->clearCallingIdentity(); - mCamera->releaseRecordingFrame(frame); + releaseRecordingFrame(frame); IPCThreadState::self()->restoreCallingIdentity(token); } @@ -263,7 +263,6 @@ void CameraSource::signalBufferReturned(MediaBuffer *buffer) { for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin(); it != mFramesBeingEncoded.end(); ++it) { if ((*it)->pointer() == buffer->data()) { - releaseOneRecordingFrame((*it)); mFramesBeingEncoded.erase(it); ++mNumFramesEncoded; @@ -332,33 +331,11 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs, ++mNumGlitches; } - // time lapse - if(mTimeBetweenTimeLapseFrameCaptureUs >= 0) { - if(mLastTimeLapseFrameRealTimestampUs == 0) { - // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs - // to current time (timestampUs) and save frame data. - LOGV("dataCallbackTimestamp timelapse: initial frame"); - - mLastTimeLapseFrameRealTimestampUs = timestampUs; - } else if (timestampUs < - (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) { - // Skip all frames from last encoded frame until - // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed. - // Tell the camera to release its recording frame and return. - LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame"); - - releaseOneRecordingFrame(data); - return; - } else { - // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time: - // - Reset mLastTimeLapseFrameRealTimestampUs to current time. - // - Artificially modify timestampUs to be one frame time (1/framerate) ahead - // of the last encoded frame's time stamp. - LOGV("dataCallbackTimestamp timelapse: got timelapse frame"); - - mLastTimeLapseFrameRealTimestampUs = timestampUs; - timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; - } + // May need to skip frame or modify timestamp. Currently implemented + // by the subclass CameraSourceTimeLapse. + if(skipCurrentFrame(timestampUs)) { + releaseOneRecordingFrame(data); + return; } mLastFrameTimestampUs = timestampUs; diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp new file mode 100644 index 0000000..0c7ffa3 --- /dev/null +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2010 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "CameraSourceTimeLapse" + +#include <binder/IPCThreadState.h> +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include <media/stagefright/CameraSource.h> +#include <media/stagefright/CameraSourceTimeLapse.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MetaData.h> +#include <camera/Camera.h> +#include <camera/CameraParameters.h> +#include <utils/String8.h> + +namespace android { + +// static +CameraSourceTimeLapse *CameraSourceTimeLapse::Create(bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate) { + sp<Camera> camera = Camera::connect(0); + + if (camera.get() == NULL) { + return NULL; + } + + return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse, + timeBetweenTimeLapseFrameCaptureUs, videoFrameRate); +} + +// static +CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera, + bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate) { + if (camera.get() == NULL) { + return NULL; + } + + return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse, + timeBetweenTimeLapseFrameCaptureUs, videoFrameRate); +} + +CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera, + bool useStillCameraForTimeLapse, + int64_t timeBetweenTimeLapseFrameCaptureUs, + int32_t videoFrameRate) + : CameraSource(camera), + mUseStillCameraForTimeLapse(useStillCameraForTimeLapse), + mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs), + mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), + mLastTimeLapseFrameRealTimestampUs(0), + mSkipCurrentFrame(false) { + + LOGV("starting time lapse mode"); + if(mUseStillCameraForTimeLapse) { + // Currently hardcoded the picture size. Will need to choose + // automatically or pass in from the app. + int32_t width, height; + width = 1024; + height = 768; + mMeta->setInt32(kKeyWidth, width); + mMeta->setInt32(kKeyHeight, height); + } +} + +CameraSourceTimeLapse::~CameraSourceTimeLapse() { +} + +// static +void *CameraSourceTimeLapse::ThreadTimeLapseWrapper(void *me) { + CameraSourceTimeLapse *source = static_cast<CameraSourceTimeLapse *>(me); + source->threadTimeLapseEntry(); + return NULL; +} + +void CameraSourceTimeLapse::threadTimeLapseEntry() { + while(mStarted) { + LOGV("threadTimeLapseEntry loop"); + sleep(mTimeBetweenTimeLapseFrameCaptureUs/1E6); + CHECK_EQ(OK, mCamera->takePicture()); + } +} + +void CameraSourceTimeLapse::startCameraRecording() { + if(mUseStillCameraForTimeLapse) { + LOGV("start time lapse recording using still camera"); + + int32_t width; + int32_t height; + mMeta->findInt32(kKeyWidth, &width); + mMeta->findInt32(kKeyHeight, &height); + + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + String8 s = mCamera->getParameters(); + IPCThreadState::self()->restoreCallingIdentity(token); + + CameraParameters params(s); + + params.setPictureSize(width, height); + mCamera->setParameters(params.flatten()); + + CHECK_EQ(OK, mCamera->takePicture()); + + // create a thread which takes pictures in a loop + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + pthread_create(&mThreadTimeLapse, &attr, ThreadTimeLapseWrapper, this); + pthread_attr_destroy(&attr); + } else { + LOGV("start time lapse recording using video camera"); + CHECK_EQ(OK, mCamera->startRecording()); + } +} + +void CameraSourceTimeLapse::stopCameraRecording() { + if(mUseStillCameraForTimeLapse) { + void *dummy; + pthread_join(mThreadTimeLapse, &dummy); + } else { + mCamera->stopRecording(); + } +} + +void CameraSourceTimeLapse::releaseRecordingFrame(const sp<IMemory>& frame) { + if(!mUseStillCameraForTimeLapse) { + mCamera->releaseRecordingFrame(frame); + } +} + +sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy(const sp<IMemory> &source_data) { + size_t source_size = source_data->size(); + void* source_pointer = source_data->pointer(); + + sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size); + sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size); + memcpy(newMemory->pointer(), source_pointer, source_size); + return newMemory; +} + +void CameraSourceTimeLapse::dataCallback(int32_t msgType, const sp<IMemory> &data) { + if(msgType != CAMERA_MSG_RAW_IMAGE) { + return; + } + + LOGV("dataCallback for timelapse still frame"); + CHECK_EQ(true, mUseStillCameraForTimeLapse); + + int64_t timestampUs; + if (mNumFramesReceived == 0) { + timestampUs = mStartTimeUs; + } else { + timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; + } + sp<IMemory> dataCopy = createIMemoryCopy(data); + dataCallbackTimestamp(timestampUs, msgType, dataCopy); +} + +bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) { + if(mSkipCurrentFrame) { + mSkipCurrentFrame = false; + return true; + } else { + return false; + } +} + +bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { + if(!mUseStillCameraForTimeLapse) { + if(mLastTimeLapseFrameRealTimestampUs == 0) { + // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs + // to current time (timestampUs) and save frame data. + LOGV("dataCallbackTimestamp timelapse: initial frame"); + + mLastTimeLapseFrameRealTimestampUs = *timestampUs; + } else if (*timestampUs < + (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) { + // Skip all frames from last encoded frame until + // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed. + // Tell the camera to release its recording frame and return. + LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame"); + return true; + } else { + // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time: + // - Reset mLastTimeLapseFrameRealTimestampUs to current time. + // - Artificially modify timestampUs to be one frame time (1/framerate) ahead + // of the last encoded frame's time stamp. + LOGV("dataCallbackTimestamp timelapse: got timelapse frame"); + + mLastTimeLapseFrameRealTimestampUs = *timestampUs; + *timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; + } + } + return false; +} + +void CameraSourceTimeLapse::dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, + const sp<IMemory> &data) { + if(!mUseStillCameraForTimeLapse) { + mSkipCurrentFrame = skipFrameAndModifyTimeStamp(×tampUs); + } + CameraSource::dataCallbackTimestamp(timestampUs, msgType, data); +} + +} // namespace android |