blob: 30ed1436cc44e1d9056634a3fd3c0695eb7f099a [file] [log] [blame]
Nipun Kwatraf9b80182010-07-12 09:17:14 -07001/*
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) {
Nipun Kwatra4cd86722010-07-18 15:52:02 -070095 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 }
Nipun Kwatraf9b80182010-07-12 09:17:14 -0700104 }
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);
Nipun Kwatraf9b80182010-07-12 09:17:14 -0700121 params.setPictureSize(width, height);
122 mCamera->setParameters(params.flatten());
Nipun Kwatra4cd86722010-07-18 15:52:02 -0700123 mCameraIdle = true;
Nipun Kwatraf9b80182010-07-12 09:17:14 -0700124
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
Nipun Kwatra4cd86722010-07-18 15:52:02 -0700163// 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
Nipun Kwatraf9b80182010-07-12 09:17:14 -0700187void CameraSourceTimeLapse::dataCallback(int32_t msgType, const sp<IMemory> &data) {
Nipun Kwatra4cd86722010-07-18 15:52:02 -0700188 if(msgType == CAMERA_MSG_COMPRESSED_IMAGE) {
189 // takePicture will complete after this callback, so restart preview.
190 restartPreview();
191 }
Nipun Kwatraf9b80182010-07-12 09:17:14 -0700192 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(&timestampUs);
251 }
252 CameraSource::dataCallbackTimestamp(timestampUs, msgType, data);
253}
254
255} // namespace android