Add C2VdaPooledBlockPool class
V4L2 stateful API will require the caller passing a fixed output
buffer to each slot of buffer queue. However, the default
C2PooledBlockPool cannot achieve this requirement.
This CL adds C2VdaPooledBlockPool for replacing C2PooledBlockPool in
the following CL.
Bug: 161770200
Test: m -j32
Change-Id: Icdad63ace87b49793d0f7215f8d735a8c950ee60
diff --git a/plugin_store/Android.bp b/plugin_store/Android.bp
index 3d3d040..ed9d784 100644
--- a/plugin_store/Android.bp
+++ b/plugin_store/Android.bp
@@ -8,6 +8,7 @@
srcs: [
"C2VdaBqBlockPool.cpp",
+ "C2VdaPooledBlockPool.cpp",
"V4L2PluginStore.cpp",
"VendorAllocatorLoader.cpp",
],
@@ -25,6 +26,7 @@
"libhidlbase",
"libnativewindow",
"liblog",
+ "libstagefright_bufferpool@1.0",
"libstagefright_bufferqueue_helper",
"libstagefright_foundation",
"libui",
@@ -33,5 +35,6 @@
cflags: [
"-Werror",
"-Wall",
+ "-Wthread-safety",
],
}
diff --git a/plugin_store/C2VdaPooledBlockPool.cpp b/plugin_store/C2VdaPooledBlockPool.cpp
new file mode 100644
index 0000000..19c9cfc
--- /dev/null
+++ b/plugin_store/C2VdaPooledBlockPool.cpp
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2VdaPooledBlockPool"
+
+#include <v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h>
+
+#include <time.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <bufferpool/BufferPoolTypes.h>
+#include <log/log.h>
+
+namespace android {
+namespace {
+// The wait time for another try to fetch a buffer from bufferpool.
+const int64_t kFetchRetryDelayUs = 10 * 1000;
+
+int64_t GetNowUs() {
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ int64_t nsecs = static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
+ return nsecs / 1000ll;
+}
+} // namespace
+
+using android::hardware::media::bufferpool::BufferPoolData;
+
+// static
+c2_status_t C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(
+ const std::shared_ptr<C2GraphicBlock>& block, uint32_t* poolId) {
+ std::shared_ptr<_C2BlockPoolData> blockPoolData =
+ _C2BlockFactory::GetGraphicBlockPoolData(*block);
+ if (blockPoolData->getType() != _C2BlockPoolData::TYPE_BUFFERPOOL) {
+ ALOGE("Obtained C2GraphicBlock is not bufferpool-backed.");
+ return C2_CORRUPTED;
+ }
+ std::shared_ptr<BufferPoolData> bpData;
+ if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData) || !bpData) {
+ ALOGE("BufferPoolData unavailable in block.");
+ return C2_CORRUPTED;
+ }
+ *poolId = bpData->mId;
+ return C2_OK;
+}
+
+// Tries to fetch a buffer from bufferpool. When the size of |mBufferIds| is smaller than
+// |mBufferCount|, pass the obtained buffer to caller and record its ID in BufferPoolData to
+// |mBufferIds|. When the size of |mBufferIds| is equal to |mBufferCount|, pass the obtained
+// buffer only if its ID is included in |mBufferIds|. Otherwise, discard the buffer and
+// return C2_TIMED_OUT.
+c2_status_t C2VdaPooledBlockPool::fetchGraphicBlock(uint32_t width, uint32_t height,
+ uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock>* block) {
+ ALOG_ASSERT(block != nullptr);
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mNextFetchTimeUs != 0) {
+ int delayUs = GetNowUs() - mNextFetchTimeUs;
+ if (delayUs > 0) {
+ ::usleep(delayUs);
+ }
+ mNextFetchTimeUs = 0;
+ }
+
+ std::shared_ptr<C2GraphicBlock> fetchBlock;
+ c2_status_t err =
+ C2PooledBlockPool::fetchGraphicBlock(width, height, format, usage, &fetchBlock);
+ if (err != C2_OK) {
+ ALOGE("Failed at C2PooledBlockPool::fetchGraphicBlock: %d", err);
+ return err;
+ }
+
+ uint32_t bufferId;
+ err = getPoolIdFromGraphicBlock(fetchBlock, &bufferId);
+ if (err != C2_OK) {
+ ALOGE("Failed to getPoolIdFromGraphicBlock: %d", err);
+ return err;
+ }
+
+ if (mBufferIds.size() < mBufferCount) {
+ mBufferIds.insert(bufferId);
+ }
+
+ if (mBufferIds.find(bufferId) != mBufferIds.end()) {
+ ALOGV("Returned buffer id = %u", bufferId);
+ *block = std::move(fetchBlock);
+ return C2_OK;
+ }
+ ALOGV("No buffer could be recycled now, wait for another try...");
+ mNextFetchTimeUs = GetNowUs() + kFetchRetryDelayUs;
+ return C2_TIMED_OUT;
+}
+
+c2_status_t C2VdaPooledBlockPool::requestNewBufferSet(int32_t bufferCount) {
+ if (bufferCount <= 0) {
+ ALOGE("Invalid requested buffer count = %d", bufferCount);
+ return C2_BAD_VALUE;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mBufferIds.clear();
+ mBufferCount = bufferCount;
+ return C2_OK;
+}
+
+} // namespace android
diff --git a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h
new file mode 100644
index 0000000..b3ea988
--- /dev/null
+++ b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_POOLED_BLOCK_POOL_H
+#define ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_POOLED_BLOCK_POOL_H
+
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+#include <C2PlatformSupport.h>
+#include <android-base/thread_annotations.h>
+
+namespace android {
+
+class C2VdaPooledBlockPool : public C2PooledBlockPool {
+public:
+ using C2PooledBlockPool::C2PooledBlockPool;
+ ~C2VdaPooledBlockPool() override = default;
+
+ // Extracts buffer ID from BufferPoolData of the graphic block.
+ // |block| is the graphic block allocated by bufferpool block pool.
+ // |poolId| is an output parameter to store the buffer ID into.
+ static c2_status_t getPoolIdFromGraphicBlock(const std::shared_ptr<C2GraphicBlock>& block,
+ uint32_t* poolId);
+
+ // Allocate the specified number of buffers.
+ // |bufferCount| is the number of requested buffers.
+ c2_status_t requestNewBufferSet(int32_t bufferCount);
+
+ // Return C2_OK and store a buffer in |block| if a buffer is successfully fetched.
+ // Return C2_TIMED_OUT if the pool already allocated |mBufferCount| buffers but they are all in
+ // use.
+ // Return C2_NO_MEMORY if the pool fails to allocate a new buffer.
+ c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock>* block /* nonnull */) override;
+
+private:
+ // Function mutex to lock at the start of each API function call for protecting the
+ // synchronization of all member variables.
+ std::mutex mMutex;
+
+ // The ids of all allocated buffers.
+ std::set<uint32_t> mBufferIds GUARDED_BY(mMutex);
+ // The maximum count of allocated buffers.
+ size_t mBufferCount GUARDED_BY(mMutex){0};
+ // The timestamp for the next fetchGraphicBlock() call.
+ // Set when the previous fetchGraphicBlock() call timed out.
+ int64_t mNextFetchTimeUs GUARDED_BY(mMutex){0};
+};
+
+} // namespace android
+#endif // ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_POOLED_BLOCK_POOL_H