1 /*
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 #define LOG_TAG "Camera3StreamSplitter"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20
21 #include <binder/ProcessState.h>
22 #include <camera/StringUtils.h>
23 #include <com_android_graphics_libgui_flags.h>
24 #include <gui/BufferItem.h>
25 #include <gui/BufferItemConsumer.h>
26 #include <gui/BufferQueue.h>
27 #include <gui/IGraphicBufferConsumer.h>
28 #include <gui/IGraphicBufferProducer.h>
29 #include <gui/Surface.h>
30 #include <system/window.h>
31 #include <ui/GraphicBuffer.h>
32 #include <utils/Trace.h>
33
34 #include <cutils/atomic.h>
35 #include <inttypes.h>
36 #include <algorithm>
37 #include <cstdint>
38 #include <memory>
39
40 #include "Camera3Stream.h"
41 #include "Flags.h"
42
43 #include "Camera3StreamSplitter.h"
44
45 // We're relying on a large number of yet-to-be-fully-launched flag dependencies
46 // here. So instead of flagging each one, we flag the entire implementation to
47 // improve legibility.
48 #if USE_NEW_STREAM_SPLITTER
49
50 namespace android {
51
connect(const std::unordered_map<size_t,sp<Surface>> & surfaces,uint64_t consumerUsage,uint64_t producerUsage,size_t halMaxBuffers,uint32_t width,uint32_t height,android::PixelFormat format,sp<Surface> * consumer,int64_t dynamicRangeProfile)52 status_t Camera3StreamSplitter::connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
53 uint64_t consumerUsage, uint64_t producerUsage, size_t halMaxBuffers, uint32_t width,
54 uint32_t height, android::PixelFormat format, sp<Surface>* consumer,
55 int64_t dynamicRangeProfile) {
56 ATRACE_CALL();
57 if (consumer == nullptr) {
58 SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
59 return BAD_VALUE;
60 }
61
62 Mutex::Autolock lock(mMutex);
63 status_t res = OK;
64
65 if (mOutputSurfaces.size() > 0 || mBufferItemConsumer != nullptr) {
66 SP_LOGE("%s: already connected", __FUNCTION__);
67 return BAD_VALUE;
68 }
69 if (mBuffers.size() > 0) {
70 SP_LOGE("%s: still has %zu pending buffers", __FUNCTION__, mBuffers.size());
71 return BAD_VALUE;
72 }
73
74 mMaxHalBuffers = halMaxBuffers;
75 mConsumerName = getUniqueConsumerName();
76 mDynamicRangeProfile = dynamicRangeProfile;
77 // Add output surfaces. This has to be before creating internal buffer queue
78 // in order to get max consumer side buffers.
79 for (auto &it : surfaces) {
80 if (it.second == nullptr) {
81 SP_LOGE("%s: Fatal: surface is NULL", __FUNCTION__);
82 return BAD_VALUE;
83 }
84 res = addOutputLocked(it.first, it.second);
85 if (res != OK) {
86 SP_LOGE("%s: Failed to add output surface: %s(%d)",
87 __FUNCTION__, strerror(-res), res);
88 return res;
89 }
90 }
91
92 // Allocate 1 extra buffer to handle the case where all buffers are detached
93 // from input, and attached to the outputs. In this case, the input queue's
94 // dequeueBuffer can still allocate 1 extra buffer before being blocked by
95 // the output's attachBuffer().
96 mMaxConsumerBuffers++;
97
98 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
99 mBufferItemConsumer = sp<BufferItemConsumer>::make(consumerUsage, mMaxConsumerBuffers);
100 mSurface = mBufferItemConsumer->getSurface();
101 #else
102 // Create BufferQueue for input
103 sp<IGraphicBufferProducer> bqProducer;
104 sp<IGraphicBufferConsumer> bqConsumer;
105 BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
106
107 mBufferItemConsumer = new BufferItemConsumer(bqConsumer, consumerUsage, mMaxConsumerBuffers);
108 mSurface = new Surface(bqProducer);
109 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
110
111 if (mBufferItemConsumer == nullptr) {
112 return NO_MEMORY;
113 }
114 mBufferItemConsumer->setName(toString8(mConsumerName));
115
116 *consumer = mSurface;
117 if (*consumer == nullptr) {
118 return NO_MEMORY;
119 }
120
121 res = mSurface->setAsyncMode(true);
122 if (res != OK) {
123 SP_LOGE("%s: Failed to enable input queue async mode: %s(%d)", __FUNCTION__,
124 strerror(-res), res);
125 return res;
126 }
127
128 mBufferItemConsumer->setFrameAvailableListener(this);
129
130 mWidth = width;
131 mHeight = height;
132 mFormat = format;
133 mProducerUsage = producerUsage;
134 mAcquiredInputBuffers = 0;
135
136 SP_LOGV("%s: connected", __FUNCTION__);
137 return res;
138 }
139
getOnFrameAvailableResult()140 status_t Camera3StreamSplitter::getOnFrameAvailableResult() {
141 ATRACE_CALL();
142 return mOnFrameAvailableRes.load();
143 }
144
disconnect()145 void Camera3StreamSplitter::disconnect() {
146 ATRACE_CALL();
147 Mutex::Autolock lock(mMutex);
148
149 mNotifiers.clear();
150
151 for (auto& output : mOutputSurfaces) {
152 if (output.second != nullptr) {
153 output.second->disconnect(NATIVE_WINDOW_API_CAMERA);
154 }
155 }
156 mOutputSurfaces.clear();
157 mHeldBuffers.clear();
158 mConsumerBufferCount.clear();
159
160 if (mBufferItemConsumer != nullptr) {
161 mBufferItemConsumer->abandon();
162 }
163
164 if (mBuffers.size() > 0) {
165 SP_LOGW("%zu buffers still being tracked", mBuffers.size());
166 mBuffers.clear();
167 }
168
169 mMaxHalBuffers = 0;
170 mMaxConsumerBuffers = 0;
171 mAcquiredInputBuffers = 0;
172 SP_LOGV("%s: Disconnected", __FUNCTION__);
173 }
174
Camera3StreamSplitter(bool useHalBufManager)175 Camera3StreamSplitter::Camera3StreamSplitter(bool useHalBufManager) :
176 mUseHalBufManager(useHalBufManager) {}
177
~Camera3StreamSplitter()178 Camera3StreamSplitter::~Camera3StreamSplitter() {
179 disconnect();
180 }
181
addOutput(size_t surfaceId,const sp<Surface> & outputQueue)182 status_t Camera3StreamSplitter::addOutput(size_t surfaceId, const sp<Surface>& outputQueue) {
183 ATRACE_CALL();
184 Mutex::Autolock lock(mMutex);
185 status_t res = addOutputLocked(surfaceId, outputQueue);
186
187 if (res != OK) {
188 SP_LOGE("%s: addOutputLocked failed %d", __FUNCTION__, res);
189 return res;
190 }
191
192 if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
193 res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
194 }
195
196 return res;
197 }
198
setHalBufferManager(bool enabled)199 void Camera3StreamSplitter::setHalBufferManager(bool enabled) {
200 Mutex::Autolock lock(mMutex);
201 mUseHalBufManager = enabled;
202 }
203
setTransform(size_t surfaceId,int transform)204 status_t Camera3StreamSplitter::setTransform(size_t surfaceId, int transform) {
205 Mutex::Autolock lock(mMutex);
206 if (!mOutputSurfaces.contains(surfaceId) || mOutputSurfaces[surfaceId] == nullptr) {
207 SP_LOGE("%s: No surface at id %zu", __FUNCTION__, surfaceId);
208 return BAD_VALUE;
209 }
210
211 mOutputTransforms[surfaceId] = transform;
212 return OK;
213 }
214
addOutputLocked(size_t surfaceId,const sp<Surface> & outputQueue)215 status_t Camera3StreamSplitter::addOutputLocked(size_t surfaceId, const sp<Surface>& outputQueue) {
216 ATRACE_CALL();
217 if (outputQueue == nullptr) {
218 SP_LOGE("addOutput: outputQueue must not be NULL");
219 return BAD_VALUE;
220 }
221
222 if (mOutputSurfaces[surfaceId] != nullptr) {
223 SP_LOGE("%s: surfaceId: %u already taken!", __FUNCTION__, (unsigned) surfaceId);
224 return BAD_VALUE;
225 }
226
227 status_t res = native_window_set_buffers_dimensions(outputQueue.get(),
228 mWidth, mHeight);
229 if (res != NO_ERROR) {
230 SP_LOGE("addOutput: failed to set buffer dimensions (%d)", res);
231 return res;
232 }
233 res = native_window_set_buffers_format(outputQueue.get(),
234 mFormat);
235 if (res != OK) {
236 ALOGE("%s: Unable to configure stream buffer format %#x for surfaceId %zu",
237 __FUNCTION__, mFormat, surfaceId);
238 return res;
239 }
240
241 // Connect to the buffer producer
242 sp<OutputListener> listener = sp<OutputListener>::make(this, outputQueue);
243 res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener, /* reportBufferRemoval */ false);
244 if (res != NO_ERROR) {
245 SP_LOGE("addOutput: failed to connect (%d)", res);
246 return res;
247 }
248
249 // Query consumer side buffer count, and update overall buffer count
250 int maxConsumerBuffers = 0;
251 res = static_cast<ANativeWindow*>(outputQueue.get())->query(
252 outputQueue.get(),
253 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
254 if (res != OK) {
255 SP_LOGE("%s: Unable to query consumer undequeued buffer count"
256 " for surface", __FUNCTION__);
257 return res;
258 }
259
260 SP_LOGV("%s: Consumer wants %d buffers, Producer wants %zu", __FUNCTION__,
261 maxConsumerBuffers, mMaxHalBuffers);
262 // The output slot count requirement can change depending on the current amount
263 // of outputs and incoming buffer consumption rate. To avoid any issues with
264 // insufficient slots, set their count to the maximum supported. The output
265 // surface buffer allocation is disabled so no real buffers will get allocated.
266 size_t totalBufferCount = BufferQueue::NUM_BUFFER_SLOTS;
267 res = native_window_set_buffer_count(outputQueue.get(),
268 totalBufferCount);
269 if (res != OK) {
270 SP_LOGE("%s: Unable to set buffer count for surface %p",
271 __FUNCTION__, outputQueue.get());
272 return res;
273 }
274
275 // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
276 // We need skip these cases as timeout will disable the non-blocking (async) mode.
277 uint64_t usage = 0;
278 res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(outputQueue.get()), &usage);
279 if (!(usage & (GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE))) {
280 nsecs_t timeout = mUseHalBufManager ?
281 kHalBufMgrDequeueBufferTimeout : kNormalDequeueBufferTimeout;
282 outputQueue->setDequeueTimeout(timeout);
283 }
284
285 res = outputQueue->allowAllocation(false);
286 if (res != OK) {
287 SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
288 return res;
289 }
290
291 // Add new entry into mOutputs
292 mOutputSurfaces[surfaceId] = outputQueue;
293 mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
294 if (mConsumerBufferCount[surfaceId] > mMaxHalBuffers) {
295 SP_LOGW("%s: Consumer buffer count %zu larger than max. Hal buffers: %zu", __FUNCTION__,
296 mConsumerBufferCount[surfaceId], mMaxHalBuffers);
297 }
298 mNotifiers[outputQueue] = listener;
299 mHeldBuffers[outputQueue] = std::make_unique<HeldBuffers>(totalBufferCount);
300
301 mMaxConsumerBuffers += maxConsumerBuffers;
302 return NO_ERROR;
303 }
304
removeOutput(size_t surfaceId)305 status_t Camera3StreamSplitter::removeOutput(size_t surfaceId) {
306 ATRACE_CALL();
307 Mutex::Autolock lock(mMutex);
308
309 status_t res = removeOutputLocked(surfaceId);
310 if (res != OK) {
311 SP_LOGE("%s: removeOutputLocked failed %d", __FUNCTION__, res);
312 return res;
313 }
314
315 if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
316 res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
317 if (res != OK) {
318 SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
319 return res;
320 }
321 }
322
323 return res;
324 }
325
removeOutputLocked(size_t surfaceId)326 status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) {
327 if (mOutputSurfaces[surfaceId] == nullptr) {
328 SP_LOGE("%s: output surface is not present!", __FUNCTION__);
329 return BAD_VALUE;
330 }
331
332 sp<Surface> surface = mOutputSurfaces[surfaceId];
333 //Search and decrement the ref. count of any buffers that are
334 //still attached to the removed surface.
335 std::vector<uint64_t> pendingBufferIds;
336
337 // TODO: can we simplify this to just use the tracker?
338 for (const auto& buffer : (*mHeldBuffers[surface])) {
339 pendingBufferIds.push_back(buffer->getId());
340 auto rc = surface->detachBuffer(buffer);
341 if (rc != NO_ERROR) {
342 // Buffers that fail to detach here will be scheduled for detach in the
343 // input buffer queue and the rest of the registered outputs instead.
344 // This will help ensure that camera stops accessing buffers that still
345 // can get referenced by the disconnected output.
346 mDetachedBuffers.emplace(buffer->getId());
347 }
348 }
349 mOutputSurfaces[surfaceId] = nullptr;
350 mHeldBuffers[surface] = nullptr;
351 for (const auto &id : pendingBufferIds) {
352 decrementBufRefCountLocked(id, surfaceId);
353 }
354
355 status_t res = surface->disconnect(NATIVE_WINDOW_API_CAMERA);
356 if (res != OK) {
357 SP_LOGE("%s: Unable disconnect from producer interface: %d ", __FUNCTION__, res);
358 return res;
359 }
360
361 mNotifiers[surface] = nullptr;
362 mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
363 mConsumerBufferCount[surfaceId] = 0;
364
365 return res;
366 }
367
outputBufferLocked(const sp<Surface> & output,const BufferItem & bufferItem,size_t surfaceId)368 status_t Camera3StreamSplitter::outputBufferLocked(const sp<Surface>& output,
369 const BufferItem& bufferItem, size_t surfaceId) {
370 ATRACE_CALL();
371 status_t res;
372
373 uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
374 const BufferTracker& tracker = *(mBuffers[bufferId]);
375
376 if (mOutputSurfaces[surfaceId] != nullptr) {
377 sp<ANativeWindow> anw = mOutputSurfaces[surfaceId];
378 camera3::Camera3Stream::queueHDRMetadata(
379 bufferItem.mGraphicBuffer->getNativeBuffer()->handle, anw, mDynamicRangeProfile);
380 } else {
381 SP_LOGE("%s: Invalid surface id: %zu!", __FUNCTION__, surfaceId);
382 }
383
384 output->setBuffersTimestamp(bufferItem.mTimestamp);
385 output->setBuffersDataSpace(static_cast<ui::Dataspace>(bufferItem.mDataSpace));
386 output->setCrop(&bufferItem.mCrop);
387 output->setScalingMode(bufferItem.mScalingMode);
388
389 int transform = bufferItem.mTransform;
390 if (mOutputTransforms.contains(surfaceId)) {
391 transform = mOutputTransforms[surfaceId];
392 }
393 output->setBuffersTransform(transform);
394
395 // In case the output BufferQueue has its own lock, if we hold splitter lock while calling
396 // queueBuffer (which will try to acquire the output lock), the output could be holding its
397 // own lock calling releaseBuffer (which will try to acquire the splitter lock), running into
398 // circular lock situation.
399 mMutex.unlock();
400 SurfaceQueueBufferOutput queueBufferOutput;
401 res = output->queueBuffer(bufferItem.mGraphicBuffer, bufferItem.mFence, &queueBufferOutput);
402 mMutex.lock();
403
404 SP_LOGV("%s: Queuing buffer to buffer queue %p bufferId %" PRIu64 " returns %d", __FUNCTION__,
405 output.get(), bufferId, res);
406 // During buffer queue 'mMutex' is not held which makes the removal of
407 // "output" possible. Check whether this is the case and return.
408 if (mOutputSurfaces[surfaceId] == nullptr) {
409 return res;
410 }
411 if (res != OK) {
412 if (res != NO_INIT && res != DEAD_OBJECT) {
413 SP_LOGE("Queuing buffer to output failed (%d)", res);
414 }
415 // If we just discovered that this output has been abandoned, note
416 // that, increment the release count so that we still release this
417 // buffer eventually, and move on to the next output
418 onAbandonedLocked();
419 decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), surfaceId);
420 return res;
421 }
422
423 // If the queued buffer replaces a pending buffer in the async
424 // queue, no onBufferReleased is called by the buffer queue.
425 // Proactively trigger the callback to avoid buffer loss.
426 if (queueBufferOutput.bufferReplaced) {
427 onBufferReplacedLocked(output, surfaceId);
428 }
429
430 return res;
431 }
432
getUniqueConsumerName()433 std::string Camera3StreamSplitter::getUniqueConsumerName() {
434 static volatile int32_t counter = 0;
435 return fmt::sprintf("Camera3StreamSplitter-%d", android_atomic_inc(&counter));
436 }
437
notifyBufferReleased(const sp<GraphicBuffer> & buffer)438 status_t Camera3StreamSplitter::notifyBufferReleased(const sp<GraphicBuffer>& buffer) {
439 ATRACE_CALL();
440
441 Mutex::Autolock lock(mMutex);
442
443 uint64_t bufferId = buffer->getId();
444 std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[bufferId]);
445 mBuffers.erase(bufferId);
446
447 return OK;
448 }
449
attachBufferToOutputs(ANativeWindowBuffer * anb,const std::vector<size_t> & surface_ids)450 status_t Camera3StreamSplitter::attachBufferToOutputs(ANativeWindowBuffer* anb,
451 const std::vector<size_t>& surface_ids) {
452 ATRACE_CALL();
453 status_t res = OK;
454
455 Mutex::Autolock lock(mMutex);
456
457 sp<GraphicBuffer> gb(static_cast<GraphicBuffer*>(anb));
458 uint64_t bufferId = gb->getId();
459
460 // Initialize buffer tracker for this input buffer
461 auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
462
463 for (auto& surface_id : surface_ids) {
464 sp<Surface>& surface = mOutputSurfaces[surface_id];
465 if (surface.get() == nullptr) {
466 //Output surface got likely removed by client.
467 continue;
468 }
469
470 //Temporarly Unlock the mutex when trying to attachBuffer to the output
471 //queue, because attachBuffer could block in case of a slow consumer. If
472 //we block while holding the lock, onFrameAvailable and onBufferReleased
473 //will block as well because they need to acquire the same lock.
474 mMutex.unlock();
475 res = surface->attachBuffer(anb);
476 mMutex.lock();
477 if (res != OK) {
478 SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)", __FUNCTION__,
479 surface.get(), strerror(-res), res);
480 // TODO: might need to detach/cleanup the already attached buffers before return?
481 return res;
482 }
483 //During buffer attach 'mMutex' is not held which makes the removal of
484 //"gbp" possible. Check whether this is the case and continue.
485 if (mHeldBuffers[surface] == nullptr) {
486 continue;
487 }
488 mHeldBuffers[surface]->insert(gb);
489 SP_LOGV("%s: Attached buffer %p on output %p.", __FUNCTION__, gb.get(), surface.get());
490 }
491
492 mBuffers[bufferId] = std::move(tracker);
493
494 return res;
495 }
496
onFrameAvailable(const BufferItem &)497 void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /*item*/) {
498 ATRACE_CALL();
499 Mutex::Autolock lock(mMutex);
500
501 // Acquire and detach the buffer from the input
502 BufferItem bufferItem;
503 status_t res = mBufferItemConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
504 if (res != NO_ERROR) {
505 SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
506 mOnFrameAvailableRes.store(res);
507 return;
508 }
509
510 uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
511
512 if (mBuffers.find(bufferId) == mBuffers.end()) {
513 SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
514 __FUNCTION__);
515 mOnFrameAvailableRes.store(INVALID_OPERATION);
516 return;
517 }
518
519 mAcquiredInputBuffers++;
520 SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
521 bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
522
523 if (bufferItem.mTransformToDisplayInverse) {
524 bufferItem.mTransform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
525 }
526
527 // Attach and queue the buffer to each of the outputs
528 BufferTracker& tracker = *(mBuffers[bufferId]);
529
530 SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
531 __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
532 for (const auto id : tracker.requestedSurfaces()) {
533 if (mOutputSurfaces[id] == nullptr) {
534 //Output surface got likely removed by client.
535 continue;
536 }
537
538 res = outputBufferLocked(mOutputSurfaces[id], bufferItem, id);
539 if (res != OK) {
540 SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
541 mOnFrameAvailableRes.store(res);
542 // If we fail to send buffer to certain output, keep sending to
543 // other outputs.
544 continue;
545 }
546 }
547
548 mOnFrameAvailableRes.store(res);
549 }
550
onFrameReplaced(const BufferItem & item)551 void Camera3StreamSplitter::onFrameReplaced(const BufferItem& item) {
552 ATRACE_CALL();
553 onFrameAvailable(item);
554 }
555
decrementBufRefCountLocked(uint64_t id,size_t surfaceId)556 void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfaceId) {
557 ATRACE_CALL();
558
559 if (mBuffers[id] == nullptr) {
560 return;
561 }
562
563 size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked(surfaceId);
564 if (referenceCount > 0) {
565 return;
566 }
567
568 // We no longer need to track the buffer now that it is being returned to the
569 // input. Note that this should happen before we unlock the mutex and call
570 // releaseBuffer, to avoid the case where the same bufferId is acquired in
571 // attachBufferToOutputs resulting in a new BufferTracker with same bufferId
572 // overwrites the current one.
573 std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[id]);
574 mBuffers.erase(id);
575
576 uint64_t bufferId = tracker_ptr->getBuffer()->getId();
577
578 auto detachBuffer = mDetachedBuffers.find(bufferId);
579 bool detach = (detachBuffer != mDetachedBuffers.end());
580 if (detach) {
581 mDetachedBuffers.erase(detachBuffer);
582 }
583 // Temporarily unlock mutex to avoid circular lock:
584 // 1. This function holds splitter lock, calls releaseBuffer which triggers
585 // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the
586 // OutputStream lock
587 // 2. Camera3SharedOutputStream::getBufferLocked calls
588 // attachBufferToOutputs, which holds the stream lock, and waits for the
589 // splitter lock.
590 mMutex.unlock();
591 int res = NO_ERROR;
592 if (mBufferItemConsumer != nullptr) {
593 if (detach) {
594 res = mBufferItemConsumer->detachBuffer(tracker_ptr->getBuffer());
595 } else {
596 res = mBufferItemConsumer->releaseBuffer(tracker_ptr->getBuffer(),
597 tracker_ptr->getMergedFence());
598 }
599 } else {
600 SP_LOGE("%s: consumer has become null!", __FUNCTION__);
601 }
602 mMutex.lock();
603
604 if (res != NO_ERROR) {
605 if (detach) {
606 SP_LOGE("%s: detachBuffer returns %d", __FUNCTION__, res);
607 } else {
608 SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
609 }
610 } else {
611 if (mAcquiredInputBuffers == 0) {
612 ALOGW("%s: Acquired input buffer count already at zero!", __FUNCTION__);
613 } else {
614 mAcquiredInputBuffers--;
615 }
616 }
617 }
618
onBufferReleasedByOutput(const sp<Surface> & from)619 void Camera3StreamSplitter::onBufferReleasedByOutput(const sp<Surface>& from) {
620 ATRACE_CALL();
621
622 from->setBuffersDimensions(mWidth, mHeight);
623 from->setBuffersFormat(mFormat);
624 from->setUsage(mProducerUsage);
625
626 sp<GraphicBuffer> buffer;
627 sp<Fence> fence;
628 auto res = from->dequeueBuffer(&buffer, &fence);
629 Mutex::Autolock lock(mMutex);
630 handleOutputDequeueStatusLocked(res, buffer);
631 if (res != OK) {
632 return;
633 }
634
635 size_t surfaceId = 0;
636 bool found = false;
637 for (const auto& it : mOutputSurfaces) {
638 if (it.second == from) {
639 found = true;
640 surfaceId = it.first;
641 break;
642 }
643 }
644 if (!found) {
645 SP_LOGV("%s: output surface not registered anymore!", __FUNCTION__);
646 return;
647 }
648
649 returnOutputBufferLocked(fence, from, surfaceId, buffer);
650 }
651
onBufferReplacedLocked(const sp<Surface> & from,size_t surfaceId)652 void Camera3StreamSplitter::onBufferReplacedLocked(const sp<Surface>& from, size_t surfaceId) {
653 ATRACE_CALL();
654
655 from->setBuffersDimensions(mWidth, mHeight);
656 from->setBuffersFormat(mFormat);
657 from->setUsage(mProducerUsage);
658
659 sp<GraphicBuffer> buffer;
660 sp<Fence> fence;
661 auto res = from->dequeueBuffer(&buffer, &fence);
662 handleOutputDequeueStatusLocked(res, buffer);
663 if (res != OK) {
664 return;
665 }
666
667 returnOutputBufferLocked(fence, from, surfaceId, buffer);
668 }
669
returnOutputBufferLocked(const sp<Fence> & fence,const sp<Surface> & from,size_t surfaceId,const sp<GraphicBuffer> & buffer)670 void Camera3StreamSplitter::returnOutputBufferLocked(const sp<Fence>& fence,
671 const sp<Surface>& from, size_t surfaceId, const sp<GraphicBuffer>& buffer) {
672 BufferTracker& tracker = *(mBuffers[buffer->getId()]);
673 // Merge the release fence of the incoming buffer so that the fence we send
674 // back to the input includes all of the outputs' fences
675 if (fence != nullptr && fence->isValid()) {
676 tracker.mergeFence(fence);
677 }
678
679 auto detachBuffer = mDetachedBuffers.find(buffer->getId());
680 bool detach = (detachBuffer != mDetachedBuffers.end());
681 if (detach) {
682 auto res = from->detachBuffer(buffer);
683 if (res == NO_ERROR) {
684 if (mHeldBuffers.contains(from)) {
685 mHeldBuffers[from]->erase(buffer);
686 } else {
687 uint64_t surfaceId = 0;
688 from->getUniqueId(&surfaceId);
689 SP_LOGW("%s: buffer %" PRIu64 " not found in held buffers of surface %" PRIu64,
690 __FUNCTION__, buffer->getId(), surfaceId);
691 }
692 } else {
693 SP_LOGE("%s: detach buffer from output failed (%d)", __FUNCTION__, res);
694 }
695 }
696
697 // Check to see if this is the last outstanding reference to this buffer
698 decrementBufRefCountLocked(buffer->getId(), surfaceId);
699 }
700
handleOutputDequeueStatusLocked(status_t res,const sp<GraphicBuffer> & buffer)701 void Camera3StreamSplitter::handleOutputDequeueStatusLocked(status_t res,
702 const sp<GraphicBuffer>& buffer) {
703 if (res == NO_INIT) {
704 // If we just discovered that this output has been abandoned, note that,
705 // but we can't do anything else, since buffer is invalid
706 onAbandonedLocked();
707 } else if (res == NO_MEMORY) {
708 SP_LOGE("%s: No free buffers", __FUNCTION__);
709 } else if (res == WOULD_BLOCK) {
710 SP_LOGE("%s: Dequeue call will block", __FUNCTION__);
711 } else if (res != OK || buffer == nullptr) {
712 SP_LOGE("%s: dequeue buffer from output failed (%d)", __FUNCTION__, res);
713 }
714 }
715
onAbandonedLocked()716 void Camera3StreamSplitter::onAbandonedLocked() {
717 // If this is called from binderDied callback, it means the app process
718 // holding the binder has died. CameraService will be notified of the binder
719 // death, and camera device will be closed, which in turn calls
720 // disconnect().
721 //
722 // If this is called from onBufferReleasedByOutput or onFrameAvailable, one
723 // consumer being abanoned shouldn't impact the other consumer. So we won't
724 // stop the buffer flow.
725 //
726 // In both cases, we don't need to do anything here.
727 SP_LOGV("One of my outputs has abandoned me");
728 }
729
OutputListener(wp<Camera3StreamSplitter> splitter,wp<Surface> output)730 Camera3StreamSplitter::OutputListener::OutputListener(wp<Camera3StreamSplitter> splitter,
731 wp<Surface> output)
732 : mSplitter(splitter), mOutput(output) {}
733
onBufferReleased()734 void Camera3StreamSplitter::OutputListener::onBufferReleased() {
735 ATRACE_CALL();
736 sp<Camera3StreamSplitter> splitter = mSplitter.promote();
737 sp<Surface> output = mOutput.promote();
738 if (splitter != nullptr && output != nullptr) {
739 splitter->onBufferReleasedByOutput(output);
740 }
741 }
742
onRemoteDied()743 void Camera3StreamSplitter::OutputListener::onRemoteDied() {
744 sp<Camera3StreamSplitter> splitter = mSplitter.promote();
745 if (splitter != nullptr) {
746 Mutex::Autolock lock(splitter->mMutex);
747 splitter->onAbandonedLocked();
748 }
749 }
750
BufferTracker(const sp<GraphicBuffer> & buffer,const std::vector<size_t> & requestedSurfaces)751 Camera3StreamSplitter::BufferTracker::BufferTracker(
752 const sp<GraphicBuffer>& buffer, const std::vector<size_t>& requestedSurfaces)
753 : mBuffer(buffer), mMergedFence(Fence::NO_FENCE), mRequestedSurfaces(requestedSurfaces),
754 mReferenceCount(requestedSurfaces.size()) {}
755
mergeFence(const sp<Fence> & with)756 void Camera3StreamSplitter::BufferTracker::mergeFence(const sp<Fence>& with) {
757 mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
758 }
759
decrementReferenceCountLocked(size_t surfaceId)760 size_t Camera3StreamSplitter::BufferTracker::decrementReferenceCountLocked(size_t surfaceId) {
761 const auto& it = std::find(mRequestedSurfaces.begin(), mRequestedSurfaces.end(), surfaceId);
762 if (it == mRequestedSurfaces.end()) {
763 return mReferenceCount;
764 } else {
765 mRequestedSurfaces.erase(it);
766 }
767
768 if (mReferenceCount > 0)
769 --mReferenceCount;
770 return mReferenceCount;
771 }
772
773 } // namespace android
774
775 #endif // USE_NEW_STREAM_SPLITTER