CameraSourceTimeLapse.cpp revision e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8
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 31namespace android { 32 33// static 34CameraSourceTimeLapse *CameraSourceTimeLapse::Create(bool useStillCameraForTimeLapse, 35 int64_t timeBetweenTimeLapseFrameCaptureUs, 36 int32_t width, int32_t height, 37 int32_t videoFrameRate) { 38 sp<Camera> camera = Camera::connect(0); 39 40 if (camera.get() == NULL) { 41 return NULL; 42 } 43 44 return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse, 45 timeBetweenTimeLapseFrameCaptureUs, width, height, videoFrameRate); 46} 47 48// static 49CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(const sp<Camera> &camera, 50 bool useStillCameraForTimeLapse, 51 int64_t timeBetweenTimeLapseFrameCaptureUs, 52 int32_t width, int32_t height, 53 int32_t videoFrameRate) { 54 if (camera.get() == NULL) { 55 return NULL; 56 } 57 58 return new CameraSourceTimeLapse(camera, useStillCameraForTimeLapse, 59 timeBetweenTimeLapseFrameCaptureUs, width, height, videoFrameRate); 60} 61 62CameraSourceTimeLapse::CameraSourceTimeLapse(const sp<Camera> &camera, 63 bool useStillCameraForTimeLapse, 64 int64_t timeBetweenTimeLapseFrameCaptureUs, 65 int32_t width, int32_t height, 66 int32_t videoFrameRate) 67 : CameraSource(camera), 68 mUseStillCameraForTimeLapse(useStillCameraForTimeLapse), 69 mTimeBetweenTimeLapseFrameCaptureUs(timeBetweenTimeLapseFrameCaptureUs), 70 mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate), 71 mLastTimeLapseFrameRealTimestampUs(0), 72 mSkipCurrentFrame(false) { 73 74 LOGV("starting time lapse mode"); 75 if(mUseStillCameraForTimeLapse) { 76 mMeta->setInt32(kKeyWidth, width); 77 mMeta->setInt32(kKeyHeight, height); 78 } 79} 80 81CameraSourceTimeLapse::~CameraSourceTimeLapse() { 82} 83 84// static 85void *CameraSourceTimeLapse::ThreadTimeLapseWrapper(void *me) { 86 CameraSourceTimeLapse *source = static_cast<CameraSourceTimeLapse *>(me); 87 source->threadTimeLapseEntry(); 88 return NULL; 89} 90 91void CameraSourceTimeLapse::threadTimeLapseEntry() { 92 while(mStarted) { 93 if(mCameraIdle) { 94 LOGV("threadTimeLapseEntry: taking picture"); 95 CHECK_EQ(OK, mCamera->takePicture()); 96 mCameraIdle = false; 97 sleep(mTimeBetweenTimeLapseFrameCaptureUs/1E6); 98 } else { 99 LOGV("threadTimeLapseEntry: camera busy with old takePicture. Sleeping a little."); 100 sleep(.01); 101 } 102 } 103} 104 105void CameraSourceTimeLapse::startCameraRecording() { 106 if(mUseStillCameraForTimeLapse) { 107 LOGV("start time lapse recording using still camera"); 108 109 int32_t width; 110 int32_t height; 111 mMeta->findInt32(kKeyWidth, &width); 112 mMeta->findInt32(kKeyHeight, &height); 113 114 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 115 String8 s = mCamera->getParameters(); 116 IPCThreadState::self()->restoreCallingIdentity(token); 117 118 CameraParameters params(s); 119 params.setPictureSize(width, height); 120 mCamera->setParameters(params.flatten()); 121 mCameraIdle = true; 122 123 // create a thread which takes pictures in a loop 124 pthread_attr_t attr; 125 pthread_attr_init(&attr); 126 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 127 128 pthread_create(&mThreadTimeLapse, &attr, ThreadTimeLapseWrapper, this); 129 pthread_attr_destroy(&attr); 130 } else { 131 LOGV("start time lapse recording using video camera"); 132 CHECK_EQ(OK, mCamera->startRecording()); 133 } 134} 135 136void CameraSourceTimeLapse::stopCameraRecording() { 137 if(mUseStillCameraForTimeLapse) { 138 void *dummy; 139 pthread_join(mThreadTimeLapse, &dummy); 140 } else { 141 mCamera->stopRecording(); 142 } 143} 144 145void CameraSourceTimeLapse::releaseRecordingFrame(const sp<IMemory>& frame) { 146 if(!mUseStillCameraForTimeLapse) { 147 mCamera->releaseRecordingFrame(frame); 148 } 149} 150 151sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy(const sp<IMemory> &source_data) { 152 size_t source_size = source_data->size(); 153 void* source_pointer = source_data->pointer(); 154 155 sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size); 156 sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size); 157 memcpy(newMemory->pointer(), source_pointer, source_size); 158 return newMemory; 159} 160 161// static 162void *CameraSourceTimeLapse::ThreadStartPreviewWrapper(void *me) { 163 CameraSourceTimeLapse *source = static_cast<CameraSourceTimeLapse *>(me); 164 source->threadStartPreview(); 165 return NULL; 166} 167 168void CameraSourceTimeLapse::threadStartPreview() { 169 CHECK_EQ(OK, mCamera->startPreview()); 170 mCameraIdle = true; 171} 172 173void CameraSourceTimeLapse::restartPreview() { 174 // Start this in a different thread, so that the dataCallback can return 175 LOGV("restartPreview"); 176 pthread_attr_t attr; 177 pthread_attr_init(&attr); 178 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 179 180 pthread_t threadPreview; 181 pthread_create(&threadPreview, &attr, ThreadStartPreviewWrapper, this); 182 pthread_attr_destroy(&attr); 183} 184 185void CameraSourceTimeLapse::dataCallback(int32_t msgType, const sp<IMemory> &data) { 186 if(msgType == CAMERA_MSG_COMPRESSED_IMAGE) { 187 // takePicture will complete after this callback, so restart preview. 188 restartPreview(); 189 } 190 if(msgType != CAMERA_MSG_RAW_IMAGE) { 191 return; 192 } 193 194 LOGV("dataCallback for timelapse still frame"); 195 CHECK_EQ(true, mUseStillCameraForTimeLapse); 196 197 int64_t timestampUs; 198 if (mNumFramesReceived == 0) { 199 timestampUs = mStartTimeUs; 200 } else { 201 timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; 202 } 203 sp<IMemory> dataCopy = createIMemoryCopy(data); 204 dataCallbackTimestamp(timestampUs, msgType, dataCopy); 205} 206 207bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) { 208 if(mSkipCurrentFrame) { 209 mSkipCurrentFrame = false; 210 return true; 211 } else { 212 return false; 213 } 214} 215 216bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) { 217 if(!mUseStillCameraForTimeLapse) { 218 if(mLastTimeLapseFrameRealTimestampUs == 0) { 219 // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs 220 // to current time (timestampUs) and save frame data. 221 LOGV("dataCallbackTimestamp timelapse: initial frame"); 222 223 mLastTimeLapseFrameRealTimestampUs = *timestampUs; 224 } else if (*timestampUs < 225 (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) { 226 // Skip all frames from last encoded frame until 227 // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed. 228 // Tell the camera to release its recording frame and return. 229 LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame"); 230 return true; 231 } else { 232 // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time: 233 // - Reset mLastTimeLapseFrameRealTimestampUs to current time. 234 // - Artificially modify timestampUs to be one frame time (1/framerate) ahead 235 // of the last encoded frame's time stamp. 236 LOGV("dataCallbackTimestamp timelapse: got timelapse frame"); 237 238 mLastTimeLapseFrameRealTimestampUs = *timestampUs; 239 *timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs; 240 } 241 } 242 return false; 243} 244 245void CameraSourceTimeLapse::dataCallbackTimestamp(int64_t timestampUs, int32_t msgType, 246 const sp<IMemory> &data) { 247 if(!mUseStillCameraForTimeLapse) { 248 mSkipCurrentFrame = skipFrameAndModifyTimeStamp(×tampUs); 249 } 250 CameraSource::dataCallbackTimestamp(timestampUs, msgType, data); 251} 252 253} // namespace android 254