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