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