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