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 fd30ba58d4e9..ed5f09f8eda8 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 000000000000..3c96e5637245 --- /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 24b0e7b77971..6ac29d80a465 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 89bfc1fd92b9..bf5643d00e86 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 bb53d97b3b4f..aa0893c9637a 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 000000000000..0c7ffa3129de --- /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  |