ProCamera.cpp revision 5e1f08b3917ac7900f8a11118afb7e8bf3e61c64
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
63void ProCamera::onLockStatusChanged(
64                                 IProCameraCallbacks::LockStatus newLockStatus)
65{
66    ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus);
67
68    sp<ProCameraListener> listener;
69    {
70        Mutex::Autolock _l(mLock);
71        listener = mListener;
72    }
73    if (listener != NULL) {
74        switch (newLockStatus) {
75            case IProCameraCallbacks::LOCK_ACQUIRED:
76                listener->onLockAcquired();
77                break;
78            case IProCameraCallbacks::LOCK_RELEASED:
79                listener->onLockReleased();
80                break;
81            case IProCameraCallbacks::LOCK_STOLEN:
82                listener->onLockStolen();
83                break;
84            default:
85                ALOGE("%s: Unknown lock status: %d",
86                      __FUNCTION__, newLockStatus);
87        }
88    }
89}
90
91void ProCamera::onResultReceived(int32_t frameId, camera_metadata* result) {
92    ALOGV("%s: frameId = %d, result = %p", __FUNCTION__, frameId, result);
93
94    sp<ProCameraListener> listener;
95    {
96        Mutex::Autolock _l(mLock);
97        listener = mListener;
98    }
99
100    CameraMetadata tmp(result);
101
102    // Unblock waitForFrame(id) callers
103    {
104        Mutex::Autolock al(mWaitMutex);
105        mMetadataReady = true;
106        mLatestMetadata = tmp; // make copy
107        mWaitCondition.broadcast();
108    }
109
110    result = tmp.release();
111
112    if (listener != NULL) {
113        listener->onResultReceived(frameId, result);
114    } else {
115        free_camera_metadata(result);
116    }
117
118}
119
120status_t ProCamera::exclusiveTryLock()
121{
122    sp <IProCameraUser> c = mCamera;
123    if (c == 0) return NO_INIT;
124
125    return c->exclusiveTryLock();
126}
127status_t ProCamera::exclusiveLock()
128{
129    sp <IProCameraUser> c = mCamera;
130    if (c == 0) return NO_INIT;
131
132    return c->exclusiveLock();
133}
134status_t ProCamera::exclusiveUnlock()
135{
136    sp <IProCameraUser> c = mCamera;
137    if (c == 0) return NO_INIT;
138
139    return c->exclusiveUnlock();
140}
141bool ProCamera::hasExclusiveLock()
142{
143    sp <IProCameraUser> c = mCamera;
144    if (c == 0) return NO_INIT;
145
146    return c->hasExclusiveLock();
147}
148
149// Note that the callee gets a copy of the metadata.
150int ProCamera::submitRequest(const struct camera_metadata* metadata,
151                             bool streaming)
152{
153    sp <IProCameraUser> c = mCamera;
154    if (c == 0) return NO_INIT;
155
156    return c->submitRequest(const_cast<struct camera_metadata*>(metadata),
157                            streaming);
158}
159
160status_t ProCamera::cancelRequest(int requestId)
161{
162    sp <IProCameraUser> c = mCamera;
163    if (c == 0) return NO_INIT;
164
165    return c->cancelRequest(requestId);
166}
167
168status_t ProCamera::deleteStream(int streamId)
169{
170    sp <IProCameraUser> c = mCamera;
171    if (c == 0) return NO_INIT;
172
173    status_t s = c->deleteStream(streamId);
174
175    mStreams.removeItem(streamId);
176
177    return s;
178}
179
180status_t ProCamera::createStream(int width, int height, int format,
181                                 const sp<Surface>& surface,
182                                 /*out*/
183                                 int* streamId)
184{
185    *streamId = -1;
186
187    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
188                                                                       format);
189
190    if (surface == 0) {
191        return BAD_VALUE;
192    }
193
194    return createStream(width, height, format,
195                        surface->getIGraphicBufferProducer(),
196                        streamId);
197}
198
199status_t ProCamera::createStream(int width, int height, int format,
200                                 const sp<IGraphicBufferProducer>& bufferProducer,
201                                 /*out*/
202                                 int* streamId) {
203    *streamId = -1;
204
205    ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
206                                                                       format);
207
208    if (bufferProducer == 0) {
209        return BAD_VALUE;
210    }
211
212    sp <IProCameraUser> c = mCamera;
213    status_t stat = c->createStream(width, height, format, bufferProducer,
214                                    streamId);
215
216    if (stat == OK) {
217        StreamInfo s(*streamId);
218
219        mStreams.add(*streamId, s);
220    }
221
222    return stat;
223}
224
225status_t ProCamera::createStreamCpu(int width, int height, int format,
226                                    int heapCount,
227                                    /*out*/
228                                    sp<CpuConsumer>* cpuConsumer,
229                                    int* streamId) {
230    return createStreamCpu(width, height, format, heapCount,
231                           /*synchronousMode*/true,
232                           cpuConsumer, streamId);
233}
234
235status_t ProCamera::createStreamCpu(int width, int height, int format,
236                                    int heapCount,
237                                    bool synchronousMode,
238                                    /*out*/
239                                    sp<CpuConsumer>* cpuConsumer,
240                                    int* streamId)
241{
242    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
243                                                                        format);
244
245    *cpuConsumer = NULL;
246
247    sp <IProCameraUser> c = mCamera;
248    if (c == 0) return NO_INIT;
249
250    sp<BufferQueue> bq = new BufferQueue();
251    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
252    cc->setName(String8("ProCamera::mCpuConsumer"));
253
254    sp<Surface> stc = new Surface(
255        cc->getProducerInterface());
256
257    status_t s = createStream(width, height, format,
258                              stc->getIGraphicBufferProducer(),
259                              streamId);
260
261    if (s != OK) {
262        ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
263                    width, height, format);
264        return s;
265    }
266
267    sp<ProFrameListener> frameAvailableListener =
268        new ProFrameListener(this, *streamId);
269
270    getStreamInfo(*streamId).cpuStream = true;
271    getStreamInfo(*streamId).cpuConsumer = cc;
272    getStreamInfo(*streamId).synchronousMode = synchronousMode;
273    getStreamInfo(*streamId).stc = stc;
274    // for lifetime management
275    getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
276
277    cc->setFrameAvailableListener(frameAvailableListener);
278
279    *cpuConsumer = cc;
280
281    return s;
282}
283
284camera_metadata* ProCamera::getCameraInfo(int cameraId) {
285    ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);
286
287    sp <IProCameraUser> c = mCamera;
288    if (c == 0) return NULL;
289
290    camera_metadata* ptr = NULL;
291    status_t status = c->getCameraInfo(cameraId, &ptr);
292
293    if (status != OK) {
294        ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status);
295    }
296
297    return ptr;
298}
299
300status_t ProCamera::createDefaultRequest(int templateId,
301                                             camera_metadata** request) const {
302    ALOGV("%s: templateId = %d", __FUNCTION__, templateId);
303
304    sp <IProCameraUser> c = mCamera;
305    if (c == 0) return NO_INIT;
306
307    return c->createDefaultRequest(templateId, request);
308}
309
310void ProCamera::onFrameAvailable(int streamId) {
311    ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
312
313    sp<ProCameraListener> listener = mListener;
314    StreamInfo& stream = getStreamInfo(streamId);
315
316    if (listener.get() != NULL) {
317        listener->onFrameAvailable(streamId, stream.cpuConsumer);
318    }
319
320    // Unblock waitForFrame(id) callers
321    {
322        Mutex::Autolock al(mWaitMutex);
323        getStreamInfo(streamId).frameReady++;
324        mWaitCondition.broadcast();
325    }
326}
327
328int ProCamera::waitForFrameBuffer(int streamId) {
329    status_t stat = BAD_VALUE;
330    Mutex::Autolock al(mWaitMutex);
331
332    StreamInfo& si = getStreamInfo(streamId);
333
334    if (si.frameReady > 0) {
335        int numFrames = si.frameReady;
336        si.frameReady = 0;
337        return numFrames;
338    } else {
339        while (true) {
340            stat = mWaitCondition.waitRelative(mWaitMutex,
341                                                mWaitTimeout);
342            if (stat != OK) {
343                ALOGE("%s: Error while waiting for frame buffer: %d",
344                    __FUNCTION__, stat);
345                return stat;
346            }
347
348            if (si.frameReady > 0) {
349                int numFrames = si.frameReady;
350                si.frameReady = 0;
351                return numFrames;
352            }
353            // else it was some other stream that got unblocked
354        }
355    }
356
357    return stat;
358}
359
360int ProCamera::dropFrameBuffer(int streamId, int count) {
361    StreamInfo& si = getStreamInfo(streamId);
362
363    if (!si.cpuStream) {
364        return BAD_VALUE;
365    } else if (count < 0) {
366        return BAD_VALUE;
367    }
368
369    if (!si.synchronousMode) {
370        ALOGW("%s: No need to drop frames on asynchronous streams,"
371              " as asynchronous mode only keeps 1 latest frame around.",
372              __FUNCTION__);
373        return BAD_VALUE;
374    }
375
376    int numDropped = 0;
377    for (int i = 0; i < count; ++i) {
378        CpuConsumer::LockedBuffer buffer;
379        if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) {
380            break;
381        }
382
383        si.cpuConsumer->unlockBuffer(buffer);
384        numDropped++;
385    }
386
387    return numDropped;
388}
389
390status_t ProCamera::waitForFrameMetadata() {
391    status_t stat = BAD_VALUE;
392    Mutex::Autolock al(mWaitMutex);
393
394    if (mMetadataReady) {
395        return OK;
396    } else {
397        while (true) {
398            stat = mWaitCondition.waitRelative(mWaitMutex,
399                                               mWaitTimeout);
400
401            if (stat != OK) {
402                ALOGE("%s: Error while waiting for metadata: %d",
403                        __FUNCTION__, stat);
404                return stat;
405            }
406
407            if (mMetadataReady) {
408                mMetadataReady = false;
409                return OK;
410            }
411            // else it was some other stream or metadata
412        }
413    }
414
415    return stat;
416}
417
418CameraMetadata ProCamera::consumeFrameMetadata() {
419    Mutex::Autolock al(mWaitMutex);
420
421    // Destructive: Subsequent calls return empty metadatas
422    CameraMetadata tmp = mLatestMetadata;
423    mLatestMetadata.clear();
424
425    return tmp;
426}
427
428ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
429    return mStreams.editValueFor(streamId);
430}
431
432}; // namespace android
433