Loading services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp +45 −11 Original line number Original line Diff line number Diff line Loading @@ -275,9 +275,17 @@ status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) { //still attached to the removed surface. //still attached to the removed surface. std::vector<uint64_t> pendingBufferIds; std::vector<uint64_t> pendingBufferIds; auto& outputSlots = *mOutputSlots[gbp]; auto& outputSlots = *mOutputSlots[gbp]; for (const auto &it : outputSlots) { for (size_t i = 0; i < outputSlots.size(); i++) { if (it.get() != nullptr) { if (outputSlots[i] != nullptr) { pendingBufferIds.push_back(it->getId()); pendingBufferIds.push_back(outputSlots[i]->getId()); auto rc = gbp->detachBuffer(i); if (rc != NO_ERROR) { //Buffers that fail to detach here will be scheduled for detach in the //input buffer queue and the rest of the registered outputs instead. //This will help ensure that camera stops accessing buffers that still //can get referenced by the disconnected output. mDetachedBuffers.emplace(outputSlots[i]->getId()); } } } } } mOutputs[surfaceId] = nullptr; mOutputs[surfaceId] = nullptr; Loading Loading @@ -521,10 +529,11 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa uint64_t bufferId = tracker_ptr->getBuffer()->getId(); uint64_t bufferId = tracker_ptr->getBuffer()->getId(); int consumerSlot = -1; int consumerSlot = -1; uint64_t frameNumber; uint64_t frameNumber; for (const auto &it : mInputSlots) { auto inputSlot = mInputSlots.begin(); if (it.second.mGraphicBuffer->getId() == bufferId) { for (; inputSlot != mInputSlots.end(); inputSlot++) { consumerSlot = it.second.mSlot; if (inputSlot->second.mGraphicBuffer->getId() == bufferId) { frameNumber = it.second.mFrameNumber; consumerSlot = inputSlot->second.mSlot; frameNumber = inputSlot->second.mFrameNumber; break; break; } } } } Loading @@ -533,6 +542,12 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa return; return; } } auto detachBuffer = mDetachedBuffers.find(bufferId); bool detach = (detachBuffer != mDetachedBuffers.end()); if (detach) { mDetachedBuffers.erase(detachBuffer); mInputSlots.erase(inputSlot); } // Temporarily unlock mutex to avoid circular lock: // Temporarily unlock mutex to avoid circular lock: // 1. This function holds splitter lock, calls releaseBuffer which triggers // 1. This function holds splitter lock, calls releaseBuffer which triggers // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the Loading @@ -544,17 +559,25 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa mMutex.unlock(); mMutex.unlock(); int res = NO_ERROR; int res = NO_ERROR; if (consumer != nullptr) { if (consumer != nullptr) { if (detach) { res = consumer->detachBuffer(consumerSlot); } else { res = consumer->releaseBuffer(consumerSlot, frameNumber, res = consumer->releaseBuffer(consumerSlot, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence()); EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence()); } } else { } else { SP_LOGE("%s: consumer has become null!", __FUNCTION__); SP_LOGE("%s: consumer has become null!", __FUNCTION__); } } mMutex.lock(); mMutex.lock(); // If the producer of this queue is disconnected, -22 error will occur if (res != NO_ERROR) { if (res != NO_ERROR) { if (detach) { SP_LOGE("%s: detachBuffer returns %d", __FUNCTION__, res); } else { SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res); SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res); } } } } } void Camera3StreamSplitter::onBufferReleasedByOutput( void Camera3StreamSplitter::onBufferReleasedByOutput( const sp<IGraphicBufferProducer>& from) { const sp<IGraphicBufferProducer>& from) { Loading Loading @@ -626,6 +649,17 @@ void Camera3StreamSplitter::onBufferReleasedByOutputLocked( SP_LOGV("%s: dequeued buffer %" PRId64 " %p from output %p", __FUNCTION__, SP_LOGV("%s: dequeued buffer %" PRId64 " %p from output %p", __FUNCTION__, buffer->getId(), buffer.get(), from.get()); buffer->getId(), buffer.get(), from.get()); auto detachBuffer = mDetachedBuffers.find(buffer->getId()); bool detach = (detachBuffer != mDetachedBuffers.end()); if (detach) { res = from->detachBuffer(slot); if (res == NO_ERROR) { outputSlots[slot] = nullptr; } else { SP_LOGE("%s: detach buffer from output failed (%d)", __FUNCTION__, res); } } // Check to see if this is the last outstanding reference to this buffer // Check to see if this is the last outstanding reference to this buffer decrementBufRefCountLocked(buffer->getId(), surfaceId); decrementBufRefCountLocked(buffer->getId(), surfaceId); } } Loading services/camera/libcameraservice/device3/Camera3StreamSplitter.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef ANDROID_SERVERS_STREAMSPLITTER_H #ifndef ANDROID_SERVERS_STREAMSPLITTER_H #define ANDROID_SERVERS_STREAMSPLITTER_H #define ANDROID_SERVERS_STREAMSPLITTER_H #include <unordered_set> #include <gui/IConsumerListener.h> #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> #include <gui/IProducerListener.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferItemConsumer.h> Loading Loading @@ -255,6 +257,10 @@ private: std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>, std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>, GBPHash> mOutputSlots; GBPHash> mOutputSlots; //A set of buffers that could potentially stay in some of the outputs after removal //and therefore should be detached from the input queue. std::unordered_set<uint64_t> mDetachedBuffers; // Latest onFrameAvailable return value // Latest onFrameAvailable return value std::atomic<status_t> mOnFrameAvailableRes{0}; std::atomic<status_t> mOnFrameAvailableRes{0}; Loading Loading
services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp +45 −11 Original line number Original line Diff line number Diff line Loading @@ -275,9 +275,17 @@ status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) { //still attached to the removed surface. //still attached to the removed surface. std::vector<uint64_t> pendingBufferIds; std::vector<uint64_t> pendingBufferIds; auto& outputSlots = *mOutputSlots[gbp]; auto& outputSlots = *mOutputSlots[gbp]; for (const auto &it : outputSlots) { for (size_t i = 0; i < outputSlots.size(); i++) { if (it.get() != nullptr) { if (outputSlots[i] != nullptr) { pendingBufferIds.push_back(it->getId()); pendingBufferIds.push_back(outputSlots[i]->getId()); auto rc = gbp->detachBuffer(i); if (rc != NO_ERROR) { //Buffers that fail to detach here will be scheduled for detach in the //input buffer queue and the rest of the registered outputs instead. //This will help ensure that camera stops accessing buffers that still //can get referenced by the disconnected output. mDetachedBuffers.emplace(outputSlots[i]->getId()); } } } } } mOutputs[surfaceId] = nullptr; mOutputs[surfaceId] = nullptr; Loading Loading @@ -521,10 +529,11 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa uint64_t bufferId = tracker_ptr->getBuffer()->getId(); uint64_t bufferId = tracker_ptr->getBuffer()->getId(); int consumerSlot = -1; int consumerSlot = -1; uint64_t frameNumber; uint64_t frameNumber; for (const auto &it : mInputSlots) { auto inputSlot = mInputSlots.begin(); if (it.second.mGraphicBuffer->getId() == bufferId) { for (; inputSlot != mInputSlots.end(); inputSlot++) { consumerSlot = it.second.mSlot; if (inputSlot->second.mGraphicBuffer->getId() == bufferId) { frameNumber = it.second.mFrameNumber; consumerSlot = inputSlot->second.mSlot; frameNumber = inputSlot->second.mFrameNumber; break; break; } } } } Loading @@ -533,6 +542,12 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa return; return; } } auto detachBuffer = mDetachedBuffers.find(bufferId); bool detach = (detachBuffer != mDetachedBuffers.end()); if (detach) { mDetachedBuffers.erase(detachBuffer); mInputSlots.erase(inputSlot); } // Temporarily unlock mutex to avoid circular lock: // Temporarily unlock mutex to avoid circular lock: // 1. This function holds splitter lock, calls releaseBuffer which triggers // 1. This function holds splitter lock, calls releaseBuffer which triggers // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the Loading @@ -544,17 +559,25 @@ void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfa mMutex.unlock(); mMutex.unlock(); int res = NO_ERROR; int res = NO_ERROR; if (consumer != nullptr) { if (consumer != nullptr) { if (detach) { res = consumer->detachBuffer(consumerSlot); } else { res = consumer->releaseBuffer(consumerSlot, frameNumber, res = consumer->releaseBuffer(consumerSlot, frameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence()); EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence()); } } else { } else { SP_LOGE("%s: consumer has become null!", __FUNCTION__); SP_LOGE("%s: consumer has become null!", __FUNCTION__); } } mMutex.lock(); mMutex.lock(); // If the producer of this queue is disconnected, -22 error will occur if (res != NO_ERROR) { if (res != NO_ERROR) { if (detach) { SP_LOGE("%s: detachBuffer returns %d", __FUNCTION__, res); } else { SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res); SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res); } } } } } void Camera3StreamSplitter::onBufferReleasedByOutput( void Camera3StreamSplitter::onBufferReleasedByOutput( const sp<IGraphicBufferProducer>& from) { const sp<IGraphicBufferProducer>& from) { Loading Loading @@ -626,6 +649,17 @@ void Camera3StreamSplitter::onBufferReleasedByOutputLocked( SP_LOGV("%s: dequeued buffer %" PRId64 " %p from output %p", __FUNCTION__, SP_LOGV("%s: dequeued buffer %" PRId64 " %p from output %p", __FUNCTION__, buffer->getId(), buffer.get(), from.get()); buffer->getId(), buffer.get(), from.get()); auto detachBuffer = mDetachedBuffers.find(buffer->getId()); bool detach = (detachBuffer != mDetachedBuffers.end()); if (detach) { res = from->detachBuffer(slot); if (res == NO_ERROR) { outputSlots[slot] = nullptr; } else { SP_LOGE("%s: detach buffer from output failed (%d)", __FUNCTION__, res); } } // Check to see if this is the last outstanding reference to this buffer // Check to see if this is the last outstanding reference to this buffer decrementBufRefCountLocked(buffer->getId(), surfaceId); decrementBufRefCountLocked(buffer->getId(), surfaceId); } } Loading
services/camera/libcameraservice/device3/Camera3StreamSplitter.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef ANDROID_SERVERS_STREAMSPLITTER_H #ifndef ANDROID_SERVERS_STREAMSPLITTER_H #define ANDROID_SERVERS_STREAMSPLITTER_H #define ANDROID_SERVERS_STREAMSPLITTER_H #include <unordered_set> #include <gui/IConsumerListener.h> #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> #include <gui/IProducerListener.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferItemConsumer.h> Loading Loading @@ -255,6 +257,10 @@ private: std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>, std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>, GBPHash> mOutputSlots; GBPHash> mOutputSlots; //A set of buffers that could potentially stay in some of the outputs after removal //and therefore should be detached from the input queue. std::unordered_set<uint64_t> mDetachedBuffers; // Latest onFrameAvailable return value // Latest onFrameAvailable return value std::atomic<status_t> mOnFrameAvailableRes{0}; std::atomic<status_t> mOnFrameAvailableRes{0}; Loading