ProCamera.cpp revision ba5ca4ee770fa0fe9e14990fd13b23f1010f5c98
1/*
2**
3** Copyright (C) 2013, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ProCamera"
20#include <utils/Log.h>
21#include <utils/threads.h>
22#include <utils/Mutex.h>
23
24#include <binder/IPCThreadState.h>
25#include <binder/IServiceManager.h>
26#include <binder/IMemory.h>
27
28#include <camera/ProCamera.h>
29#include <camera/ICameraService.h>
30#include <camera/IProCameraUser.h>
31#include <camera/IProCameraCallbacks.h>
32
33#include <gui/IGraphicBufferProducer.h>
34
35#include <system/camera_metadata.h>
36
37namespace android {
38
39sp<ProCamera> ProCamera::connect(int cameraId)
40{
41    return CameraBaseT::connect(cameraId, String16(),
42                                 ICameraService::USE_CALLING_UID);
43}
44
45ProCamera::ProCamera(int cameraId)
46    : CameraBase(cameraId)
47{
48}
49
50ProCamera::~ProCamera()
51{
52
53}
54
55/* IProCameraUser's implementation */
56
57// callback from camera service
58void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
59{
60    return CameraBaseT::notifyCallback(msgType, ext1, ext2);
61}
62
63// callback from camera service when frame or image is ready
64void ProCamera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
65                          camera_frame_metadata_t *metadata)
66{
67    return CameraBaseT::dataCallback(msgType, dataPtr, metadata);
68}
69
70// callback from camera service when timestamped frame is ready
71void ProCamera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
72                                   const sp<IMemory>& dataPtr)
73{
74    CameraBaseT::dataCallbackTimestamp(timestamp, msgType, dataPtr);
75}
76
77
78void ProCamera::onLockStatusChanged(
79                                 IProCameraCallbacks::LockStatus newLockStatus)
80{
81    ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus);
82
83    sp<ProCameraListener> listener;
84    {
85        Mutex::Autolock _l(mLock);
86        listener = mListener;
87    }
88    if (listener != NULL) {
89        switch (newLockStatus) {
90            case IProCameraCallbacks::LOCK_ACQUIRED:
91                listener->onLockAcquired();
92                break;
93            case IProCameraCallbacks::LOCK_RELEASED:
94                listener->onLockReleased();
95                break;
96            case IProCameraCallbacks::LOCK_STOLEN:
97                listener->onLockStolen();
98                break;
99            default:
100                ALOGE("%s: Unknown lock status: %d",
101                      __FUNCTION__, newLockStatus);
102        }
103    }
104}
105
106void ProCamera::onResultReceived(int32_t frameId, camera_metadata* result) {
107    ALOGV("%s: frameId = %d, result = %p", __FUNCTION__, frameId, result);
108
109    sp<ProCameraListener> listener;
110    {
111        Mutex::Autolock _l(mLock);
112        listener = mListener;
113    }
114
115    CameraMetadata tmp(result);
116
117    // Unblock waitForFrame(id) callers
118    {
119        Mutex::Autolock al(mWaitMutex);
120        mMetadataReady = true;
121        mLatestMetadata = tmp;
122        mWaitCondition.broadcast();
123    }
124
125    result = tmp.release();
126
127    if (listener != NULL) {
128        listener->onResultReceived(frameId, result);
129    } else {
130        free_camera_metadata(result);
131    }
132
133}
134
135status_t ProCamera::exclusiveTryLock()
136{
137    sp <IProCameraUser> c = mCamera;
138    if (c == 0) return NO_INIT;
139
140    return c->exclusiveTryLock();
141}
142status_t ProCamera::exclusiveLock()
143{
144    sp <IProCameraUser> c = mCamera;
145    if (c == 0) return NO_INIT;
146
147    return c->exclusiveLock();
148}
149status_t ProCamera::exclusiveUnlock()
150{
151    sp <IProCameraUser> c = mCamera;
152    if (c == 0) return NO_INIT;
153
154    return c->exclusiveUnlock();
155}
156bool ProCamera::hasExclusiveLock()
157{
158    sp <IProCameraUser> c = mCamera;
159    if (c == 0) return NO_INIT;
160
161    return c->hasExclusiveLock();
162}
163
164// Note that the callee gets a copy of the metadata.
165int ProCamera::submitRequest(const struct camera_metadata* metadata,
166                             bool streaming)
167{
168    sp <IProCameraUser> c = mCamera;
169    if (c == 0) return NO_INIT;
170
171    return c->submitRequest(const_cast<struct camera_metadata*>(metadata),
172                            streaming);
173}
174
175status_t ProCamera::cancelRequest(int requestId)
176{
177    sp <IProCameraUser> c = mCamera;
178    if (c == 0) return NO_INIT;
179
180    return c->cancelRequest(requestId);
181}
182
183status_t ProCamera::deleteStream(int streamId)
184{
185    sp <IProCameraUser> c = mCamera;
186    if (c == 0) return NO_INIT;
187
188    status_t s = c->cancelStream(streamId);
189
190    mStreams.removeItem(streamId);
191
192    return s;
193}
194
195status_t ProCamera::createStream(int width, int height, int format,
196                                 const sp<Surface>& surface,
197                                 /*out*/
198                                 int* streamId)
199{
200    *streamId = -1;
201
202    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
203                                                                       format);
204
205    if (surface == 0) {
206        return BAD_VALUE;
207    }
208
209    return createStream(width, height, format,
210                        surface->getIGraphicBufferProducer(),
211                        streamId);
212}
213
214status_t ProCamera::createStream(int width, int height, int format,
215                                 const sp<IGraphicBufferProducer>& bufferProducer,
216                                 /*out*/
217                                 int* streamId) {
218    *streamId = -1;
219
220    ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
221                                                                       format);
222
223    if (bufferProducer == 0) {
224        return BAD_VALUE;
225    }
226
227    sp <IProCameraUser> c = mCamera;
228    status_t stat = c->createStream(width, height, format, bufferProducer,
229                                    streamId);
230
231    if (stat == OK) {
232        StreamInfo s(*streamId);
233
234        mStreams.add(*streamId, s);
235    }
236
237    return stat;
238}
239
240status_t ProCamera::createStreamCpu(int width, int height, int format,
241                                    int heapCount,
242                                    /*out*/
243                                    sp<CpuConsumer>* cpuConsumer,
244                                    int* streamId) {
245    return createStreamCpu(width, height, format, heapCount,
246                           /*synchronousMode*/true,
247                           cpuConsumer, streamId);
248}
249
250status_t ProCamera::createStreamCpu(int width, int height, int format,
251                                    int heapCount,
252                                    bool synchronousMode,
253                                    /*out*/
254                                    sp<CpuConsumer>* cpuConsumer,
255                                    int* streamId)
256{
257    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
258                                                                        format);
259
260    *cpuConsumer = NULL;
261
262    sp <IProCameraUser> c = mCamera;
263    if (c == 0) return NO_INIT;
264
265    sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode);
266    cc->setName(String8("ProCamera::mCpuConsumer"));
267
268    sp<Surface> stc = new Surface(
269        cc->getProducerInterface());
270
271    status_t s = createStream(width, height, format,
272                              stc->getIGraphicBufferProducer(),
273                              streamId);
274
275    if (s != OK) {
276        ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
277                    width, height, format);
278        return s;
279    }
280
281    sp<ProFrameListener> frameAvailableListener =
282        new ProFrameListener(this, *streamId);
283
284    getStreamInfo(*streamId).cpuStream = true;
285    getStreamInfo(*streamId).cpuConsumer = cc;
286    getStreamInfo(*streamId).synchronousMode = synchronousMode;
287    getStreamInfo(*streamId).stc = stc;
288    // for lifetime management
289    getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
290
291    cc->setFrameAvailableListener(frameAvailableListener);
292
293    *cpuConsumer = cc;
294
295    return s;
296}
297
298camera_metadata* ProCamera::getCameraInfo(int cameraId) {
299    ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);
300
301    sp <IProCameraUser> c = mCamera;
302    if (c == 0) return NULL;
303
304    camera_metadata* ptr = NULL;
305    status_t status = c->getCameraInfo(cameraId, &ptr);
306
307    if (status != OK) {
308        ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status);
309    }
310
311    return ptr;
312}
313
314status_t ProCamera::createDefaultRequest(int templateId,
315                                             camera_metadata** request) const {
316    ALOGV("%s: templateId = %d", __FUNCTION__, templateId);
317
318    sp <IProCameraUser> c = mCamera;
319    if (c == 0) return NO_INIT;
320
321    return c->createDefaultRequest(templateId, request);
322}
323
324void ProCamera::onFrameAvailable(int streamId) {
325    ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
326
327    sp<ProCameraListener> listener = mListener;
328    StreamInfo& stream = getStreamInfo(streamId);
329
330    CpuConsumer::LockedBuffer buf;
331
332    if (listener.get() != NULL) {
333        if (listener->useOnFrameAvailable()) {
334            listener->onFrameAvailable(streamId, stream.cpuConsumer);
335            return;
336        }
337    }
338
339    // Unblock waitForFrame(id) callers
340    {
341        Mutex::Autolock al(mWaitMutex);
342        getStreamInfo(streamId).frameReady++;
343        mWaitCondition.broadcast();
344    }
345}
346
347int ProCamera::waitForFrameBuffer(int streamId) {
348    status_t stat = BAD_VALUE;
349    Mutex::Autolock al(mWaitMutex);
350
351    StreamInfo& si = getStreamInfo(streamId);
352
353    if (si.frameReady > 0) {
354        int numFrames = si.frameReady;
355        si.frameReady = 0;
356        return numFrames;
357    } else {
358        while (true) {
359            stat = mWaitCondition.waitRelative(mWaitMutex,
360                                                mWaitTimeout);
361            if (stat != OK) {
362                ALOGE("%s: Error while waiting for frame buffer: %d",
363                    __FUNCTION__, stat);
364                return stat;
365            }
366
367            if (si.frameReady > 0) {
368                int numFrames = si.frameReady;
369                si.frameReady = 0;
370                return numFrames;
371            }
372            // else it was some other stream that got unblocked
373        }
374    }
375
376    return stat;
377}
378
379int ProCamera::dropFrameBuffer(int streamId, int count) {
380    StreamInfo& si = getStreamInfo(streamId);
381
382    if (!si.cpuStream) {
383        return BAD_VALUE;
384    } else if (count < 0) {
385        return BAD_VALUE;
386    }
387
388    if (!si.synchronousMode) {
389        ALOGW("%s: No need to drop frames on asynchronous streams,"
390              " as asynchronous mode only keeps 1 latest frame around.",
391              __FUNCTION__);
392        return BAD_VALUE;
393    }
394
395    int numDropped = 0;
396    for (int i = 0; i < count; ++i) {
397        CpuConsumer::LockedBuffer buffer;
398        if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) {
399            break;
400        }
401
402        si.cpuConsumer->unlockBuffer(buffer);
403        numDropped++;
404    }
405
406    return numDropped;
407}
408
409status_t ProCamera::waitForFrameMetadata() {
410    status_t stat = BAD_VALUE;
411    Mutex::Autolock al(mWaitMutex);
412
413    if (mMetadataReady) {
414        return OK;
415    } else {
416        while (true) {
417            stat = mWaitCondition.waitRelative(mWaitMutex,
418                                               mWaitTimeout);
419
420            if (stat != OK) {
421                ALOGE("%s: Error while waiting for metadata: %d",
422                        __FUNCTION__, stat);
423                return stat;
424            }
425
426            if (mMetadataReady) {
427                mMetadataReady = false;
428                return OK;
429            }
430            // else it was some other stream or metadata
431        }
432    }
433
434    return stat;
435}
436
437CameraMetadata ProCamera::consumeFrameMetadata() {
438    Mutex::Autolock al(mWaitMutex);
439
440    // Destructive: Subsequent calls return empty metadatas
441    CameraMetadata tmp = mLatestMetadata;
442    mLatestMetadata.release();
443
444    return tmp;
445}
446
447ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
448    return mStreams.editValueFor(streamId);
449}
450
451}; // namespace android
452