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