CameraSourceTimeLapse.cpp revision 155e833a7a5fc3e193691324cf9326da1bc3289a
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 <media/stagefright/YUVImage.h> 28#include <media/stagefright/YUVCanvas.h> 29#include <camera/Camera.h> 30#include <camera/CameraParameters.h> 31#include <ui/Rect.h> 32#include <utils/String8.h> 33#include <utils/Vector.h> 34#include "OMX_Video.h" 35#include <limits.h> 36 37namespace android { 38 39// static 40CameraSourceTimeLapse *CameraSourceTimeLapse::Create( 41 int64_t timeBetweenTimeLapseFrameCaptureUs, 42 int32_t width, int32_t height, 43 int32_t videoFrameRate) { 44 sp<Camera> camera = Camera::connect(0); 45 46 if (camera.get() == NULL) { 47 return NULL; 48 } 49 50 return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs, 51 width, height, videoFrameRate); 52} 53 54// static 55CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera, 56 int64_t timeBetweenTimeLapseFrameCaptureUs, 57 int32_t width, int32_t height, 58 int32_t videoFrameRate) { 59 if (camera.get() == NULL) { 60 return NULL; 61 } 62 63 return new CameraSourceTimeLapse(camera, timeBetweenTimeLapseFrameCaptureUs, 64 width, height, videoFrameRate); 65} 66 67CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera, 68 int64_t timeBetweenTimeLapseFrameCaptureUs, 69 int32_t width, int32_t height, 70 int32_t videoFrameRate) 71 : CameraSource(camera), 72 mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs), 73 mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), 74 mLastTimeLapseFrameRealTimestampUs(0), 75 mSkipCurrentFrame(false) { 76 77 LOGV("starting time lapse mode"); 78 mVideoWidth = width; 79 mVideoHeight = height; 80 81 if (trySettingPreviewSize(width, height)) { 82 mUseStillCameraForTimeLapse = false; 83 } else { 84 // TODO: Add a check to see that mTimeBetweenTimeLapseFrameCaptureUs is greater 85 // than the fastest rate at which the still camera can take pictures. 86 mUseStillCameraForTimeLapse = true; 87 CHECK(setPictureSizeToClosestSupported(width, height)); 88 mNeedCropping = computeCropRectangleOffset(); 89 mMeta->setInt32(kKeyWidth, width); 90 mMeta->setInt32(kKeyHeight, height); 91 } 92} 93 94CameraSourceTimeLapse::~CameraSourceTimeLapse() { 95} 96 97bool CameraSourceTimeLapse::trySettingPreviewSize(int32_t width, int32_t height) { 98 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 99 String8 s = mCamera->getParameters(); 100 IPCThreadState::self()->restoreCallingIdentity(token); 101 102 CameraParameters params(s); 103 Vector<Size> supportedSizes; 104 params.getSupportedPreviewSizes(supportedSizes); 105 106 bool previewSizeSupported = false; 107 for (uint32_t i = 0; i < supportedSizes.size(); ++i) { 108 int32_t pictureWidth = supportedSizes[i].width; 109 int32_t pictureHeight = supportedSizes[i].height; 110 111 if ((pictureWidth == width) && (pictureHeight == height)) { 112 previewSizeSupported = true; 113 } 114 } 115 116 if (previewSizeSupported) { 117 LOGV("Video size (%d, %d) is a supported preview size", width, height); 118 params.setPreviewSize(width, height); 119 CHECK(mCamera->setParameters(params.flatten())); 120 return true; 121 } 122 123 return false; 124} 125 126bool CameraSourceTimeLapse::setPictureSizeToClosestSupported(int32_t width, int32_t height) { 127 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 128 String8 s = mCamera->getParameters(); 129 IPCThreadState::self()->restoreCallingIdentity(token); 130 131 CameraParameters params(s); 132 Vector<Size> supportedSizes; 133 params.getSupportedPictureSizes(supportedSizes); 134 135 int32_t minPictureSize = INT_MAX; 136 for (uint32_t i = 0; i < supportedSizes.size(); ++i) { 137 int32_t pictureWidth = supportedSizes[i].width; 138 int32_t pictureHeight = supportedSizes[i].height; 139 140 if ((pictureWidth >= width) && (pictureHeight >= height)) { 141 int32_t pictureSize = pictureWidth*pictureHeight; 142 if (pictureSize < minPictureSize) { 143 minPictureSize = pictureSize; 144 mPictureWidth = pictureWidth; 145 mPictureHeight = pictureHeight; 146 } 147 } 148 } 149 LOGV("Picture size = (%d, %d)", mPictureWidth, mPictureHeight); 150 return (minPictureSize != INT_MAX); 151} 152 153bool CameraSourceTimeLapse::computeCropRectangleOffset() { 154 if ((mPictureWidth == mVideoWidth) && (mPictureHeight == mVideoHeight)) { 155 return false; 156 } 157 158 CHECK((mPictureWidth > mVideoWidth) && (mPictureHeight > mVideoHeight)); 159 160 int32_t widthDifference = mPictureWidth - mVideoWidth; 161 int32_t heightDifference = mPictureHeight - mVideoHeight; 162 163 mCropRectStartX = widthDifference/2; 164 mCropRectStartY = heightDifference/2; 165 166 LOGV("setting crop rectangle offset to (%d, %d)", mCropRectStartX, mCropRectStartY); 167 168 return true; 169} 170 171// static 172void *CameraSourceTimeLapse::ThreadTimeLapseWrapper(void *me) { 173 CameraSourceTimeLapse *source = static_cast<CameraSourceTimeLapse *>(me); 174 source->threadTimeLapseEntry(); 175 return NULL; 176} 177 178void CameraSourceTimeLapse::threadTimeLapseEntry() { 179 while(mStarted) { 180 if (mCameraIdle) { 181 LOGV("threadTimeLapseEntry: taking picture"); 182 CHECK_EQ(OK, mCamera->takePicture()); 183 mCameraIdle = false; 184 usleep(mTimeBetweenTimeLapseFrameCaptureUs); 185 } else { 186 LOGV("threadTimeLapseEntry: camera busy with old takePicture. Sleeping a little."); 187 usleep(1E4); 188 } 189 } 190} 191 192void CameraSourceTimeLapse::startCameraRecording() { 193 if (mUseStillCameraForTimeLapse) { 194 LOGV("start time lapse recording using still camera"); 195 196 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 197 String8 s = mCamera->getParameters(); 198 IPCThreadState::self()->restoreCallingIdentity(token); 199 200 CameraParameters params(s); 201 params.setPictureSize(mPictureWidth, mPictureHeight); 202 mCamera->setParameters(params.flatten()); 203 mCameraIdle = true; 204 205 // create a thread which takes pictures in a loop 206 pthread_attr_t attr; 207 pthread_attr_init(&attr); 208 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 209 210 pthread_create(&mThreadTimeLapse, &attr, ThreadTimeLapseWrapper, this); 211 pthread_attr_destroy(&attr); 212 } else { 213 LOGV("start time lapse recording using video camera"); 214 CHECK_EQ(OK, mCamera->startRecording()); 215 } 216} 217 218void CameraSourceTimeLapse::stopCameraRecording() { 219 if (mUseStillCameraForTimeLapse) { 220 void *dummy; 221 pthread_join(mThreadTimeLapse, &dummy); 222 CHECK_EQ(OK, mCamera->startPreview()); 223 } else { 224 mCamera->stopRecording(); 225 } 226} 227 228void CameraSourceTimeLapse::releaseRecordingFrame(const sp<IMemory>& frame) { 229 if (!mUseStillCameraForTimeLapse) { 230 mCamera->releaseRecordingFrame(frame); 231 } 232} 233 234sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy(const sp<IMemory> &source_data) { 235 size_t source_size = source_data->size(); 236 void* source_pointer = source_data->pointer(); 237 238 sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size); 239 sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size); 240 memcpy(newMemory->pointer(), source_pointer, source_size); 241 return newMemory; 242} 243 244// Allocates IMemory of final type MemoryBase with the given size. 245sp<IMemory> allocateIMemory(size_t size) { 246 sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(size); 247 sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, size); 248 return newMemory; 249} 250 251// static 252void *CameraSourceTimeLapse::ThreadStartPreviewWrapper(void *me) { 253 CameraSourceTimeLapse *source = static_cast<CameraSourceTimeLapse *>(me); 254 source->threadStartPreview(); 255 return NULL; 256} 257 258void CameraSourceTimeLapse::threadStartPreview() { 259 CHECK_EQ(OK, mCamera->startPreview()); 260 mCameraIdle = true; 261} 262 263void CameraSourceTimeLapse::restartPreview() { 264 // Start this in a different thread, so that the dataCallback can return 265 LOGV("restartPreview"); 266 pthread_attr_t attr; 267 pthread_attr_init(&attr); 268 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 269 270 pthread_t threadPreview; 271 pthread_create(&threadPreview, &attr, ThreadStartPreviewWrapper, this); 272 pthread_attr_destroy(&attr); 273} 274 275sp<IMemory> CameraSourceTimeLapse::cropYUVImage(const sp<IMemory> &source_data) { 276 // find the YUV format 277 int32_t srcFormat; 278 CHECK(mMeta->findInt32(kKeyColorFormat, &srcFormat)); 279 YUVImage::YUVFormat yuvFormat; 280 if (srcFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 281 yuvFormat = YUVImage::YUV420SemiPlanar; 282 } else if (srcFormat == OMX_COLOR_FormatYUV420Planar) { 283 yuvFormat = YUVImage::YUV420Planar; 284 } 285 286 // allocate memory for cropped image and setup a canvas using it. 287 sp<IMemory> croppedImageMemory = allocateIMemory( 288 YUVImage::bufferSize(yuvFormat, mVideoWidth, mVideoHeight)); 289 YUVImage yuvImageCropped(yuvFormat, 290 mVideoWidth, mVideoHeight, 291 (uint8_t *)croppedImageMemory->pointer()); 292 YUVCanvas yuvCanvasCrop(yuvImageCropped); 293 294 YUVImage yuvImageSource(yuvFormat, 295 mPictureWidth, mPictureHeight, 296 (uint8_t *)source_data->pointer()); 297 yuvCanvasCrop.CopyImageRect( 298 Rect(mCropRectStartX, mCropRectStartY, 299 mCropRectStartX + mVideoWidth, 300 mCropRectStartY + mVideoHeight), 301 0, 0, 302 yuvImageSource); 303 304 return croppedImageMemory; 305} 306 307void CameraSourceTimeLapse::dataCallback(int32_t msgType, const sp<IMemory> &data) { 308 if (msgType == CAMERA_MSG_COMPRESSED_IMAGE) { 309 // takePicture will complete after this callback, so restart preview. 310 restartPreview(); 311 return; 312 } 313 if (msgType != CAMERA_MSG_RAW_IMAGE) { 314 return; 315 } 316 317 LOGV("dataCallback for timelapse still frame"); 318 CHECK_EQ(true, mUseStillCameraForTimeLapse); 319 320 int64_t timestampUs; 321 if (mNumFramesReceived == 0) { 322 timestampUs = mStartTimeUs; 323 } else { 324 timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; 325 } 326 327 if (mNeedCropping) { 328 sp<IMemory> croppedImageData = cropYUVImage(data); 329 dataCallbackTimestamp(timestampUs, msgType, croppedImageData); 330 } else { 331 sp<IMemory> dataCopy = createIMemoryCopy(data); 332 dataCallbackTimestamp(timestampUs, msgType, dataCopy); 333 } 334} 335 336bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) { 337 if (mSkipCurrentFrame) { 338 mSkipCurrentFrame = false; 339 return true; 340 } else { 341 return false; 342 } 343} 344 345bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { 346 if (!mUseStillCameraForTimeLapse) { 347 if (mLastTimeLapseFrameRealTimestampUs == 0) { 348 // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs 349 // to current time (timestampUs) and save frame data. 350 LOGV("dataCallbackTimestamp timelapse: initial frame"); 351 352 mLastTimeLapseFrameRealTimestampUs = *timestampUs; 353 } else if (*timestampUs < 354 (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) { 355 // Skip all frames from last encoded frame until 356 // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed. 357 // Tell the camera to release its recording frame and return. 358 LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame"); 359 return true; 360 } else { 361 // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time: 362 // - Reset mLastTimeLapseFrameRealTimestampUs to current time. 363 // - Artificially modify timestampUs to be one frame time (1/framerate) ahead 364 // of the last encoded frame's time stamp. 365 LOGV("dataCallbackTimestamp timelapse: got timelapse frame"); 366 367 mLastTimeLapseFrameRealTimestampUs = *timestampUs; 368 *timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; 369 } 370 } 371 return false; 372} 373 374void CameraSourceTimeLapse::dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, 375 const sp<IMemory> &data) { 376 if (!mUseStillCameraForTimeLapse) { 377 mSkipCurrentFrame = skipFrameAndModifyTimeStamp(×tampUs); 378 } 379 CameraSource::dataCallbackTimestamp(timestampUs, msgType, data); 380} 381 382} // namespace android 383