Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "CameraSourceTimeLapse"
     19 
     20 #include <binder/IPCThreadState.h>
     21 #include <binder/MemoryBase.h>
     22 #include <binder/MemoryHeapBase.h>
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/CameraSource.h>
     25 #include <media/stagefright/CameraSourceTimeLapse.h>
     26 #include <media/stagefright/MetaData.h>
     27 #include <camera/Camera.h>
     28 #include <camera/CameraParameters.h>
     29 #include <utils/String8.h>
     30 #include <utils/Vector.h>
     31 
     32 namespace android {
     33 
     34 // static
     35 CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
     36         const sp<ICamera> &camera,
     37         const sp<ICameraRecordingProxy> &proxy,
     38         int32_t cameraId,
     39         const String16& clientName,
     40         uid_t clientUid,
     41         Size videoSize,
     42         int32_t videoFrameRate,
     43         const sp<IGraphicBufferProducer>& surface,
     44         int64_t timeBetweenFrameCaptureUs) {
     45 
     46     CameraSourceTimeLapse *source = new
     47             CameraSourceTimeLapse(camera, proxy, cameraId,
     48                 clientName, clientUid,
     49                 videoSize, videoFrameRate, surface,
     50                 timeBetweenFrameCaptureUs);
     51 
     52     if (source != NULL) {
     53         if (source->initCheck() != OK) {
     54             delete source;
     55             return NULL;
     56         }
     57     }
     58     return source;
     59 }
     60 
     61 CameraSourceTimeLapse::CameraSourceTimeLapse(
     62         const sp<ICamera>& camera,
     63         const sp<ICameraRecordingProxy>& proxy,
     64         int32_t cameraId,
     65         const String16& clientName,
     66         uid_t clientUid,
     67         Size videoSize,
     68         int32_t videoFrameRate,
     69         const sp<IGraphicBufferProducer>& surface,
     70         int64_t timeBetweenFrameCaptureUs)
     71       : CameraSource(camera, proxy, cameraId, clientName, clientUid,
     72                 videoSize, videoFrameRate, surface, true),
     73       mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
     74       mLastTimeLapseFrameRealTimestampUs(0),
     75       mSkipCurrentFrame(false) {
     76 
     77     mTimeBetweenFrameCaptureUs = timeBetweenFrameCaptureUs;
     78     ALOGD("starting time lapse mode: %lld us",
     79         mTimeBetweenFrameCaptureUs);
     80 
     81     mVideoWidth = videoSize.width;
     82     mVideoHeight = videoSize.height;
     83 
     84     if (!trySettingVideoSize(videoSize.width, videoSize.height)) {
     85         mInitCheck = NO_INIT;
     86     }
     87 
     88     // Initialize quick stop variables.
     89     mQuickStop = false;
     90     mForceRead = false;
     91     mLastReadBufferCopy = NULL;
     92     mStopWaitingForIdleCamera = false;
     93 }
     94 
     95 CameraSourceTimeLapse::~CameraSourceTimeLapse() {
     96     if (mLastReadBufferCopy) {
     97         mLastReadBufferCopy->release();
     98         mLastReadBufferCopy = NULL;
     99     }
    100 }
    101 
    102 void CameraSourceTimeLapse::startQuickReadReturns() {
    103     ALOGV("startQuickReadReturns");
    104     Mutex::Autolock autoLock(mQuickStopLock);
    105 
    106     // Enable quick stop mode.
    107     mQuickStop = true;
    108 
    109     // Force dataCallbackTimestamp() coming from the video camera to
    110     // not skip the next frame as we want read() to get a get a frame
    111     // right away.
    112     mForceRead = true;
    113 }
    114 
    115 bool CameraSourceTimeLapse::trySettingVideoSize(
    116         int32_t width, int32_t height) {
    117 
    118     ALOGV("trySettingVideoSize");
    119     int64_t token = IPCThreadState::self()->clearCallingIdentity();
    120     String8 s = mCamera->getParameters();
    121 
    122     CameraParameters params(s);
    123     Vector<Size> supportedSizes;
    124     params.getSupportedVideoSizes(supportedSizes);
    125     bool videoOutputSupported = false;
    126     if (supportedSizes.size() == 0) {
    127         params.getSupportedPreviewSizes(supportedSizes);
    128     } else {
    129         videoOutputSupported = true;
    130     }
    131 
    132     bool videoSizeSupported = false;
    133     for (uint32_t i = 0; i < supportedSizes.size(); ++i) {
    134         int32_t pictureWidth = supportedSizes[i].width;
    135         int32_t pictureHeight = supportedSizes[i].height;
    136 
    137         if ((pictureWidth == width) && (pictureHeight == height)) {
    138             videoSizeSupported = true;
    139         }
    140     }
    141 
    142     bool isSuccessful = false;
    143     if (videoSizeSupported) {
    144         ALOGV("Video size (%d, %d) is supported", width, height);
    145         if (videoOutputSupported) {
    146             params.setVideoSize(width, height);
    147         } else {
    148             params.setPreviewSize(width, height);
    149         }
    150         if (mCamera->setParameters(params.flatten()) == OK) {
    151             isSuccessful = true;
    152         } else {
    153             ALOGE("Failed to set preview size to %dx%d", width, height);
    154             isSuccessful = false;
    155         }
    156     }
    157 
    158     IPCThreadState::self()->restoreCallingIdentity(token);
    159     return isSuccessful;
    160 }
    161 
    162 void CameraSourceTimeLapse::signalBufferReturned(MediaBuffer* buffer) {
    163     ALOGV("signalBufferReturned");
    164     Mutex::Autolock autoLock(mQuickStopLock);
    165     if (mQuickStop && (buffer == mLastReadBufferCopy)) {
    166         buffer->setObserver(NULL);
    167         buffer->release();
    168     } else {
    169         return CameraSource::signalBufferReturned(buffer);
    170     }
    171 }
    172 
    173 void createMediaBufferCopy(
    174         const MediaBuffer& sourceBuffer,
    175         int64_t frameTime,
    176         MediaBuffer **newBuffer) {
    177 
    178     ALOGV("createMediaBufferCopy");
    179     size_t sourceSize = sourceBuffer.size();
    180     void* sourcePointer = sourceBuffer.data();
    181 
    182     (*newBuffer) = new MediaBuffer(sourceSize);
    183     memcpy((*newBuffer)->data(), sourcePointer, sourceSize);
    184 
    185     (*newBuffer)->meta_data()->setInt64(kKeyTime, frameTime);
    186 }
    187 
    188 void CameraSourceTimeLapse::fillLastReadBufferCopy(MediaBuffer& sourceBuffer) {
    189     ALOGV("fillLastReadBufferCopy");
    190     int64_t frameTime;
    191     CHECK(sourceBuffer.meta_data()->findInt64(kKeyTime, &frameTime));
    192     createMediaBufferCopy(sourceBuffer, frameTime, &mLastReadBufferCopy);
    193     mLastReadBufferCopy->add_ref();
    194     mLastReadBufferCopy->setObserver(this);
    195 }
    196 
    197 status_t CameraSourceTimeLapse::read(
    198         MediaBuffer **buffer, const ReadOptions *options) {
    199     ALOGV("read");
    200     if (mLastReadBufferCopy == NULL) {
    201         mLastReadStatus = CameraSource::read(buffer, options);
    202 
    203         // mQuickStop may have turned to true while read was blocked.
    204         // Make a copy of the buffer in that case.
    205         Mutex::Autolock autoLock(mQuickStopLock);
    206         if (mQuickStop && *buffer) {
    207             fillLastReadBufferCopy(**buffer);
    208         }
    209         return mLastReadStatus;
    210     } else {
    211         (*buffer) = mLastReadBufferCopy;
    212         (*buffer)->add_ref();
    213         return mLastReadStatus;
    214     }
    215 }
    216 
    217 sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy(
    218         const sp<IMemory> &source_data) {
    219 
    220     ALOGV("createIMemoryCopy");
    221     size_t source_size = source_data->size();
    222     void* source_pointer = source_data->pointer();
    223 
    224     sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size);
    225     sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size);
    226     memcpy(newMemory->pointer(), source_pointer, source_size);
    227     return newMemory;
    228 }
    229 
    230 bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) {
    231     ALOGV("skipCurrentFrame");
    232     if (mSkipCurrentFrame) {
    233         mSkipCurrentFrame = false;
    234         return true;
    235     } else {
    236         return false;
    237     }
    238 }
    239 
    240 bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) {
    241     ALOGV("skipFrameAndModifyTimeStamp");
    242     if (mLastTimeLapseFrameRealTimestampUs == 0) {
    243         // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs
    244         // to current time (timestampUs) and save frame data.
    245         ALOGV("dataCallbackTimestamp timelapse: initial frame");
    246 
    247         mLastTimeLapseFrameRealTimestampUs = *timestampUs;
    248         return false;
    249     }
    250 
    251     {
    252         Mutex::Autolock autoLock(mQuickStopLock);
    253 
    254         // mForceRead may be set to true by startQuickReadReturns(). In that
    255         // case don't skip this frame.
    256         if (mForceRead) {
    257             ALOGV("dataCallbackTimestamp timelapse: forced read");
    258             mForceRead = false;
    259             *timestampUs =
    260                 mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs;
    261 
    262             // Really make sure that this video recording frame will not be dropped.
    263             if (*timestampUs < mStartTimeUs) {
    264                 ALOGI("set timestampUs to start time stamp %lld us", mStartTimeUs);
    265                 *timestampUs = mStartTimeUs;
    266             }
    267             return false;
    268         }
    269     }
    270 
    271     // Workaround to bypass the first 2 input frames for skipping.
    272     // The first 2 output frames from the encoder are: decoder specific info and
    273     // the compressed video frame data for the first input video frame.
    274     if (mNumFramesEncoded >= 1 && *timestampUs <
    275         (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs)) {
    276         // Skip all frames from last encoded frame until
    277         // sufficient time (mTimeBetweenFrameCaptureUs) has passed.
    278         // Tell the camera to release its recording frame and return.
    279         ALOGV("dataCallbackTimestamp timelapse: skipping intermediate frame");
    280         return true;
    281     } else {
    282         // Desired frame has arrived after mTimeBetweenFrameCaptureUs time:
    283         // - Reset mLastTimeLapseFrameRealTimestampUs to current time.
    284         // - Artificially modify timestampUs to be one frame time (1/framerate) ahead
    285         // of the last encoded frame's time stamp.
    286         ALOGV("dataCallbackTimestamp timelapse: got timelapse frame");
    287 
    288         mLastTimeLapseFrameRealTimestampUs = *timestampUs;
    289         *timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs;
    290         return false;
    291     }
    292     return false;
    293 }
    294 
    295 void CameraSourceTimeLapse::dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
    296             const sp<IMemory> &data) {
    297     ALOGV("dataCallbackTimestamp");
    298     mSkipCurrentFrame = skipFrameAndModifyTimeStamp(&timestampUs);
    299     CameraSource::dataCallbackTimestamp(timestampUs, msgType, data);
    300 }
    301 
    302 }  // namespace android
    303