Loading services/camera/libcameraservice/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,8 @@ LOCAL_SRC_FILES:= \ camera3/Camera3Stream.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ camera3/Camera3ZslStream.cpp camera3/Camera3ZslStream.cpp \ gui/RingBufferConsumer.cpp \ LOCAL_SHARED_LIBRARIES:= \ libui \ Loading services/camera/libcameraservice/gui/RingBufferConsumer.cpp 0 → 100644 +346 −0 Original line number Diff line number Diff line /* * 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 <cassert> //#define LOG_NDEBUG 0 #define LOG_TAG "RingBufferConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> #include <gui/RingBufferConsumer.h> #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<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer( const RingBufferComparator& filter, bool waitForFence) { sp<PinnedBufferItem> pinnedBuffer; { List<RingBufferItem>::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<RingBufferItem>::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<RingBufferItem>::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<RingBufferItem>::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 services/camera/libcameraservice/gui/RingBufferConsumer.h 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef ANDROID_GUI_RINGBUFFERCONSUMER_H #define ANDROID_GUI_RINGBUFFERCONSUMER_H #include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> #include <utils/String8.h> #include <utils/Vector.h> #include <utils/threads.h> #include <utils/List.h> #define ANDROID_GRAPHICS_RINGBUFFERCONSUMER_JNI_ID "mRingBufferConsumer" namespace android { /** * The RingBufferConsumer maintains a ring buffer of BufferItem objects, * (which are 'acquired' as long as they are part of the ring buffer, and * 'released' when they leave the ring buffer). * * When new buffers are produced, the oldest non-pinned buffer item is immediately * dropped from the ring buffer, and overridden with the newest buffer. * * Users can only access a buffer item after pinning it (which also guarantees * that during its duration it will not be released back into the BufferQueue). * * Note that the 'oldest' buffer is the one with the smallest timestamp. * * Edge cases: * - If ringbuffer is not full, no drops occur when a buffer is produced. * - If all the buffers get filled or pinned then there will be no empty * buffers left, so the producer will block on dequeue. */ class RingBufferConsumer : public ConsumerBase, public ConsumerBase::FrameAvailableListener { public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; typedef BufferQueue::BufferItem BufferItem; enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; // Create a new ring buffer consumer. The consumerUsage parameter determines // the consumer usage flags passed to the graphics allocator. The // bufferCount parameter specifies how many buffers can be pinned for user // access at the same time. RingBufferConsumer(uint32_t consumerUsage, int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS); virtual ~RingBufferConsumer(); // set the name of the RingBufferConsumer that will be used to identify it in // log messages. void setName(const String8& name); sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); } // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. status_t setDefaultBufferSize(uint32_t w, uint32_t h); // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // by the producer endpoint. status_t setDefaultBufferFormat(uint32_t defaultFormat); // setConsumerUsage allows the BufferQueue consumer usage to be // set at a later time after construction. status_t setConsumerUsage(uint32_t usage); // Buffer info, minus the graphics buffer/slot itself. struct BufferInfo { // mCrop is the current crop rectangle for this buffer slot. Rect mCrop; // mTransform is the current transform flags for this buffer slot. uint32_t mTransform; // mScalingMode is the current scaling mode for this buffer slot. uint32_t mScalingMode; // mTimestamp is the current timestamp for this buffer slot. This gets // to set by queueBuffer each time this slot is queued. int64_t mTimestamp; // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; // mPinned is whether or not the buffer has been pinned already. bool mPinned; }; struct RingBufferComparator { // Return < 0 to select i1, > 0 to select i2, 0 for neither // i1 or i2 can be NULL. // // The comparator has to implement a total ordering. Otherwise // a linear scan won't find the most preferred buffer. virtual int compare(const BufferInfo* i1, const BufferInfo* i2) const = 0; virtual ~RingBufferComparator() {} }; struct PinnedBufferItem : public LightRefBase<PinnedBufferItem> { PinnedBufferItem(wp<RingBufferConsumer> consumer, const BufferItem& item) : mConsumer(consumer), mBufferItem(item) { } ~PinnedBufferItem() { sp<RingBufferConsumer> consumer = mConsumer.promote(); if (consumer != NULL) { consumer->unpinBuffer(mBufferItem); } } bool isEmpty() { return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT; } BufferItem& getBufferItem() { return mBufferItem; } const BufferItem& getBufferItem() const { return mBufferItem; } private: wp<RingBufferConsumer> mConsumer; BufferItem mBufferItem; }; // Find a buffer using the filter, then pin it before returning it. // // The filter will be invoked on each buffer item in the ring buffer, // passing the item that was selected from each previous iteration, // as well as the current iteration's item. // // Pinning will ensure that the buffer will not be dropped when a new // frame is available. sp<PinnedBufferItem> pinSelectedBuffer(const RingBufferComparator& filter, bool waitForFence = true); // Release all the non-pinned buffers in the ring buffer status_t clear(); private: // Override ConsumerBase::onFrameAvailable virtual void onFrameAvailable(); void pinBufferLocked(const BufferItem& item); void unpinBuffer(const BufferItem& item); // Releases oldest buffer. Returns NO_BUFFER_AVAILABLE // if all the buffers were pinned. // Returns NOT_ENOUGH_DATA if list was empty. status_t releaseOldestBufferLocked(size_t* pinnedFrames); struct RingBufferItem : public BufferItem { RingBufferItem() : BufferItem(), mPinCount(0) {} int mPinCount; }; // List of acquired buffers in our ring buffer List<RingBufferItem> mBufferItemList; const int mBufferCount; }; } // namespace android #endif // ANDROID_GUI_CPUCONSUMER_H Loading
services/camera/libcameraservice/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,8 @@ LOCAL_SRC_FILES:= \ camera3/Camera3Stream.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ camera3/Camera3ZslStream.cpp camera3/Camera3ZslStream.cpp \ gui/RingBufferConsumer.cpp \ LOCAL_SHARED_LIBRARIES:= \ libui \ Loading
services/camera/libcameraservice/gui/RingBufferConsumer.cpp 0 → 100644 +346 −0 Original line number Diff line number Diff line /* * 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 <cassert> //#define LOG_NDEBUG 0 #define LOG_TAG "RingBufferConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> #include <gui/RingBufferConsumer.h> #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<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer( const RingBufferComparator& filter, bool waitForFence) { sp<PinnedBufferItem> pinnedBuffer; { List<RingBufferItem>::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<RingBufferItem>::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<RingBufferItem>::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<RingBufferItem>::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
services/camera/libcameraservice/gui/RingBufferConsumer.h 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef ANDROID_GUI_RINGBUFFERCONSUMER_H #define ANDROID_GUI_RINGBUFFERCONSUMER_H #include <gui/ConsumerBase.h> #include <ui/GraphicBuffer.h> #include <utils/String8.h> #include <utils/Vector.h> #include <utils/threads.h> #include <utils/List.h> #define ANDROID_GRAPHICS_RINGBUFFERCONSUMER_JNI_ID "mRingBufferConsumer" namespace android { /** * The RingBufferConsumer maintains a ring buffer of BufferItem objects, * (which are 'acquired' as long as they are part of the ring buffer, and * 'released' when they leave the ring buffer). * * When new buffers are produced, the oldest non-pinned buffer item is immediately * dropped from the ring buffer, and overridden with the newest buffer. * * Users can only access a buffer item after pinning it (which also guarantees * that during its duration it will not be released back into the BufferQueue). * * Note that the 'oldest' buffer is the one with the smallest timestamp. * * Edge cases: * - If ringbuffer is not full, no drops occur when a buffer is produced. * - If all the buffers get filled or pinned then there will be no empty * buffers left, so the producer will block on dequeue. */ class RingBufferConsumer : public ConsumerBase, public ConsumerBase::FrameAvailableListener { public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; typedef BufferQueue::BufferItem BufferItem; enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; // Create a new ring buffer consumer. The consumerUsage parameter determines // the consumer usage flags passed to the graphics allocator. The // bufferCount parameter specifies how many buffers can be pinned for user // access at the same time. RingBufferConsumer(uint32_t consumerUsage, int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS); virtual ~RingBufferConsumer(); // set the name of the RingBufferConsumer that will be used to identify it in // log messages. void setName(const String8& name); sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); } // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. status_t setDefaultBufferSize(uint32_t w, uint32_t h); // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // by the producer endpoint. status_t setDefaultBufferFormat(uint32_t defaultFormat); // setConsumerUsage allows the BufferQueue consumer usage to be // set at a later time after construction. status_t setConsumerUsage(uint32_t usage); // Buffer info, minus the graphics buffer/slot itself. struct BufferInfo { // mCrop is the current crop rectangle for this buffer slot. Rect mCrop; // mTransform is the current transform flags for this buffer slot. uint32_t mTransform; // mScalingMode is the current scaling mode for this buffer slot. uint32_t mScalingMode; // mTimestamp is the current timestamp for this buffer slot. This gets // to set by queueBuffer each time this slot is queued. int64_t mTimestamp; // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; // mPinned is whether or not the buffer has been pinned already. bool mPinned; }; struct RingBufferComparator { // Return < 0 to select i1, > 0 to select i2, 0 for neither // i1 or i2 can be NULL. // // The comparator has to implement a total ordering. Otherwise // a linear scan won't find the most preferred buffer. virtual int compare(const BufferInfo* i1, const BufferInfo* i2) const = 0; virtual ~RingBufferComparator() {} }; struct PinnedBufferItem : public LightRefBase<PinnedBufferItem> { PinnedBufferItem(wp<RingBufferConsumer> consumer, const BufferItem& item) : mConsumer(consumer), mBufferItem(item) { } ~PinnedBufferItem() { sp<RingBufferConsumer> consumer = mConsumer.promote(); if (consumer != NULL) { consumer->unpinBuffer(mBufferItem); } } bool isEmpty() { return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT; } BufferItem& getBufferItem() { return mBufferItem; } const BufferItem& getBufferItem() const { return mBufferItem; } private: wp<RingBufferConsumer> mConsumer; BufferItem mBufferItem; }; // Find a buffer using the filter, then pin it before returning it. // // The filter will be invoked on each buffer item in the ring buffer, // passing the item that was selected from each previous iteration, // as well as the current iteration's item. // // Pinning will ensure that the buffer will not be dropped when a new // frame is available. sp<PinnedBufferItem> pinSelectedBuffer(const RingBufferComparator& filter, bool waitForFence = true); // Release all the non-pinned buffers in the ring buffer status_t clear(); private: // Override ConsumerBase::onFrameAvailable virtual void onFrameAvailable(); void pinBufferLocked(const BufferItem& item); void unpinBuffer(const BufferItem& item); // Releases oldest buffer. Returns NO_BUFFER_AVAILABLE // if all the buffers were pinned. // Returns NOT_ENOUGH_DATA if list was empty. status_t releaseOldestBufferLocked(size_t* pinnedFrames); struct RingBufferItem : public BufferItem { RingBufferItem() : BufferItem(), mPinCount(0) {} int mPinCount; }; // List of acquired buffers in our ring buffer List<RingBufferItem> mBufferItemList; const int mBufferCount; }; } // namespace android #endif // ANDROID_GUI_CPUCONSUMER_H