1/*
2 * Copyright (C) 2013 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 "Camera3-OutputStream"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23#include "Camera3OutputStream.h"
24
25#ifndef container_of
26#define container_of(ptr, type, member) \
27    (type *)((char*)(ptr) - offsetof(type, member))
28#endif
29
30namespace android {
31
32namespace camera3 {
33
34Camera3OutputStream::Camera3OutputStream(int id,
35        sp<ANativeWindow> consumer,
36        uint32_t width, uint32_t height, int format) :
37        Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
38                            /*maxSize*/0, format),
39        mConsumer(consumer),
40        mTransform(0),
41        mTraceFirstBuffer(true) {
42
43    if (mConsumer == NULL) {
44        ALOGE("%s: Consumer is NULL!", __FUNCTION__);
45        mState = STATE_ERROR;
46    }
47}
48
49Camera3OutputStream::Camera3OutputStream(int id,
50        sp<ANativeWindow> consumer,
51        uint32_t width, uint32_t height, size_t maxSize, int format) :
52        Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
53                            format),
54        mConsumer(consumer),
55        mTransform(0),
56        mTraceFirstBuffer(true) {
57
58    if (format != HAL_PIXEL_FORMAT_BLOB) {
59        ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
60                format);
61        mState = STATE_ERROR;
62    }
63
64    if (mConsumer == NULL) {
65        ALOGE("%s: Consumer is NULL!", __FUNCTION__);
66        mState = STATE_ERROR;
67    }
68}
69
70Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
71                                         uint32_t width, uint32_t height,
72                                         int format) :
73        Camera3IOStreamBase(id, type, width, height,
74                            /*maxSize*/0,
75                            format),
76        mTransform(0) {
77
78    // Subclasses expected to initialize mConsumer themselves
79}
80
81
82Camera3OutputStream::~Camera3OutputStream() {
83    disconnectLocked();
84}
85
86status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
87    ATRACE_CALL();
88    status_t res;
89
90    if ((res = getBufferPreconditionCheckLocked()) != OK) {
91        return res;
92    }
93
94    ANativeWindowBuffer* anb;
95    int fenceFd;
96
97    /**
98     * Release the lock briefly to avoid deadlock for below scenario:
99     * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
100     * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
101     * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
102     * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
103     * StreamingProcessor lock.
104     * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
105     * and try to lock bufferQueue lock.
106     * Then there is circular locking dependency.
107     */
108    sp<ANativeWindow> currentConsumer = mConsumer;
109    mLock.unlock();
110
111    res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
112    mLock.lock();
113    if (res != OK) {
114        ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
115                __FUNCTION__, mId, strerror(-res), res);
116        return res;
117    }
118
119    /**
120     * FenceFD now owned by HAL except in case of error,
121     * in which case we reassign it to acquire_fence
122     */
123    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
124                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
125
126    return OK;
127}
128
129status_t Camera3OutputStream::returnBufferLocked(
130        const camera3_stream_buffer &buffer,
131        nsecs_t timestamp) {
132    ATRACE_CALL();
133
134    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true);
135
136    if (res != OK) {
137        return res;
138    }
139
140    mLastTimestamp = timestamp;
141
142    return OK;
143}
144
145status_t Camera3OutputStream::returnBufferCheckedLocked(
146            const camera3_stream_buffer &buffer,
147            nsecs_t timestamp,
148            bool output,
149            /*out*/
150            sp<Fence> *releaseFenceOut) {
151
152    (void)output;
153    ALOG_ASSERT(output, "Expected output to be true");
154
155    status_t res;
156    sp<Fence> releaseFence;
157
158    /**
159     * Fence management - calculate Release Fence
160     */
161    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
162        if (buffer.release_fence != -1) {
163            ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when "
164                  "there is an error", __FUNCTION__, mId, buffer.release_fence);
165            close(buffer.release_fence);
166        }
167
168        /**
169         * Reassign release fence as the acquire fence in case of error
170         */
171        releaseFence = new Fence(buffer.acquire_fence);
172    } else {
173        res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
174        if (res != OK) {
175            ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
176                  __FUNCTION__, mId, strerror(-res), res);
177            return res;
178        }
179
180        releaseFence = new Fence(buffer.release_fence);
181    }
182
183    int anwReleaseFence = releaseFence->dup();
184
185    /**
186     * Release the lock briefly to avoid deadlock with
187     * StreamingProcessor::startStream -> Camera3Stream::isConfiguring (this
188     * thread will go into StreamingProcessor::onFrameAvailable) during
189     * queueBuffer
190     */
191    sp<ANativeWindow> currentConsumer = mConsumer;
192    mLock.unlock();
193
194    /**
195     * Return buffer back to ANativeWindow
196     */
197    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
198        // Cancel buffer
199        res = currentConsumer->cancelBuffer(currentConsumer.get(),
200                container_of(buffer.buffer, ANativeWindowBuffer, handle),
201                anwReleaseFence);
202        if (res != OK) {
203            ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
204                  " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
205        }
206    } else {
207        if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
208            {
209                char traceLog[48];
210                snprintf(traceLog, sizeof(traceLog), "Stream %d: first full buffer\n", mId);
211                ATRACE_NAME(traceLog);
212            }
213            mTraceFirstBuffer = false;
214        }
215
216        res = currentConsumer->queueBuffer(currentConsumer.get(),
217                container_of(buffer.buffer, ANativeWindowBuffer, handle),
218                anwReleaseFence);
219        if (res != OK) {
220            ALOGE("%s: Stream %d: Error queueing buffer to native window: "
221                  "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
222        }
223    }
224    mLock.lock();
225    if (res != OK) {
226        close(anwReleaseFence);
227    }
228
229    *releaseFenceOut = releaseFence;
230
231    return res;
232}
233
234void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const {
235    (void) args;
236    String8 lines;
237    lines.appendFormat("    Stream[%d]: Output\n", mId);
238    write(fd, lines.string(), lines.size());
239
240    Camera3IOStreamBase::dump(fd, args);
241}
242
243status_t Camera3OutputStream::setTransform(int transform) {
244    ATRACE_CALL();
245    Mutex::Autolock l(mLock);
246    return setTransformLocked(transform);
247}
248
249status_t Camera3OutputStream::setTransformLocked(int transform) {
250    status_t res = OK;
251    if (mState == STATE_ERROR) {
252        ALOGE("%s: Stream in error state", __FUNCTION__);
253        return INVALID_OPERATION;
254    }
255
256    mTransform = transform;
257    if (mState == STATE_CONFIGURED) {
258        res = native_window_set_buffers_transform(mConsumer.get(),
259                transform);
260        if (res != OK) {
261            ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
262                    __FUNCTION__, transform, strerror(-res), res);
263        }
264    }
265    return res;
266}
267
268status_t Camera3OutputStream::configureQueueLocked() {
269    status_t res;
270
271    mTraceFirstBuffer = true;
272    if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) {
273        return res;
274    }
275
276    ALOG_ASSERT(mConsumer != 0, "mConsumer should never be NULL");
277
278    // Configure consumer-side ANativeWindow interface
279    res = native_window_api_connect(mConsumer.get(),
280            NATIVE_WINDOW_API_CAMERA);
281    if (res != OK) {
282        ALOGE("%s: Unable to connect to native window for stream %d",
283                __FUNCTION__, mId);
284        return res;
285    }
286
287    res = native_window_set_usage(mConsumer.get(), camera3_stream::usage);
288    if (res != OK) {
289        ALOGE("%s: Unable to configure usage %08x for stream %d",
290                __FUNCTION__, camera3_stream::usage, mId);
291        return res;
292    }
293
294    res = native_window_set_scaling_mode(mConsumer.get(),
295            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
296    if (res != OK) {
297        ALOGE("%s: Unable to configure stream scaling: %s (%d)",
298                __FUNCTION__, strerror(-res), res);
299        return res;
300    }
301
302    if (mMaxSize == 0) {
303        // For buffers of known size
304        res = native_window_set_buffers_dimensions(mConsumer.get(),
305                camera3_stream::width, camera3_stream::height);
306    } else {
307        // For buffers with bounded size
308        res = native_window_set_buffers_dimensions(mConsumer.get(),
309                mMaxSize, 1);
310    }
311    if (res != OK) {
312        ALOGE("%s: Unable to configure stream buffer dimensions"
313                " %d x %d (maxSize %zu) for stream %d",
314                __FUNCTION__, camera3_stream::width, camera3_stream::height,
315                mMaxSize, mId);
316        return res;
317    }
318    res = native_window_set_buffers_format(mConsumer.get(),
319            camera3_stream::format);
320    if (res != OK) {
321        ALOGE("%s: Unable to configure stream buffer format %#x for stream %d",
322                __FUNCTION__, camera3_stream::format, mId);
323        return res;
324    }
325
326    int maxConsumerBuffers;
327    res = mConsumer->query(mConsumer.get(),
328            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
329    if (res != OK) {
330        ALOGE("%s: Unable to query consumer undequeued"
331                " buffer count for stream %d", __FUNCTION__, mId);
332        return res;
333    }
334
335    ALOGV("%s: Consumer wants %d buffers, HAL wants %d", __FUNCTION__,
336            maxConsumerBuffers, camera3_stream::max_buffers);
337    if (camera3_stream::max_buffers == 0) {
338        ALOGE("%s: Camera HAL requested max_buffer count: %d, requires at least 1",
339                __FUNCTION__, camera3_stream::max_buffers);
340        return INVALID_OPERATION;
341    }
342
343    mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers;
344    mHandoutTotalBufferCount = 0;
345    mFrameCount = 0;
346    mLastTimestamp = 0;
347
348    res = native_window_set_buffer_count(mConsumer.get(),
349            mTotalBufferCount);
350    if (res != OK) {
351        ALOGE("%s: Unable to set buffer count for stream %d",
352                __FUNCTION__, mId);
353        return res;
354    }
355
356    res = native_window_set_buffers_transform(mConsumer.get(),
357            mTransform);
358    if (res != OK) {
359        ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
360                __FUNCTION__, mTransform, strerror(-res), res);
361    }
362
363    return OK;
364}
365
366status_t Camera3OutputStream::disconnectLocked() {
367    status_t res;
368
369    if ((res = Camera3IOStreamBase::disconnectLocked()) != OK) {
370        return res;
371    }
372
373    res = native_window_api_disconnect(mConsumer.get(),
374                                       NATIVE_WINDOW_API_CAMERA);
375
376    /**
377     * This is not an error. if client calling process dies, the window will
378     * also die and all calls to it will return DEAD_OBJECT, thus it's already
379     * "disconnected"
380     */
381    if (res == DEAD_OBJECT) {
382        ALOGW("%s: While disconnecting stream %d from native window, the"
383                " native window died from under us", __FUNCTION__, mId);
384    }
385    else if (res != OK) {
386        ALOGE("%s: Unable to disconnect stream %d from native window "
387              "(error %d %s)",
388              __FUNCTION__, mId, res, strerror(-res));
389        mState = STATE_ERROR;
390        return res;
391    }
392
393    mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG
394                                           : STATE_CONSTRUCTED;
395    return OK;
396}
397
398status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) {
399
400    status_t res;
401    int32_t u = 0;
402    res = mConsumer->query(mConsumer.get(),
403            NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u);
404    *usage = u;
405
406    return res;
407}
408
409}; // namespace camera3
410
411}; // namespace android
412