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(&timestampUs);
251    }
252    CameraSource::dataCallbackTimestamp(timestampUs, msgType, data);
253}
254
255}  // namespace android
256