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