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