CallbackProcessor.cpp revision cf70d3469332445dc3ffd09729da3538612b1bb2
1/*
2 * Copyright (C) 2012 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_TAG "Camera2Client::CallbackProcessor"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23
24#include "CallbackProcessor.h"
25#include <gui/SurfaceTextureClient.h>
26#include "../Camera2Device.h"
27#include "../Camera2Client.h"
28
29
30namespace android {
31namespace camera2 {
32
33CallbackProcessor::CallbackProcessor(wp<Camera2Client> client):
34        Thread(false),
35        mClient(client),
36        mCallbackAvailable(false),
37        mCallbackStreamId(NO_STREAM) {
38}
39
40CallbackProcessor::~CallbackProcessor() {
41    ALOGV("%s: Exit", __FUNCTION__);
42    deleteStream();
43}
44
45void CallbackProcessor::onFrameAvailable() {
46    Mutex::Autolock l(mInputMutex);
47    if (!mCallbackAvailable) {
48        mCallbackAvailable = true;
49        mCallbackAvailableSignal.signal();
50    }
51}
52
53status_t CallbackProcessor::updateStream(const Parameters &params) {
54    ATRACE_CALL();
55    status_t res;
56
57    Mutex::Autolock l(mInputMutex);
58
59    sp<Camera2Client> client = mClient.promote();
60    if (client == 0) return OK;
61    sp<Camera2Device> device = client->getCameraDevice();
62
63    if (mCallbackConsumer == 0) {
64        // Create CPU buffer queue endpoint
65        mCallbackConsumer = new CpuConsumer(kCallbackHeapCount);
66        mCallbackConsumer->setFrameAvailableListener(this);
67        mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
68        mCallbackWindow = new SurfaceTextureClient(
69            mCallbackConsumer->getProducerInterface());
70    }
71
72    if (mCallbackStreamId != NO_STREAM) {
73        // Check if stream parameters have to change
74        uint32_t currentWidth, currentHeight, currentFormat;
75        res = device->getStreamInfo(mCallbackStreamId,
76                &currentWidth, &currentHeight, &currentFormat);
77        if (res != OK) {
78            ALOGE("%s: Camera %d: Error querying callback output stream info: "
79                    "%s (%d)", __FUNCTION__, client->getCameraId(),
80                    strerror(-res), res);
81            return res;
82        }
83        if (currentWidth != (uint32_t)params.previewWidth ||
84                currentHeight != (uint32_t)params.previewHeight ||
85                currentFormat != (uint32_t)params.previewFormat) {
86            // Since size should only change while preview is not running,
87            // assuming that all existing use of old callback stream is
88            // completed.
89            res = device->deleteStream(mCallbackStreamId);
90            if (res != OK) {
91                ALOGE("%s: Camera %d: Unable to delete old output stream "
92                        "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(),
93                        strerror(-res), res);
94                return res;
95            }
96            mCallbackStreamId = NO_STREAM;
97        }
98    }
99
100    if (mCallbackStreamId == NO_STREAM) {
101        ALOGV("Creating callback stream: %d %d format 0x%x",
102                params.previewWidth, params.previewHeight,
103                params.previewFormat);
104        res = device->createStream(mCallbackWindow,
105                params.previewWidth, params.previewHeight,
106                params.previewFormat, 0, &mCallbackStreamId);
107        if (res != OK) {
108            ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
109                    "%s (%d)", __FUNCTION__, client->getCameraId(),
110                    strerror(-res), res);
111            return res;
112        }
113    }
114
115    return OK;
116}
117
118status_t CallbackProcessor::deleteStream() {
119    ATRACE_CALL();
120    status_t res;
121
122    Mutex::Autolock l(mInputMutex);
123
124    if (mCallbackStreamId != NO_STREAM) {
125        sp<Camera2Client> client = mClient.promote();
126        if (client == 0) return OK;
127        sp<Camera2Device> device = client->getCameraDevice();
128
129        device->deleteStream(mCallbackStreamId);
130
131        mCallbackHeap.clear();
132        mCallbackWindow.clear();
133        mCallbackConsumer.clear();
134
135        mCallbackStreamId = NO_STREAM;
136    }
137    return OK;
138}
139
140int CallbackProcessor::getStreamId() const {
141    Mutex::Autolock l(mInputMutex);
142    return mCallbackStreamId;
143}
144
145void CallbackProcessor::dump(int fd, const Vector<String16>& args) const {
146}
147
148bool CallbackProcessor::threadLoop() {
149    status_t res;
150
151    {
152        Mutex::Autolock l(mInputMutex);
153        while (!mCallbackAvailable) {
154            res = mCallbackAvailableSignal.waitRelative(mInputMutex,
155                    kWaitDuration);
156            if (res == TIMED_OUT) return true;
157        }
158        mCallbackAvailable = false;
159    }
160
161    do {
162        sp<Camera2Client> client = mClient.promote();
163        if (client == 0) return false;
164        res = processNewCallback(client);
165    } while (res == OK);
166
167    return true;
168}
169
170status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) {
171    ATRACE_CALL();
172    status_t res;
173
174    int callbackHeapId;
175    sp<Camera2Heap> callbackHeap;
176    size_t heapIdx;
177
178    CpuConsumer::LockedBuffer imgBuffer;
179    ALOGV("%s: Getting buffer", __FUNCTION__);
180    res = mCallbackConsumer->lockNextBuffer(&imgBuffer);
181    if (res != OK) {
182        if (res != BAD_VALUE) {
183            ALOGE("%s: Camera %d: Error receiving next callback buffer: "
184                    "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
185        }
186        return res;
187    }
188    ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__,
189            client->getCameraId());
190
191    {
192        SharedParameters::Lock l(client->getParameters());
193
194        if ( l.mParameters.state != Parameters::PREVIEW
195                && l.mParameters.state != Parameters::RECORD
196                && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
197            ALOGV("%s: Camera %d: No longer streaming",
198                    __FUNCTION__, client->getCameraId());
199            mCallbackConsumer->unlockBuffer(imgBuffer);
200            return OK;
201        }
202
203        if (! (l.mParameters.previewCallbackFlags &
204                CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) {
205            ALOGV("%s: No longer enabled, dropping", __FUNCTION__);
206            mCallbackConsumer->unlockBuffer(imgBuffer);
207            return OK;
208        }
209        if ((l.mParameters.previewCallbackFlags &
210                        CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) &&
211                !l.mParameters.previewCallbackOneShot) {
212            ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__);
213            mCallbackConsumer->unlockBuffer(imgBuffer);
214            return OK;
215        }
216
217        if (imgBuffer.format != l.mParameters.previewFormat) {
218            ALOGE("%s: Camera %d: Unexpected format for callback: "
219                    "%x, expected %x", __FUNCTION__, client->getCameraId(),
220                    imgBuffer.format, l.mParameters.previewFormat);
221            mCallbackConsumer->unlockBuffer(imgBuffer);
222            return INVALID_OPERATION;
223        }
224
225        // In one-shot mode, stop sending callbacks after the first one
226        if (l.mParameters.previewCallbackFlags &
227                CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
228            ALOGV("%s: clearing oneshot", __FUNCTION__);
229            l.mParameters.previewCallbackOneShot = false;
230        }
231    }
232
233    size_t bufferSize = Camera2Client::calculateBufferSize(
234            imgBuffer.width, imgBuffer.height,
235            imgBuffer.format, imgBuffer.stride);
236    size_t currentBufferSize = (mCallbackHeap == 0) ?
237            0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount);
238    if (bufferSize != currentBufferSize) {
239        mCallbackHeap.clear();
240        mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount,
241                "Camera2Client::CallbackHeap");
242        if (mCallbackHeap->mHeap->getSize() == 0) {
243            ALOGE("%s: Camera %d: Unable to allocate memory for callbacks",
244                    __FUNCTION__, client->getCameraId());
245            mCallbackConsumer->unlockBuffer(imgBuffer);
246            return INVALID_OPERATION;
247        }
248
249        mCallbackHeapHead = 0;
250        mCallbackHeapFree = kCallbackHeapCount;
251    }
252
253    if (mCallbackHeapFree == 0) {
254        ALOGE("%s: Camera %d: No free callback buffers, dropping frame",
255                __FUNCTION__, client->getCameraId());
256        mCallbackConsumer->unlockBuffer(imgBuffer);
257        return OK;
258    }
259
260    heapIdx = mCallbackHeapHead;
261
262    mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount;
263    mCallbackHeapFree--;
264
265    // TODO: Get rid of this memcpy by passing the gralloc queue all the way
266    // to app
267
268    ssize_t offset;
269    size_t size;
270    sp<IMemoryHeap> heap =
271            mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset,
272                    &size);
273    uint8_t *data = (uint8_t*)heap->getBase() + offset;
274    memcpy(data, imgBuffer.data, bufferSize);
275
276    ALOGV("%s: Freeing buffer", __FUNCTION__);
277    mCallbackConsumer->unlockBuffer(imgBuffer);
278
279    // Call outside parameter lock to allow re-entrancy from notification
280    {
281        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
282        if (l.mCameraClient != 0) {
283            ALOGV("%s: Camera %d: Invoking client data callback",
284                    __FUNCTION__, client->getCameraId());
285            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
286                    mCallbackHeap->mBuffers[heapIdx], NULL);
287        }
288    }
289
290    // Only increment free if we're still using the same heap
291    mCallbackHeapFree++;
292
293    ALOGV("%s: exit", __FUNCTION__);
294
295    return OK;
296}
297
298}; // namespace camera2
299}; // namespace android
300