From 40602741ae87e6bf368c17dd28db4d2db344bded Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Mon, 29 Apr 2013 10:31:06 -0700 Subject: camera: Add new RingBufferConsumer to keep a ring buffer of acquired frames Bug: 8563838 Change-Id: I5a95e0be94e5388b30639905efae42d3c3279f72 --- .../libcameraservice/gui/RingBufferConsumer.cpp | 346 +++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 services/camera/libcameraservice/gui/RingBufferConsumer.cpp (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp new file mode 100644 index 0000000..1b2a717 --- /dev/null +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef NDEBUG +#include + +//#define LOG_NDEBUG 0 +#define LOG_TAG "RingBufferConsumer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + +#include + +#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) + +typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; + +namespace android { + +RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage, + int bufferCount) : + ConsumerBase(new BufferQueue(true)), + mBufferCount(bufferCount) +{ + mBufferQueue->setConsumerUsageBits(consumerUsage); + mBufferQueue->setSynchronousMode(true); + mBufferQueue->setMaxAcquiredBufferCount(bufferCount); + + assert(bufferCount > 0); +} + +RingBufferConsumer::~RingBufferConsumer() { +} + +void RingBufferConsumer::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + mName = name; + mBufferQueue->setConsumerName(name); +} + +sp RingBufferConsumer::pinSelectedBuffer( + const RingBufferComparator& filter, + bool waitForFence) { + + sp pinnedBuffer; + + { + List::iterator it, end, accIt; + BufferInfo acc, cur; + BufferInfo* accPtr = NULL; + + Mutex::Autolock _l(mMutex); + + for (it = mBufferItemList.begin(), end = mBufferItemList.end(); + it != end; + ++it) { + + const RingBufferItem& item = *it; + + cur.mCrop = item.mCrop; + cur.mTransform = item.mTransform; + cur.mScalingMode = item.mScalingMode; + cur.mTimestamp = item.mTimestamp; + cur.mFrameNumber = item.mFrameNumber; + cur.mPinned = item.mPinCount > 0; + + int ret = filter.compare(accPtr, &cur); + + if (ret == 0) { + accPtr = NULL; + } else if (ret > 0) { + acc = cur; + accPtr = &acc; + accIt = it; + } // else acc = acc + } + + if (!accPtr) { + return NULL; + } + + pinnedBuffer = new PinnedBufferItem(this, *accIt); + pinBufferLocked(pinnedBuffer->getBufferItem()); + + } // end scope of mMutex autolock + + if (pinnedBuffer != 0) { + BI_LOGV("Pinned buffer frame %lld, timestamp %lld", + pinnedBuffer->getBufferItem().mFrameNumber, + pinnedBuffer->getBufferItem().mTimestamp); + } + + if (waitForFence) { + status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(1000, + "RingBufferConsumer::pinSelectedBuffer"); + if (err != OK) { + BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", + strerror(-err), err); + } + } + + return pinnedBuffer; +} + +status_t RingBufferConsumer::clear() { + + status_t err; + Mutex::Autolock _l(mMutex); + + BI_LOGV("%s", __FUNCTION__); + + // Avoid annoying log warnings by returning early + if (mBufferItemList.size() == 0) { + return OK; + } + + do { + size_t pinnedFrames = 0; + err = releaseOldestBufferLocked(&pinnedFrames); + + if (err == NO_BUFFER_AVAILABLE) { + assert(pinnedFrames == mBufferItemList.size()); + break; + } + + if (err == NOT_ENOUGH_DATA) { + // Fine. Empty buffer item list. + break; + } + + if (err != OK) { + BI_LOGE("Clear failed, could not release buffer"); + return err; + } + + } while(true); + + return OK; +} + +void RingBufferConsumer::pinBufferLocked(const BufferItem& item) { + List::iterator it, end; + + for (it = mBufferItemList.begin(), end = mBufferItemList.end(); + it != end; + ++it) { + + RingBufferItem& find = *it; + if (item.mGraphicBuffer == find.mGraphicBuffer) { + find.mPinCount++; + break; + } + } + + if (it == end) { + BI_LOGE("Failed to pin buffer (timestamp %lld, framenumber %lld)", + item.mTimestamp, item.mFrameNumber); + } +} + +status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) { + status_t err = OK; + + List::iterator it, end, accIt; + + it = mBufferItemList.begin(); + end = mBufferItemList.end(); + accIt = it; + + if (it == end) { + /** + * This is fine. We really care about being able to acquire a buffer + * successfully after this function completes, not about it releasing + * some buffer. + */ + BI_LOGV("%s: No buffers yet acquired, can't release anything", + __FUNCTION__); + return NOT_ENOUGH_DATA; + } + + for (; it != end; ++it) { + RingBufferItem& find = *it; + if (find.mTimestamp < accIt->mTimestamp && find.mPinCount <= 0) { + accIt = it; + } + + if (find.mPinCount > 0 && pinnedFrames != NULL) { + ++(*pinnedFrames); + } + } + + if (accIt != end) { + RingBufferItem& item = *accIt; + + // In case the object was never pinned, pass the acquire fence + // back to the release fence. If the fence was already waited on, + // it'll just be a no-op to wait on it again. + err = addReleaseFenceLocked(item.mBuf, item.mFence); + + if (err != OK) { + BI_LOGE("Failed to add release fence to buffer " + "(timestamp %lld, framenumber %lld", + item.mTimestamp, item.mFrameNumber); + return err; + } + + BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld", + item.mTimestamp, item.mFrameNumber); + + err = releaseBufferLocked(item.mBuf, + EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + if (err != OK) { + BI_LOGE("Failed to release buffer: %s (%d)", + strerror(-err), err); + return err; + } + + BI_LOGV("Buffer timestamp %lld, frame %lld evicted", + item.mTimestamp, item.mFrameNumber); + + size_t currentSize = mBufferItemList.size(); + mBufferItemList.erase(accIt); + assert(mBufferItemList.size() == currentSize - 1); + } else { + BI_LOGW("All buffers pinned, could not find any to release"); + return NO_BUFFER_AVAILABLE; + + } + + return OK; +} + +void RingBufferConsumer::onFrameAvailable() { + status_t err; + + { + Mutex::Autolock _l(mMutex); + + /** + * Release oldest frame + */ + if (mBufferItemList.size() >= (size_t)mBufferCount) { + err = releaseOldestBufferLocked(/*pinnedFrames*/NULL); + assert(err != NOT_ENOUGH_DATA); + + // TODO: implement the case for NO_BUFFER_AVAILABLE + assert(err != NO_BUFFER_AVAILABLE); + if (err != OK) { + return; + } + // TODO: in unpinBuffer rerun this routine if we had buffers + // we could've locked but didn't because there was no space + } + + RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(), + RingBufferItem()); + + /** + * Acquire new frame + */ + err = acquireBufferLocked(&item); + if (err != OK) { + if (err != NO_BUFFER_AVAILABLE) { + BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + } + + mBufferItemList.erase(--mBufferItemList.end()); + return; + } + + BI_LOGV("New buffer acquired (timestamp %lld), " + "buffer items %u out of %d", + item.mTimestamp, + mBufferItemList.size(), mBufferCount); + + item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer; + } // end of mMutex lock + + ConsumerBase::onFrameAvailable(); +} + +void RingBufferConsumer::unpinBuffer(const BufferItem& item) { + Mutex::Autolock _l(mMutex); + + List::iterator it, end, accIt; + + for (it = mBufferItemList.begin(), end = mBufferItemList.end(); + it != end; + ++it) { + + RingBufferItem& find = *it; + if (item.mGraphicBuffer == find.mGraphicBuffer) { + status_t res = addReleaseFenceLocked(item.mBuf, item.mFence); + + if (res != OK) { + BI_LOGE("Failed to add release fence to buffer " + "(timestamp %lld, framenumber %lld", + item.mTimestamp, item.mFrameNumber); + return; + } + + find.mPinCount--; + break; + } + } + + if (it == end) { + BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld", + item.mTimestamp, item.mFrameNumber); + } +} + +status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferSize(w, h); +} + +status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferFormat(defaultFormat); +} + +status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) { + Mutex::Autolock _l(mMutex); + return mBufferQueue->setConsumerUsageBits(usage); +} + +} // namespace android -- cgit v1.1 From 083a08ac82704fdcc37334a4253ff075f703cc87 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Tue, 14 May 2013 16:17:12 -0700 Subject: Camera: don't spam RingBufferConsumer logs in eng builds Bug: 8969579 Change-Id: Ia51d4072725754fd3b6ca028232a605885376287 --- services/camera/libcameraservice/gui/RingBufferConsumer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index 1b2a717..c7790fc 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -14,9 +14,6 @@ * limitations under the License. */ -#undef NDEBUG -#include - //#define LOG_NDEBUG 0 #define LOG_TAG "RingBufferConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -30,6 +27,9 @@ #define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) #define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#undef assert +#define assert(x) ALOG_ASSERT((x), #x) + typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; namespace android { -- cgit v1.1 From d030447b617105b31bf3013e5e4b39d422b53b77 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 15 May 2013 12:59:19 -0700 Subject: stagefright: BufferProducer updates Update BufferQueue and ConsumerBase users to new BufferQueue API, to allow BufferQueue slots to be reused. Buffer consumers generally now need to track the unique frameNumber belonging to each frame acquired if they are using BufferQueue directly. Otherwise, they can simply track the graphicBuffer. Change-Id: I30ee3158cf40fb10bbd085241646d5f1128ee480 Signed-off-by: Lajos Molnar Related-to-bug: 7093648 --- services/camera/libcameraservice/gui/RingBufferConsumer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index cd39bad..dfa1066 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -214,7 +214,11 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) { // In case the object was never pinned, pass the acquire fence // back to the release fence. If the fence was already waited on, // it'll just be a no-op to wait on it again. - err = addReleaseFenceLocked(item.mBuf, item.mFence); + + // item.mGraphicBuffer was populated with the proper graphic-buffer + // at acquire even if it was previously acquired + err = addReleaseFenceLocked(item.mBuf, + item.mGraphicBuffer, item.mFence); if (err != OK) { BI_LOGE("Failed to add release fence to buffer " @@ -226,7 +230,9 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) { BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld", item.mTimestamp, item.mFrameNumber); - err = releaseBufferLocked(item.mBuf, + // item.mGraphicBuffer was populated with the proper graphic-buffer + // at acquire even if it was previously acquired + err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { @@ -310,7 +316,8 @@ void RingBufferConsumer::unpinBuffer(const BufferItem& item) { RingBufferItem& find = *it; if (item.mGraphicBuffer == find.mGraphicBuffer) { - status_t res = addReleaseFenceLocked(item.mBuf, item.mFence); + status_t res = addReleaseFenceLocked(item.mBuf, + item.mGraphicBuffer, item.mFence); if (res != OK) { BI_LOGE("Failed to add release fence to buffer " -- cgit v1.1 From 656e86250cd68f7f362c50a4bc92a865e9deacbe Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 28 Jun 2013 14:03:03 -0700 Subject: Pass additional arg to acquireBuffer calls. Bug 7900302 Change-Id: I30b9cca783e0a48f77035b745b7d5e20edf10f27 --- services/camera/libcameraservice/gui/RingBufferConsumer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index dfa1066..7625735 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -284,7 +284,7 @@ void RingBufferConsumer::onFrameAvailable() { /** * Acquire new frame */ - err = acquireBufferLocked(&item); + err = acquireBufferLocked(&item, 0); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); -- cgit v1.1 From 5e1f08b3917ac7900f8a11118afb7e8bf3e61c64 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 16 Jul 2013 22:54:39 -0700 Subject: update to new Consumer APIs Change-Id: I3c5d4be2a2e8783fbf98b3e268fd02658f71dc7d --- services/camera/libcameraservice/gui/RingBufferConsumer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index 7625735..8141f4e 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -36,11 +36,10 @@ namespace android { RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage, int bufferCount) : - ConsumerBase(new BufferQueue(true)), + ConsumerBase(new BufferQueue()), mBufferCount(bufferCount) { mBufferQueue->setConsumerUsageBits(consumerUsage); - mBufferQueue->setSynchronousMode(true); mBufferQueue->setMaxAcquiredBufferCount(bufferCount); assert(bufferCount > 0); -- cgit v1.1 From deeef54487a34034dc0cfaab20b20d557224c07c Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 2 Aug 2013 01:50:59 -0700 Subject: separte producer and consumer interfaces Bug: 9265647 Change-Id: Iefabc11e4bd2e2e8ffd31160476c450affe6629c --- .../camera/libcameraservice/gui/RingBufferConsumer.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'services/camera/libcameraservice/gui/RingBufferConsumer.cpp') diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp index 8141f4e..ebc7ea7 100644 --- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp +++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp @@ -34,13 +34,14 @@ typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; namespace android { -RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage, +RingBufferConsumer::RingBufferConsumer(const sp& consumer, + uint32_t consumerUsage, int bufferCount) : - ConsumerBase(new BufferQueue()), + ConsumerBase(consumer), mBufferCount(bufferCount) { - mBufferQueue->setConsumerUsageBits(consumerUsage); - mBufferQueue->setMaxAcquiredBufferCount(bufferCount); + mConsumer->setConsumerUsageBits(consumerUsage); + mConsumer->setMaxAcquiredBufferCount(bufferCount); assert(bufferCount > 0); } @@ -51,7 +52,7 @@ RingBufferConsumer::~RingBufferConsumer() { void RingBufferConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; - mBufferQueue->setConsumerName(name); + mConsumer->setConsumerName(name); } sp RingBufferConsumer::pinSelectedBuffer( @@ -342,17 +343,17 @@ void RingBufferConsumer::unpinBuffer(const BufferItem& item) { status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferSize(w, h); + return mConsumer->setDefaultBufferSize(w, h); } status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); + return mConsumer->setDefaultBufferFormat(defaultFormat); } status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setConsumerUsageBits(usage); + return mConsumer->setConsumerUsageBits(usage); } } // namespace android -- cgit v1.1