1/*
2 * Copyright (C) 2016 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#include "Camera3SharedOutputStream.h"
18
19namespace android {
20
21namespace camera3 {
22
23Camera3SharedOutputStream::Camera3SharedOutputStream(int id,
24        const std::vector<sp<Surface>>& surfaces,
25        uint32_t width, uint32_t height, int format,
26        uint32_t consumerUsage, android_dataspace dataSpace,
27        camera3_stream_rotation_t rotation,
28        nsecs_t timestampOffset, int setId) :
29        Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
30                            format, dataSpace, rotation, consumerUsage,
31                            timestampOffset, setId),
32        mSurfaces(surfaces) {
33}
34
35Camera3SharedOutputStream::~Camera3SharedOutputStream() {
36    disconnectLocked();
37}
38
39status_t Camera3SharedOutputStream::connectStreamSplitterLocked() {
40    status_t res = OK;
41
42    mStreamSplitter = new Camera3StreamSplitter();
43
44    uint32_t usage;
45    getEndpointUsage(&usage);
46
47    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
48    if (res != OK) {
49        ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
50                __FUNCTION__, strerror(-res), res);
51        return res;
52    }
53
54    return res;
55}
56
57status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
58    Mutex::Autolock l(mLock);
59    status_t res = OK;
60    const sp<GraphicBuffer> buffer(static_cast<GraphicBuffer*>(anwBuffer));
61
62    if (mStreamSplitter != nullptr) {
63        res = mStreamSplitter->notifyBufferReleased(buffer);
64    }
65
66    return res;
67}
68
69bool Camera3SharedOutputStream::isConsumerConfigurationDeferred(size_t surface_id) const {
70    Mutex::Autolock l(mLock);
71    return (surface_id >= mSurfaces.size());
72}
73
74status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
75    Mutex::Autolock l(mLock);
76    if (surfaces.size() == 0) {
77        ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
78        return INVALID_OPERATION;
79    }
80
81    status_t ret = OK;
82    for (auto& surface : surfaces) {
83        if (surface == nullptr) {
84            ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
85            return INVALID_OPERATION;
86        }
87
88        mSurfaces.push_back(surface);
89
90        // Only call addOutput if the splitter has been connected.
91        if (mStreamSplitter != nullptr) {
92            ret = mStreamSplitter->addOutput(surface);
93            if (ret != OK) {
94                ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
95                return ret;
96
97            }
98        }
99    }
100    return ret;
101}
102
103status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
104        const std::vector<size_t>& surface_ids) {
105    ANativeWindowBuffer* anb;
106    int fenceFd = -1;
107
108    status_t res;
109    res = getBufferLockedCommon(&anb, &fenceFd);
110    if (res != OK) {
111        return res;
112    }
113
114    // Attach the buffer to the splitter output queues. This could block if
115    // the output queue doesn't have any empty slot. So unlock during the course
116    // of attachBufferToOutputs.
117    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
118    mLock.unlock();
119    res = splitter->attachBufferToOutputs(anb, surface_ids);
120    mLock.lock();
121    if (res != OK) {
122        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
123                __FUNCTION__, mId, strerror(-res), res);
124        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
125        // let prepareNextBuffer handle the error.)
126        if (res == NO_INIT && mState == STATE_CONFIGURED) {
127            mState = STATE_ABANDONED;
128        }
129
130        return res;
131    }
132
133    /**
134     * FenceFD now owned by HAL except in case of error,
135     * in which case we reassign it to acquire_fence
136     */
137    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
138                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
139
140    return OK;
141}
142
143status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
144            ANativeWindowBuffer* buffer, int anwReleaseFence) {
145    status_t res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
146
147    // After queuing buffer to the internal consumer queue, check whether the buffer is
148    // successfully queued to the output queues.
149    if (res == OK) {
150        res = mStreamSplitter->getOnFrameAvailableResult();
151        if (res != OK) {
152            ALOGE("%s: getOnFrameAvailable returns %d", __FUNCTION__, res);
153        }
154    } else {
155        ALOGE("%s: queueBufer failed %d", __FUNCTION__, res);
156    }
157
158    return res;
159}
160
161status_t Camera3SharedOutputStream::configureQueueLocked() {
162    status_t res;
163
164    if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) {
165        return res;
166    }
167
168    res = connectStreamSplitterLocked();
169    if (res != OK) {
170        ALOGE("Cannot connect to stream splitter: %s(%d)", strerror(-res), res);
171        return res;
172    }
173
174    res = configureConsumerQueueLocked();
175    if (res != OK) {
176        ALOGE("Failed to configureConsumerQueueLocked: %s(%d)", strerror(-res), res);
177        return res;
178    }
179
180    return OK;
181}
182
183status_t Camera3SharedOutputStream::disconnectLocked() {
184    status_t res;
185    res = Camera3OutputStream::disconnectLocked();
186
187    if (mStreamSplitter != nullptr) {
188        mStreamSplitter->disconnect();
189    }
190
191    return res;
192}
193
194status_t Camera3SharedOutputStream::getEndpointUsage(uint32_t *usage) const {
195
196    status_t res = OK;
197    uint32_t u = 0;
198
199    if (mConsumer == nullptr) {
200        // Called before shared buffer queue is constructed.
201        *usage = getPresetConsumerUsage();
202
203        for (auto surface : mSurfaces) {
204            if (surface != nullptr) {
205                res = getEndpointUsageForSurface(&u, surface);
206                *usage |= u;
207            }
208        }
209    } else {
210        // Called after shared buffer queue is constructed.
211        res = getEndpointUsageForSurface(&u, mConsumer);
212        *usage |= u;
213    }
214
215    return res;
216}
217
218} // namespace camera3
219
220} // namespace android
221