blob: c9f43aa74ce6aef6ff75fe43ed864fc2c4b7d571 [file] [log] [blame]
Shuzhen Wang0129d522016-10-30 22:43:41 -07001/*
2 * Copyright 2014,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 <inttypes.h>
18
19#define LOG_TAG "Camera3StreamSplitter"
20#define ATRACE_TAG ATRACE_TAG_CAMERA
21//#define LOG_NDEBUG 0
22
23#include <gui/BufferItem.h>
24#include <gui/IGraphicBufferConsumer.h>
25#include <gui/IGraphicBufferProducer.h>
26#include <gui/BufferQueue.h>
27#include <gui/Surface.h>
28
29#include <ui/GraphicBuffer.h>
30
31#include <binder/ProcessState.h>
32
33#include <utils/Trace.h>
34
35#include "Camera3StreamSplitter.h"
36
37namespace android {
38
39status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
40 uint32_t consumerUsage, size_t hal_max_buffers,
41 sp<Surface>& consumer) {
42 if (consumer != nullptr) {
43 ALOGE("%s: output Surface is not NULL", __FUNCTION__);
44 return BAD_VALUE;
45 }
46
47 Mutex::Autolock lock(mMutex);
48 status_t res = OK;
49
50 if (mOutputs.size() > 0 || mConsumer != nullptr) {
51 ALOGE("%s: StreamSplitter already connected", __FUNCTION__);
52 return BAD_VALUE;
53 }
54
55 // Add output surfaces. This has to be before creating internal buffer queue
56 // in order to get max consumer side buffers.
57 for (size_t i = 0; i < surfaces.size(); i++) {
Shuzhen Wang758c2152017-01-10 18:26:18 -080058 if (surfaces[i] == nullptr) {
59 ALOGE("%s: Fatal: surface is NULL", __FUNCTION__);
60 return BAD_VALUE;
61 }
62 res = addOutputLocked(surfaces[i], hal_max_buffers, OutputType::NonDeferred);
63 if (res != OK) {
64 ALOGE("%s: Failed to add output surface: %s(%d)",
65 __FUNCTION__, strerror(-res), res);
66 return res;
Shuzhen Wang0129d522016-10-30 22:43:41 -070067 }
68 }
69
70 // Create buffer queue for input
71 BufferQueue::createBufferQueue(&mProducer, &mConsumer);
72
73 mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
74 mMaxConsumerBuffers);
75 if (mBufferItemConsumer == nullptr) {
76 return NO_MEMORY;
77 }
78 mConsumer->setConsumerName(getUniqueConsumerName());
79
80 mSurface = new Surface(mProducer);
81 if (mSurface == nullptr) {
82 return NO_MEMORY;
83 }
84 consumer = mSurface;
85
86 res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
87
88 return res;
89}
90
91void Camera3StreamSplitter::disconnect() {
92 Mutex::Autolock lock(mMutex);
93
94 for (auto& output : mOutputs) {
95 output->disconnect(NATIVE_WINDOW_API_CAMERA);
96 }
97 mOutputs.clear();
98
99 if (mConsumer != nullptr) {
100 mConsumer->consumerDisconnect();
101 mConsumer.clear();
102 }
103
104 if (mBuffers.size() > 0) {
105 ALOGI("%zu buffers still being tracked", mBuffers.size());
106 }
107}
108
109Camera3StreamSplitter::~Camera3StreamSplitter() {
110 disconnect();
111}
112
113status_t Camera3StreamSplitter::addOutput(
Shuzhen Wang758c2152017-01-10 18:26:18 -0800114 const sp<Surface>& outputQueue, size_t hal_max_buffers) {
Shuzhen Wang0129d522016-10-30 22:43:41 -0700115 Mutex::Autolock lock(mMutex);
116 return addOutputLocked(outputQueue, hal_max_buffers, OutputType::Deferred);
117}
118
119status_t Camera3StreamSplitter::addOutputLocked(
120 const sp<Surface>& outputQueue, size_t hal_max_buffers,
121 OutputType outputType) {
122 if (outputQueue == nullptr) {
123 ALOGE("addOutput: outputQueue must not be NULL");
124 return BAD_VALUE;
125 }
126 if (hal_max_buffers < 1) {
127 ALOGE("%s: Camera HAL requested max_buffer count: %zu, requires at least 1",
128 __FUNCTION__, hal_max_buffers);
129 return BAD_VALUE;
130 }
131
132 sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
133 // Connect to the buffer producer
134 IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
135 sp<OutputListener> listener(new OutputListener(this, gbp));
136 IInterface::asBinder(gbp)->linkToDeath(listener);
137 status_t status = gbp->connect(listener, NATIVE_WINDOW_API_CAMERA,
138 /* producerControlledByApp */ true, &queueBufferOutput);
139 if (status != NO_ERROR) {
140 ALOGE("addOutput: failed to connect (%d)", status);
141 return status;
142 }
143
144 // Query consumer side buffer count, and update overall buffer count
145 int maxConsumerBuffers = 0;
146 status = static_cast<ANativeWindow*>(outputQueue.get())->query(
147 outputQueue.get(),
148 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
149 if (status != OK) {
150 ALOGE("%s: Unable to query consumer undequeued buffer count"
151 " for surface", __FUNCTION__);
152 return status;
153 }
154
155 if (maxConsumerBuffers > mMaxConsumerBuffers) {
156 if (outputType == OutputType::Deferred) {
157 ALOGE("%s: Fatal: Deferred surface has higher consumer buffer count"
158 " %d than what's already configured %d", __FUNCTION__,
159 maxConsumerBuffers, mMaxConsumerBuffers);
160 return BAD_VALUE;
161 }
162 mMaxConsumerBuffers = maxConsumerBuffers;
163 }
164
165 ALOGV("%s: Consumer wants %d buffers, HAL wants %zu", __FUNCTION__,
166 maxConsumerBuffers, hal_max_buffers);
167 size_t totalBufferCount = maxConsumerBuffers + hal_max_buffers;
168 status = native_window_set_buffer_count(outputQueue.get(),
169 totalBufferCount);
170 if (status != OK) {
171 ALOGE("%s: Unable to set buffer count for surface %p",
172 __FUNCTION__, outputQueue.get());
173 return status;
174 }
175
176 // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
177 // We need skip these cases as timeout will disable the non-blocking (async) mode.
178 int32_t usage = 0;
179 static_cast<ANativeWindow*>(outputQueue.get())->query(
180 outputQueue.get(),
181 NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
182 if (!(usage & (GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE))) {
183 outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
184 }
185
186 status = gbp->allowAllocation(false);
187 if (status != OK) {
188 ALOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
189 return status;
190 }
191
192 // Add new entry into mOutputs
193 mOutputs.push_back(gbp);
194 return NO_ERROR;
195}
196
197String8 Camera3StreamSplitter::getUniqueConsumerName() {
198 static volatile int32_t counter = 0;
199 return String8::format("Camera3StreamSplitter-%d", android_atomic_inc(&counter));
200}
201
202status_t Camera3StreamSplitter::notifyRequestedSurfaces(
203 const std::vector<size_t>& surfaces) {
204 ATRACE_CALL();
205 Mutex::Autolock lock(mMutex);
206
207 mRequestedSurfaces.push_back(surfaces);
208 return OK;
209}
210
211
212void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /* item */) {
213 ATRACE_CALL();
214 Mutex::Autolock lock(mMutex);
215
216 // The current policy is that if any one consumer is consuming buffers too
217 // slowly, the splitter will stall the rest of the outputs by not acquiring
218 // any more buffers from the input. This will cause back pressure on the
219 // input queue, slowing down its producer.
220
221 // If there are too many outstanding buffers, we block until a buffer is
222 // released back to the input in onBufferReleased
223 while (mOutstandingBuffers >= mMaxConsumerBuffers) {
224 mReleaseCondition.wait(mMutex);
225
226 // If the splitter is abandoned while we are waiting, the release
227 // condition variable will be broadcast, and we should just return
228 // without attempting to do anything more (since the input queue will
229 // also be abandoned).
230 if (mIsAbandoned) {
231 return;
232 }
233 }
234 // If the splitter is abandoned without reaching mMaxConsumerBuffers, just
235 // return without attempting to do anything more.
236 if (mIsAbandoned) {
237 return;
238 }
239
240 ++mOutstandingBuffers;
241
242 // Acquire and detach the buffer from the input
243 BufferItem bufferItem;
244 status_t status = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
245 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
246 "acquiring buffer from input failed (%d)", status);
247
248 ALOGV("acquired buffer %#" PRIx64 " from input",
249 bufferItem.mGraphicBuffer->getId());
250
251 status = mConsumer->detachBuffer(bufferItem.mSlot);
252 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
253 "detaching buffer from input failed (%d)", status);
254
255 IGraphicBufferProducer::QueueBufferInput queueInput(
256 bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
257 bufferItem.mDataSpace, bufferItem.mCrop,
258 static_cast<int32_t>(bufferItem.mScalingMode),
259 bufferItem.mTransform, bufferItem.mFence);
260
261 // Attach and queue the buffer to each of the outputs
262 std::vector<std::vector<size_t> >::iterator surfaces = mRequestedSurfaces.begin();
263 if (surfaces != mRequestedSurfaces.end()) {
264
265 LOG_ALWAYS_FATAL_IF(surfaces->size() == 0,
266 "requested surface ids shouldn't be empty");
267
268 // Initialize our reference count for this buffer
269 mBuffers[bufferItem.mGraphicBuffer->getId()] =
270 std::unique_ptr<BufferTracker>(
271 new BufferTracker(bufferItem.mGraphicBuffer, surfaces->size()));
272
273 for (auto id : *surfaces) {
274
275 LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
276 "requested surface id exceeding max registered ids");
277
278 int slot = BufferItem::INVALID_BUFFER_SLOT;
279 status = mOutputs[id]->attachBuffer(&slot, bufferItem.mGraphicBuffer);
280 if (status == NO_INIT) {
281 // If we just discovered that this output has been abandoned, note
282 // that, decrement the reference count so that we still release this
283 // buffer eventually, and move on to the next output
284 onAbandonedLocked();
285 mBuffers[bufferItem.mGraphicBuffer->getId()]->
286 decrementReferenceCountLocked();
287 continue;
288 } else if (status == WOULD_BLOCK) {
289 // If the output is async, attachBuffer may return WOULD_BLOCK
290 // indicating number of dequeued buffers has reached limit. In
291 // this case, simply decrement the reference count, and move on
292 // to the next output.
293 // TODO: Do we need to report BUFFER_ERROR for this result?
294 mBuffers[bufferItem.mGraphicBuffer->getId()]->
295 decrementReferenceCountLocked();
296 continue;
297 } else if (status == TIMED_OUT) {
298 // If attachBuffer times out due to the value set by
299 // setDequeueTimeout, simply decrement the reference count, and
300 // move on to the next output.
301 // TODO: Do we need to report BUFFER_ERROR for this result?
302 mBuffers[bufferItem.mGraphicBuffer->getId()]->
303 decrementReferenceCountLocked();
304 continue;
305 } else {
306 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
307 "attaching buffer to output failed (%d)", status);
308 }
309
310 IGraphicBufferProducer::QueueBufferOutput queueOutput;
311 status = mOutputs[id]->queueBuffer(slot, queueInput, &queueOutput);
312 if (status == NO_INIT) {
313 // If we just discovered that this output has been abandoned, note
314 // that, increment the release count so that we still release this
315 // buffer eventually, and move on to the next output
316 onAbandonedLocked();
317 mBuffers[bufferItem.mGraphicBuffer->getId()]->
318 decrementReferenceCountLocked();
319 continue;
320 } else {
321 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
322 "queueing buffer to output failed (%d)", status);
323 }
324
Shuzhen Wanga141c5f2017-01-24 14:51:37 -0800325 // If the queued buffer replaces a pending buffer in the async
326 // queue, no onBufferReleased is called by the buffer queue.
327 // Proactively trigger the callback to avoid buffer loss.
328 if (queueOutput.bufferReplaced) {
329 onBufferReleasedByOutputLocked(mOutputs[id]);
330 }
331
Shuzhen Wang0129d522016-10-30 22:43:41 -0700332 ALOGV("queued buffer %#" PRIx64 " to output %p",
333 bufferItem.mGraphicBuffer->getId(), mOutputs[id].get());
334 }
335
336 mRequestedSurfaces.erase(surfaces);
337 }
338}
339
340void Camera3StreamSplitter::onBufferReleasedByOutput(
341 const sp<IGraphicBufferProducer>& from) {
342 ATRACE_CALL();
343 Mutex::Autolock lock(mMutex);
344
Shuzhen Wanga141c5f2017-01-24 14:51:37 -0800345 onBufferReleasedByOutputLocked(from);
346}
347
348void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
349 const sp<IGraphicBufferProducer>& from) {
350
Shuzhen Wang0129d522016-10-30 22:43:41 -0700351 sp<GraphicBuffer> buffer;
352 sp<Fence> fence;
353 status_t status = from->detachNextBuffer(&buffer, &fence);
354 if (status == NO_INIT) {
355 // If we just discovered that this output has been abandoned, note that,
356 // but we can't do anything else, since buffer is invalid
357 onAbandonedLocked();
358 return;
359 } else {
360 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
361 "detaching buffer from output failed (%d)", status);
362 }
363
364 ALOGV("detached buffer %#" PRIx64 " from output %p",
365 buffer->getId(), from.get());
366
367 BufferTracker& tracker = *(mBuffers[buffer->getId()]);
368
369 // Merge the release fence of the incoming buffer so that the fence we send
370 // back to the input includes all of the outputs' fences
371 tracker.mergeFence(fence);
372
373 // Check to see if this is the last outstanding reference to this buffer
374 size_t referenceCount = tracker.decrementReferenceCountLocked();
375 ALOGV("buffer %#" PRIx64 " reference count %zu", buffer->getId(),
376 referenceCount);
377 if (referenceCount > 0) {
378 return;
379 }
380
381 // If we've been abandoned, we can't return the buffer to the input, so just
382 // stop tracking it and move on
383 if (mIsAbandoned) {
384 mBuffers.erase(buffer->getId());
385 return;
386 }
387
388 // Attach and release the buffer back to the input
389 int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
390 status = mConsumer->attachBuffer(&consumerSlot, tracker.getBuffer());
391 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
392 "attaching buffer to input failed (%d)", status);
393
394 status = mConsumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
395 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker.getMergedFence());
396 LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
397 "releasing buffer to input failed (%d)", status);
398
399 ALOGV("released buffer %#" PRIx64 " to input", buffer->getId());
400
401 // We no longer need to track the buffer once it has been returned to the
402 // input
403 mBuffers.erase(buffer->getId());
404
405 // Notify any waiting onFrameAvailable calls
406 --mOutstandingBuffers;
407 mReleaseCondition.signal();
408}
409
410void Camera3StreamSplitter::onAbandonedLocked() {
411 ALOGE("one of my outputs has abandoned me");
412 if (!mIsAbandoned && mConsumer != nullptr) {
413 mConsumer->consumerDisconnect();
414 }
415 mIsAbandoned = true;
416 mReleaseCondition.broadcast();
417}
418
419Camera3StreamSplitter::OutputListener::OutputListener(
420 wp<Camera3StreamSplitter> splitter,
421 wp<IGraphicBufferProducer> output)
422 : mSplitter(splitter), mOutput(output) {}
423
424void Camera3StreamSplitter::OutputListener::onBufferReleased() {
425 sp<Camera3StreamSplitter> splitter = mSplitter.promote();
426 sp<IGraphicBufferProducer> output = mOutput.promote();
427 if (splitter != nullptr && output != nullptr) {
428 splitter->onBufferReleasedByOutput(output);
429 }
430}
431
432void Camera3StreamSplitter::OutputListener::binderDied(const wp<IBinder>& /* who */) {
433 sp<Camera3StreamSplitter> splitter = mSplitter.promote();
434 if (splitter != nullptr) {
435 Mutex::Autolock lock(splitter->mMutex);
436 splitter->onAbandonedLocked();
437 }
438}
439
440Camera3StreamSplitter::BufferTracker::BufferTracker(
441 const sp<GraphicBuffer>& buffer, size_t referenceCount)
442 : mBuffer(buffer), mMergedFence(Fence::NO_FENCE),
443 mReferenceCount(referenceCount) {}
444
445void Camera3StreamSplitter::BufferTracker::mergeFence(const sp<Fence>& with) {
446 mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
447}
448
449size_t Camera3StreamSplitter::BufferTracker::decrementReferenceCountLocked() {
450 if (mReferenceCount > 0)
451 --mReferenceCount;
452 return mReferenceCount;
453}
454
455} // namespace android