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