From add5343beb09f23bc0265cd717794240ad63304a Mon Sep 17 00:00:00 2001 From: Tao Wu Date: Mon, 27 Feb 2023 19:18:43 -0800 Subject: V4L2EncodeComponent: force sync gpu buffer Android encoder framework reuses the same gpu buffers as inputs and doesn't call lock/unlock explicitly between writes. If there is format conversion, this is fine since we will read back what we've written first and then put it in another buffer. Whenever there is no format conversion, this causes sync issue on ARCVM since host side buffers never get updated. Fix this by explicitly calling lock/unlock before sending buffer to encoder. Bug: 268317650 Test: atest com.google.android.media.gts.RtcVideoCodecTest#testDynamicBitrateChangeVp8 Change-Id: Ia1750aa37c2d879ddff0301814e489974f218f5c --- components/V4L2EncodeComponent.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/V4L2EncodeComponent.cpp b/components/V4L2EncodeComponent.cpp index f9d735d..da61217 100644 --- a/components/V4L2EncodeComponent.cpp +++ b/components/V4L2EncodeComponent.cpp @@ -517,6 +517,27 @@ void V4L2EncodeComponent::queueTask(std::unique_ptr work) { reportError(status); return; } + } else { + // Android encoder framework reuses the same gpu buffers as + // inputs and doesn't call lock/unlock explicitly between writes. + // If there is format conversion, this is fine since we will + // read back what we've written first and then put it in another + // buffer. Whenever there is no format conversion, this causes + // sync issue on ARCVM since host side buffers never get updated. + // Fix this by explicitly calling lock/unlock before sending buffer + // to encoder. + const C2Handle* handle = inputBlock.handle(); + uint32_t width, height, format, stride, generation, igbpSlot; + uint64_t usage, igbpId; + _UnwrapNativeCodec2GrallocMetadata(handle, &width, &height, &format, &usage, &stride, + &generation, &igbpId, &igbpSlot); + native_handle_t* gralloc_handle = UnwrapNativeCodec2GrallocHandle(handle); + sp buffer = + new GraphicBuffer(gralloc_handle, GraphicBuffer::CLONE_HANDLE, width, height, + format, 1, usage, stride); + void* pixels; + buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels); + buffer->unlock(); } if (!encode(inputBlock, index, timestamp)) { return; -- cgit v1.2.3 From 0efa67cee4e4287c82920a26424b6624fb56e83f Mon Sep 17 00:00:00 2001 From: Tao Wu Date: Fri, 10 Mar 2023 18:29:47 -0800 Subject: V4L2EncodeComponent: Better error handling when syncing buffer Thanks Yiwei pointed out the buggy code which doesn't do error handling and also we should only sync CPU writable buffer. Bug: 268317650 Test: atest com.google.android.media.gts.RtcVideoCodecTest#testDynamicBitrateChangeVp8 Change-Id: I3c1019fb0d56180ef8460625843cf8e98301ddce --- components/V4L2EncodeComponent.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/components/V4L2EncodeComponent.cpp b/components/V4L2EncodeComponent.cpp index da61217..b266a6e 100644 --- a/components/V4L2EncodeComponent.cpp +++ b/components/V4L2EncodeComponent.cpp @@ -531,13 +531,18 @@ void V4L2EncodeComponent::queueTask(std::unique_ptr work) { uint64_t usage, igbpId; _UnwrapNativeCodec2GrallocMetadata(handle, &width, &height, &format, &usage, &stride, &generation, &igbpId, &igbpSlot); - native_handle_t* gralloc_handle = UnwrapNativeCodec2GrallocHandle(handle); - sp buffer = - new GraphicBuffer(gralloc_handle, GraphicBuffer::CLONE_HANDLE, width, height, - format, 1, usage, stride); - void* pixels; - buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels); - buffer->unlock(); + do { + if (!(usage & GRALLOC_USAGE_SW_WRITE_MASK)) break; + native_handle_t* gralloc_handle = UnwrapNativeCodec2GrallocHandle(handle); + if (nullptr == gralloc_handle) break; + sp buffer = + new GraphicBuffer(gralloc_handle, GraphicBuffer::CLONE_HANDLE, width, + height, format, 1, usage, stride); + native_handle_delete(gralloc_handle); + void* pixels; + if (buffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &pixels)) break; + buffer->unlock(); + } while (0); } if (!encode(inputBlock, index, timestamp)) { return; -- cgit v1.2.3 From 35f4783d906bfa559d76bce18c83bfe6ac1056b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 09:42:37 +0000 Subject: service: Uprev Codec 2.0 VNDK to 1.2 This CL uprevs Codec 2.0 VNDK version 1.2 to take advantage of asynchronous graphic buffer fetching from buffer queue in following patches. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: Icad6d78c3f36d365749af787f2b3bab3edc54d3e (cherry picked from commit d1454490efa1865cd9fd33bd13237f9ef919823b) --- plugin_store/C2VdaBqBlockPool.cpp | 10 ++++++++++ .../include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h | 4 ++++ service/Android.bp | 6 +++--- service/android.hardware.media.c2@1.0-service-v4l2-32.rc | 7 ------- service/android.hardware.media.c2@1.0-service-v4l2-64.rc | 7 ------- service/android.hardware.media.c2@1.2-service-v4l2-32.rc | 7 +++++++ service/android.hardware.media.c2@1.2-service-v4l2-64.rc | 7 +++++++ service/service.cpp | 6 +++--- 8 files changed, 34 insertions(+), 20 deletions(-) delete mode 100644 service/android.hardware.media.c2@1.0-service-v4l2-32.rc delete mode 100644 service/android.hardware.media.c2@1.0-service-v4l2-64.rc create mode 100644 service/android.hardware.media.c2@1.2-service-v4l2-32.rc create mode 100644 service/android.hardware.media.c2@1.2-service-v4l2-64.rc diff --git a/plugin_store/C2VdaBqBlockPool.cpp b/plugin_store/C2VdaBqBlockPool.cpp index d53f4a0..3356885 100644 --- a/plugin_store/C2VdaBqBlockPool.cpp +++ b/plugin_store/C2VdaBqBlockPool.cpp @@ -918,6 +918,16 @@ c2_status_t C2VdaBqBlockPool::fetchGraphicBlock( return C2_NO_INIT; } +c2_status_t C2VdaBqBlockPool::fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, + C2MemoryUsage usage, + std::shared_ptr* block, + C2Fence* fence) { + if (mImpl) { + return mImpl->fetchGraphicBlock(width, height, format, usage, block); + } + return C2_NO_INIT; +} + void C2VdaBqBlockPool::setRenderCallback( const C2BufferQueueBlockPool::OnRenderCallback& renderCallback) { if (mImpl) { diff --git a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h index fde6299..addc23d 100644 --- a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h +++ b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h @@ -55,6 +55,10 @@ public: C2MemoryUsage usage, std::shared_ptr* block /* nonnull */) override; + c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, + C2MemoryUsage usage, std::shared_ptr* block, + C2Fence* fence) override; + void setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback& renderCallback = C2BufferQueueBlockPool::OnRenderCallback()) override; void configureProducer(const android::sp& producer) override; diff --git a/service/Android.bp b/service/Android.bp index c901a02..a690f08 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -8,7 +8,7 @@ package { } cc_binary { - name: "android.hardware.media.c2@1.0-service-v4l2", + name: "android.hardware.media.c2@1.2-service-v4l2", defaults: [ "hidl_defaults", @@ -37,11 +37,11 @@ cc_binary { multilib: { lib32: { suffix: "-32", - init_rc: ["android.hardware.media.c2@1.0-service-v4l2-32.rc"], + init_rc: ["android.hardware.media.c2@1.2-service-v4l2-32.rc"], }, lib64: { suffix: "-64", - init_rc: ["android.hardware.media.c2@1.0-service-v4l2-64.rc"], + init_rc: ["android.hardware.media.c2@1.2-service-v4l2-64.rc"], }, }, } diff --git a/service/android.hardware.media.c2@1.0-service-v4l2-32.rc b/service/android.hardware.media.c2@1.0-service-v4l2-32.rc deleted file mode 100644 index e4ddbc3..0000000 --- a/service/android.hardware.media.c2@1.0-service-v4l2-32.rc +++ /dev/null @@ -1,7 +0,0 @@ -service android-hardware-media-c2-v4l2-hal-1-0 /vendor/bin/hw/android.hardware.media.c2@1.0-service-v4l2-32 - class hal - user media - group mediadrm drmrpc - ioprio rt 4 - task_profiles ProcessCapacityHigh - setenv MESA_GLSL_CACHE_DISABLE 1 diff --git a/service/android.hardware.media.c2@1.0-service-v4l2-64.rc b/service/android.hardware.media.c2@1.0-service-v4l2-64.rc deleted file mode 100644 index 454953b..0000000 --- a/service/android.hardware.media.c2@1.0-service-v4l2-64.rc +++ /dev/null @@ -1,7 +0,0 @@ -service android-hardware-media-c2-v4l2-hal-1-0 /vendor/bin/hw/android.hardware.media.c2@1.0-service-v4l2-64 - class hal - user media - group mediadrm drmrpc - ioprio rt 4 - task_profiles ProcessCapacityHigh - setenv MESA_GLSL_CACHE_DISABLE 1 diff --git a/service/android.hardware.media.c2@1.2-service-v4l2-32.rc b/service/android.hardware.media.c2@1.2-service-v4l2-32.rc new file mode 100644 index 0000000..4fe0ccb --- /dev/null +++ b/service/android.hardware.media.c2@1.2-service-v4l2-32.rc @@ -0,0 +1,7 @@ +service android-hardware-media-c2-v4l2-hal-1-2 /vendor/bin/hw/android.hardware.media.c2@1.2-service-v4l2-32 + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + task_profiles ProcessCapacityHigh + setenv MESA_GLSL_CACHE_DISABLE 1 diff --git a/service/android.hardware.media.c2@1.2-service-v4l2-64.rc b/service/android.hardware.media.c2@1.2-service-v4l2-64.rc new file mode 100644 index 0000000..9869c6b --- /dev/null +++ b/service/android.hardware.media.c2@1.2-service-v4l2-64.rc @@ -0,0 +1,7 @@ +service android-hardware-media-c2-v4l2-hal-1-2 /vendor/bin/hw/android.hardware.media.c2@1.2-service-v4l2-64 + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + task_profiles ProcessCapacityHigh + setenv MESA_GLSL_CACHE_DISABLE 1 diff --git a/service/service.cpp b/service/service.cpp index 616e641..6917354 100644 --- a/service/service.cpp +++ b/service/service.cpp @@ -5,9 +5,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "android.hardware.media.c2@1.0-service-v4l2" -#include #include -#include +#include +#include #include #include #include @@ -39,7 +39,7 @@ int main(int /* argc */, char** /* argv */) { // Create IComponentStore service. { - using namespace ::android::hardware::media::c2::V1_0; + using namespace ::android::hardware::media::c2::V1_2; ALOGD("Instantiating Codec2's V4L2 IComponentStore service..."); android::sp store( -- cgit v1.2.3 From d81926adf9cd0acf305f73aab9dd6e3b9a43314d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 09:50:09 +0000 Subject: VideoFramePool: implement asynchronous frame fetching This CL adds asynchronous frame fetching to VideoFramePool that relies on new API introduced in Codec 2.0. When a buffer is not available the new version of fetchGraphicBlock returns a C2_BLOCKING together fence that will be signaled once the call should be retried. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: Id470113e2037ec2c69ed1ccbf2fe15a4facf80ce (cherry picked from commit cb4034b1ed2b067355f66c0fa40968065934b07e) --- components/VideoFramePool.cpp | 73 ++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index 665ff73..05e22a6 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -176,28 +176,41 @@ void VideoFramePool::getVideoFrameTask() { // Variables used to exponential backoff retry when buffer fetching times out. constexpr size_t kFetchRetryDelayInit = 64; // Initial delay: 64us constexpr size_t kFetchRetryDelayMax = 16384; // Max delay: 16ms (1 frame at 60fps) + constexpr size_t kFenceWaitTimeoutNs = 16000000; // 16ms (1 frame at 60fps) static size_t sNumRetries = 0; static size_t sDelay = kFetchRetryDelayInit; + C2Fence fence; std::shared_ptr block; - c2_status_t err = mBlockPool->fetchGraphicBlock( - mSize.width, mSize.height, static_cast(mPixelFormat), mMemoryUsage, &block); - if (err == C2_TIMED_OUT || err == C2_BLOCKING) { - if (setNotifyBlockAvailableCb(*mBlockPool, - ::base::BindOnce(&VideoFramePool::getVideoFrameTaskThunk, - mFetchTaskRunner, mFetchWeakThis))) { - ALOGV("%s(): fetchGraphicBlock() timeout, waiting for block available.", __func__); - } else { - ALOGV("%s(): fetchGraphicBlock() timeout, waiting %zuus (%zu retry)", __func__, sDelay, - sNumRetries + 1); - mFetchTaskRunner->PostDelayedTask( - FROM_HERE, ::base::BindOnce(&VideoFramePool::getVideoFrameTask, mFetchWeakThis), - ::base::TimeDelta::FromMicroseconds(sDelay)); - - sDelay = std::min(sDelay * 2, kFetchRetryDelayMax); // Exponential backoff - sNumRetries++; + c2_status_t err = mBlockPool->fetchGraphicBlock(mSize.width, mSize.height, + static_cast(mPixelFormat), + mMemoryUsage, &block, &fence); + if (err == C2_BLOCKING) { + err = fence.wait(kFenceWaitTimeoutNs); + if (err == C2_OK) { + ALOGV("%s(): fence wait succeded, retrying now", __func__); + mFetchTaskRunner->PostTask( + FROM_HERE, + ::base::BindOnce(&VideoFramePool::getVideoFrameTask, mFetchWeakThis)); + return; } + ALOGV("%s(): fence wait unsucessful err=%d", __func__, err); + } else if (err == C2_OMITTED) { + // Fenced version is not supported, try legacy version. + err = mBlockPool->fetchGraphicBlock(mSize.width, mSize.height, + static_cast(mPixelFormat), mMemoryUsage, + &block); + } + if (err == C2_TIMED_OUT || err == C2_BLOCKING) { + ALOGV("%s(): fetchGraphicBlock() timeout, waiting %zuus (%zu retry)", __func__, sDelay, + sNumRetries + 1); + mFetchTaskRunner->PostDelayedTask( + FROM_HERE, ::base::BindOnce(&VideoFramePool::getVideoFrameTask, mFetchWeakThis), + ::base::TimeDelta::FromMicroseconds(sDelay)); + + sDelay = std::min(sDelay * 2, kFetchRetryDelayMax); // Exponential backoff + sNumRetries++; return; } @@ -205,20 +218,28 @@ void VideoFramePool::getVideoFrameTask() { sNumRetries = 0; sDelay = kFetchRetryDelayInit; + if (err != C2_OK) { + ALOGE("%s(): Failed to fetch block, err=%d", __func__, err); + return; + } + + ALOG_ASSERT(block != nullptr); + std::unique_ptr frame = VideoFrame::Create(std::move(block)); std::optional frameWithBlockId; - if (err == C2_OK) { - ALOG_ASSERT(block != nullptr); - std::optional bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); - std::unique_ptr frame = VideoFrame::Create(std::move(block)); + std::optional bufferId; + + if (bufferId && frame) { + bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); + + if (bufferId) { + ALOGV("%s(): Got buffer with id = %u", __func__, *bufferId); + } + // Only pass the frame + id pair if both have successfully been obtained. // Otherwise exit the loop so a nullopt is passed to the client. - if (bufferId && frame) { - frameWithBlockId = std::make_pair(std::move(frame), *bufferId); - } else { - ALOGE("%s(): Failed to generate VideoFrame or get the buffer id.", __func__); - } + frameWithBlockId = std::make_pair(std::move(frame), *bufferId); } else { - ALOGE("%s(): Failed to fetch block, err=%d", __func__, err); + ALOGE("%s(): Failed to generate VideoFrame or get the buffer id.", __func__); } mClientTaskRunner->PostTask( -- cgit v1.2.3 From d4829d03becedacf65d798cf05284c124675fceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 10:03:59 +0000 Subject: VideoFramePool: limit the number of provided buffers This CL moves limitation logic from C2VdaPooledBufferPool to VideoFramePool. This will allow removal of C2VdaPooledBufferPool. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: I78abfdbcda6f9b3de2a6d5bcfd705a7028490f9b (cherry picked from commit b9a66dedb0c92d411e7d5f6b2199934f6664eaba) --- components/VideoFramePool.cpp | 48 +++++++++++++++++----- .../v4l2_codec2/components/VideoFramePool.h | 15 ++++++- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index 05e22a6..c8ea842 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -91,16 +91,19 @@ std::unique_ptr VideoFramePool::Create( return nullptr; } - std::unique_ptr pool = ::base::WrapUnique(new VideoFramePool( - std::move(blockPool), size, pixelFormat, memoryUsage, std::move(taskRunner))); + std::unique_ptr pool = + ::base::WrapUnique(new VideoFramePool(std::move(blockPool), numBuffers, size, + pixelFormat, memoryUsage, std::move(taskRunner))); if (!pool->initialize()) return nullptr; return pool; } -VideoFramePool::VideoFramePool(std::shared_ptr blockPool, const ui::Size& size, - HalPixelFormat pixelFormat, C2MemoryUsage memoryUsage, +VideoFramePool::VideoFramePool(std::shared_ptr blockPool, const size_t maxBufferCount, + const ui::Size& size, HalPixelFormat pixelFormat, + C2MemoryUsage memoryUsage, scoped_refptr<::base::SequencedTaskRunner> taskRunner) : mBlockPool(std::move(blockPool)), + mMaxBufferCount(maxBufferCount), mSize(size), mPixelFormat(pixelFormat), mMemoryUsage(memoryUsage), @@ -144,6 +147,18 @@ void VideoFramePool::destroyTask() { mFetchWeakThisFactory.InvalidateWeakPtrs(); } +bool VideoFramePool::shouldDropBuffer(uint32_t bufferId) { + if (mBuffers.size() < mMaxBufferCount) { + return false; + } + + if (mBuffers.find(bufferId) != mBuffers.end()) { + return false; + } + + return true; +} + bool VideoFramePool::getVideoFrame(GetVideoFrameCB cb) { ALOGV("%s()", __func__); ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence()); @@ -202,6 +217,23 @@ void VideoFramePool::getVideoFrameTask() { &block); } + std::optional bufferId; + if (err == C2_OK) { + bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); + + if (bufferId) { + ALOGV("%s(): Got buffer with id = %u", __func__, *bufferId); + + if (shouldDropBuffer(*bufferId)) { + // We drop buffer, since we got more then needed. + ALOGV("%s(): Dropping allocated buffer with id = %u", __func__, *bufferId); + bufferId = std::nullopt; + block.reset(); + err = C2_TIMED_OUT; + } + } + } + if (err == C2_TIMED_OUT || err == C2_BLOCKING) { ALOGV("%s(): fetchGraphicBlock() timeout, waiting %zuus (%zu retry)", __func__, sDelay, sNumRetries + 1); @@ -226,18 +258,12 @@ void VideoFramePool::getVideoFrameTask() { ALOG_ASSERT(block != nullptr); std::unique_ptr frame = VideoFrame::Create(std::move(block)); std::optional frameWithBlockId; - std::optional bufferId; if (bufferId && frame) { - bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); - - if (bufferId) { - ALOGV("%s(): Got buffer with id = %u", __func__, *bufferId); - } - // Only pass the frame + id pair if both have successfully been obtained. // Otherwise exit the loop so a nullopt is passed to the client. frameWithBlockId = std::make_pair(std::move(frame), *bufferId); + mBuffers.insert(*bufferId); } else { ALOGE("%s(): Failed to generate VideoFrame or get the buffer id.", __func__); } diff --git a/components/include/v4l2_codec2/components/VideoFramePool.h b/components/include/v4l2_codec2/components/VideoFramePool.h index 2978eed..4e1537e 100644 --- a/components/include/v4l2_codec2/components/VideoFramePool.h +++ b/components/include/v4l2_codec2/components/VideoFramePool.h @@ -44,12 +44,13 @@ public: private: // |blockPool| is the C2BlockPool that we fetch graphic blocks from. + // |maxBufferCount| maximum number of buffer that should should provide to client // |size| is the resolution size of the required graphic blocks. // |pixelFormat| is the pixel format of the required graphic blocks. // |isSecure| indicates the video stream is encrypted or not. // All public methods and the callbacks should be run on |taskRunner|. - VideoFramePool(std::shared_ptr blockPool, const ui::Size& size, - HalPixelFormat pixelFormat, C2MemoryUsage memoryUsage, + VideoFramePool(std::shared_ptr blockPool, const size_t maxBufferCount, + const ui::Size& size, HalPixelFormat pixelFormat, C2MemoryUsage memoryUsage, scoped_refptr<::base::SequencedTaskRunner> taskRunner); bool initialize(); void destroyTask(); @@ -59,6 +60,9 @@ private: void getVideoFrameTask(); void onVideoFrameReady(std::optional frameWithBlockId); + // Returns true if a buffer shall not be handed to client. + bool shouldDropBuffer(uint32_t bufferId); + // Ask |blockPool| to allocate the specified number of buffers. // |bufferCount| is the number of requested buffers. static c2_status_t requestNewBufferSet(C2BlockPool& blockPool, int32_t bufferCount, @@ -73,6 +77,13 @@ private: static bool setNotifyBlockAvailableCb(C2BlockPool& blockPool, ::base::OnceClosure cb); std::shared_ptr mBlockPool; + + // Holds the number of maximum amount of buffers that VideoFramePool + // should provide to client. + size_t mMaxBufferCount; + // Contains known buffer ids that are valid for the pool. + std::set mBuffers; + const ui::Size mSize; const HalPixelFormat mPixelFormat; const C2MemoryUsage mMemoryUsage; -- cgit v1.2.3 From 3ace4ef817bb9fe3627b71df2520ec2b2b2f1790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 10:15:53 +0000 Subject: V4L2DecodeInterface: Switch to C2BufferQueueBlockPool Due to move to Codec 2.0 VNDK 1.2 and implementation of asynchronous graphic buffer fetching, there is no need to use C2VdaBqBlockPool. Limitation of number of fetched buffers is done by C2SurfaceSyncMemory and VideoFramePool. For this reason switching to C2BufferQueueBlockPool. This moves unblocks a dozen of tests failures on Android T. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: Ia36a290146860f68c611da4746cd0375225adc99 (cherry picked from commit c53b55c4f7dd02dd9029d5db226673d740c51a79) --- components/V4L2DecodeInterface.cpp | 2 +- components/VideoFramePool.cpp | 28 +++++++++++----------- plugin_store/V4L2PluginStore.cpp | 7 ++---- .../v4l2_codec2/plugin_store/V4L2AllocatorId.h | 3 +-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/components/V4L2DecodeInterface.cpp b/components/V4L2DecodeInterface.cpp index d22f77b..fb384c6 100644 --- a/components/V4L2DecodeInterface.cpp +++ b/components/V4L2DecodeInterface.cpp @@ -269,7 +269,7 @@ V4L2DecodeInterface::V4L2DecodeInterface(const std::string& name, const C2Allocator::id_t outputAllocators[] = {V4L2AllocatorId::V4L2_BUFFERPOOL}; const C2Allocator::id_t surfaceAllocator = - secureMode ? V4L2AllocatorId::SECURE_GRAPHIC : V4L2AllocatorId::V4L2_BUFFERQUEUE; + secureMode ? V4L2AllocatorId::SECURE_GRAPHIC : C2PlatformAllocatorStore::BUFFERQUEUE; const C2BlockPool::local_id_t outputBlockPools[] = {C2BlockPool::BASIC_GRAPHIC}; addParameter( diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index c8ea842..97eea13 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -17,8 +17,8 @@ #include #include -#include #include +#include #include using android::hardware::graphics::common::V1_0::BufferUsage; @@ -30,11 +30,20 @@ std::optional VideoFramePool::getBufferIdFromGraphicBlock(C2BlockPool& const C2Block2D& block) { ALOGV("%s() blockPool.getAllocatorId() = %u", __func__, blockPool.getAllocatorId()); - if (blockPool.getAllocatorId() == android::V4L2AllocatorId::V4L2_BUFFERPOOL) { + switch (blockPool.getAllocatorId()) { + case V4L2AllocatorId::SECURE_GRAPHIC: + FALLTHROUGH; + case C2PlatformAllocatorStore::BUFFERQUEUE: { + auto dmabufId = android::getDmabufId(block.handle()->data[0]); + if (!dmabufId) { + return std::nullopt; + } + return dmabufId.value(); + } + case V4L2AllocatorId::V4L2_BUFFERPOOL: + FALLTHROUGH; + case V4L2AllocatorId::SECURE_LINEAR: return C2VdaPooledBlockPool::getBufferIdFromGraphicBlock(block); - } else if (blockPool.getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { - C2VdaBqBlockPool* bqPool = static_cast(&blockPool); - return bqPool->getBufferIdFromGraphicBlock(block); } ALOGE("%s(): unknown allocator ID: %u", __func__, blockPool.getAllocatorId()); @@ -50,9 +59,6 @@ c2_status_t VideoFramePool::requestNewBufferSet(C2BlockPool& blockPool, int32_t if (blockPool.getAllocatorId() == android::V4L2AllocatorId::V4L2_BUFFERPOOL) { C2VdaPooledBlockPool* bpPool = static_cast(&blockPool); return bpPool->requestNewBufferSet(bufferCount); - } else if (blockPool.getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { - C2VdaBqBlockPool* bqPool = static_cast(&blockPool); - return bqPool->requestNewBufferSet(bufferCount, size.width, size.height, format, usage); } ALOGE("%s(): unknown allocator ID: %u", __func__, blockPool.getAllocatorId()); @@ -61,12 +67,6 @@ c2_status_t VideoFramePool::requestNewBufferSet(C2BlockPool& blockPool, int32_t // static bool VideoFramePool::setNotifyBlockAvailableCb(C2BlockPool& blockPool, ::base::OnceClosure cb) { - ALOGV("%s() blockPool.getAllocatorId() = %u", __func__, blockPool.getAllocatorId()); - - if (blockPool.getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { - C2VdaBqBlockPool* bqPool = static_cast(&blockPool); - return bqPool->setNotifyBlockAvailableCb(std::move(cb)); - } return false; } diff --git a/plugin_store/V4L2PluginStore.cpp b/plugin_store/V4L2PluginStore.cpp index 2d53c5f..b116759 100644 --- a/plugin_store/V4L2PluginStore.cpp +++ b/plugin_store/V4L2PluginStore.cpp @@ -12,10 +12,10 @@ #include #include +#include #include #include -#include #include #include #include @@ -70,14 +70,11 @@ C2BlockPool* createBlockPool(C2Allocator::id_t allocatorId, C2BlockPool::local_i case V4L2AllocatorId::V4L2_BUFFERPOOL: return new C2VdaPooledBlockPool(allocator, poolId); - case V4L2AllocatorId::V4L2_BUFFERQUEUE: - return new C2VdaBqBlockPool(allocator, poolId); - case V4L2AllocatorId::SECURE_LINEAR: return new C2PooledBlockPool(allocator, poolId); case V4L2AllocatorId::SECURE_GRAPHIC: - return new C2VdaBqBlockPool(allocator, poolId); + return new C2BufferQueueBlockPool(allocator, poolId); default: ALOGE("%s(): Unknown allocator id=%u", __func__, allocatorId); diff --git a/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h b/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h index 0808963..45a470c 100644 --- a/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h +++ b/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h @@ -12,8 +12,7 @@ namespace V4L2AllocatorId { // The allocator ids used for V4L2DecodeComponent. enum : C2AllocatorStore::id_t { - V4L2_BUFFERQUEUE = C2PlatformAllocatorStore::PLATFORM_END, - V4L2_BUFFERPOOL, + V4L2_BUFFERPOOL = C2PlatformAllocatorStore::PLATFORM_END, SECURE_LINEAR, SECURE_GRAPHIC, }; -- cgit v1.2.3 From 9613d2acd87b0a4db79b5226930ba5c7a3a1c78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 10:30:51 +0000 Subject: V4L2DecodeInterface: Switch to C2PooledBlockPool With implementation of limitation of number of fetched buffers inside VideoFramePool, there is no need to use C2VdaPooledBlockPool, hence switching to C2PooledBlockPool. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: Iaac647c0ddbeba1e820bb2daf63e94894eb2b424 (cherry picked from commit db98c8b058f8a97bfcbf140a5423852bf772c45a) --- components/VideoFramePool.cpp | 28 ++++++++++++++++++---------- plugin_store/V4L2PluginStore.cpp | 3 +-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index 97eea13..bb892a8 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -10,6 +10,9 @@ #include #include +#include +#include + #include #include #include @@ -17,11 +20,11 @@ #include #include -#include #include #include using android::hardware::graphics::common::V1_0::BufferUsage; +using android::hardware::media::bufferpool::BufferPoolData; namespace android { @@ -42,8 +45,20 @@ std::optional VideoFramePool::getBufferIdFromGraphicBlock(C2BlockPool& } case V4L2AllocatorId::V4L2_BUFFERPOOL: FALLTHROUGH; - case V4L2AllocatorId::SECURE_LINEAR: - return C2VdaPooledBlockPool::getBufferIdFromGraphicBlock(block); + case V4L2AllocatorId::SECURE_LINEAR: { + std::shared_ptr<_C2BlockPoolData> blockPoolData = + _C2BlockFactory::GetGraphicBlockPoolData(block); + if (blockPoolData->getType() != _C2BlockPoolData::TYPE_BUFFERPOOL) { + ALOGE("Obtained C2GraphicBlock is not bufferpool-backed."); + return std::nullopt; + } + std::shared_ptr bpData; + if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData) || !bpData) { + ALOGE("BufferPoolData unavailable in block."); + return std::nullopt; + } + return bpData->mId; + } } ALOGE("%s(): unknown allocator ID: %u", __func__, blockPool.getAllocatorId()); @@ -54,13 +69,6 @@ std::optional VideoFramePool::getBufferIdFromGraphicBlock(C2BlockPool& c2_status_t VideoFramePool::requestNewBufferSet(C2BlockPool& blockPool, int32_t bufferCount, const ui::Size& size, uint32_t format, C2MemoryUsage usage) { - ALOGV("%s() blockPool.getAllocatorId() = %u", __func__, blockPool.getAllocatorId()); - - if (blockPool.getAllocatorId() == android::V4L2AllocatorId::V4L2_BUFFERPOOL) { - C2VdaPooledBlockPool* bpPool = static_cast(&blockPool); - return bpPool->requestNewBufferSet(bufferCount); - } - ALOGE("%s(): unknown allocator ID: %u", __func__, blockPool.getAllocatorId()); return C2_BAD_VALUE; } diff --git a/plugin_store/V4L2PluginStore.cpp b/plugin_store/V4L2PluginStore.cpp index b116759..a8cdab6 100644 --- a/plugin_store/V4L2PluginStore.cpp +++ b/plugin_store/V4L2PluginStore.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -68,7 +67,7 @@ C2BlockPool* createBlockPool(C2Allocator::id_t allocatorId, C2BlockPool::local_i switch (allocatorId) { case V4L2AllocatorId::V4L2_BUFFERPOOL: - return new C2VdaPooledBlockPool(allocator, poolId); + return new C2PooledBlockPool(allocator, poolId); case V4L2AllocatorId::SECURE_LINEAR: return new C2PooledBlockPool(allocator, poolId); -- cgit v1.2.3 From 8e52544fb84c17674c16ff66da234197bf429fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 10:46:30 +0000 Subject: VideoFramePool: Remove unused methods This CL removes requestNewBufferSet and setNotifyBlockAvailableCb methods, that became unused after switch to C2BufferQueueBlockPool and C2PooledBlockPool. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: I6085cb7d5a7118d2b81d1f6d9d533b98fc978fa1 (cherry picked from commit d73cbf57bde3c2d9563d6fba2e001c560ec3f3e3) --- components/VideoFramePool.cpp | 18 ------------------ .../include/v4l2_codec2/components/VideoFramePool.h | 10 ---------- 2 files changed, 28 deletions(-) diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index bb892a8..070cc40 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -65,19 +65,6 @@ std::optional VideoFramePool::getBufferIdFromGraphicBlock(C2BlockPool& return std::nullopt; } -// static -c2_status_t VideoFramePool::requestNewBufferSet(C2BlockPool& blockPool, int32_t bufferCount, - const ui::Size& size, uint32_t format, - C2MemoryUsage usage) { - ALOGE("%s(): unknown allocator ID: %u", __func__, blockPool.getAllocatorId()); - return C2_BAD_VALUE; -} - -// static -bool VideoFramePool::setNotifyBlockAvailableCb(C2BlockPool& blockPool, ::base::OnceClosure cb) { - return false; -} - // static std::unique_ptr VideoFramePool::Create( std::shared_ptr blockPool, const size_t numBuffers, const ui::Size& size, @@ -94,11 +81,6 @@ std::unique_ptr VideoFramePool::Create( } const C2MemoryUsage memoryUsage(usage); - if (requestNewBufferSet(*blockPool, numBuffers, size, static_cast(pixelFormat), - memoryUsage) != C2_OK) { - return nullptr; - } - std::unique_ptr pool = ::base::WrapUnique(new VideoFramePool(std::move(blockPool), numBuffers, size, pixelFormat, memoryUsage, std::move(taskRunner))); diff --git a/components/include/v4l2_codec2/components/VideoFramePool.h b/components/include/v4l2_codec2/components/VideoFramePool.h index 4e1537e..6bebc37 100644 --- a/components/include/v4l2_codec2/components/VideoFramePool.h +++ b/components/include/v4l2_codec2/components/VideoFramePool.h @@ -63,19 +63,9 @@ private: // Returns true if a buffer shall not be handed to client. bool shouldDropBuffer(uint32_t bufferId); - // Ask |blockPool| to allocate the specified number of buffers. - // |bufferCount| is the number of requested buffers. - static c2_status_t requestNewBufferSet(C2BlockPool& blockPool, int32_t bufferCount, - const ui::Size& size, uint32_t format, - C2MemoryUsage usage); - static std::optional getBufferIdFromGraphicBlock(C2BlockPool& blockPool, const C2Block2D& block); - // Ask |blockPool| to notify when a block is available via |cb|. - // Return true if |blockPool| supports notifying buffer available. - static bool setNotifyBlockAvailableCb(C2BlockPool& blockPool, ::base::OnceClosure cb); - std::shared_ptr mBlockPool; // Holds the number of maximum amount of buffers that VideoFramePool -- cgit v1.2.3 From 7cdc36b64189fa67bcb1a218f49fe4798b4d6e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 7 Mar 2023 10:43:44 +0000 Subject: plugin_store: Remove unused code This CL removes unused source code files, since classes inside of them are no longer used in the component. Removed classes are: * C2VdaBqBlockPool * C2VdaPooledBlockPool * H2BGraphicBufferProducer Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: I0fc53c942ecb44bde246fca72234a176acb47122 (cherry picked from commit 347ef4623d3a6b96b36f699ecfe65316b888e315) --- components/V4L2DecodeComponent.cpp | 1 - plugin_store/Android.bp | 3 - plugin_store/C2VdaBqBlockPool.cpp | 967 --------------------- plugin_store/C2VdaPooledBlockPool.cpp | 86 -- plugin_store/H2BGraphicBufferProducer.cpp | 287 ------ .../v4l2_codec2/plugin_store/C2VdaBqBlockPool.h | 108 --- .../plugin_store/C2VdaPooledBlockPool.h | 53 -- .../plugin_store/H2BGraphicBufferProducer.h | 48 - 8 files changed, 1553 deletions(-) delete mode 100644 plugin_store/C2VdaBqBlockPool.cpp delete mode 100644 plugin_store/C2VdaPooledBlockPool.cpp delete mode 100644 plugin_store/H2BGraphicBufferProducer.cpp delete mode 100644 plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h delete mode 100644 plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h delete mode 100644 plugin_store/include/v4l2_codec2/plugin_store/H2BGraphicBufferProducer.h diff --git a/components/V4L2DecodeComponent.cpp b/components/V4L2DecodeComponent.cpp index 456f3c4..2770b1e 100644 --- a/components/V4L2DecodeComponent.cpp +++ b/components/V4L2DecodeComponent.cpp @@ -30,7 +30,6 @@ #include #include #include -#include namespace android { namespace { diff --git a/plugin_store/Android.bp b/plugin_store/Android.bp index 621cbfc..6427512 100644 --- a/plugin_store/Android.bp +++ b/plugin_store/Android.bp @@ -16,10 +16,7 @@ cc_library_shared { ], srcs: [ - "C2VdaBqBlockPool.cpp", - "C2VdaPooledBlockPool.cpp", "DmabufHelpers.cpp", - "H2BGraphicBufferProducer.cpp", "V4L2PluginStore.cpp", "VendorAllocatorLoader.cpp", ], diff --git a/plugin_store/C2VdaBqBlockPool.cpp b/plugin_store/C2VdaBqBlockPool.cpp deleted file mode 100644 index 3356885..0000000 --- a/plugin_store/C2VdaBqBlockPool.cpp +++ /dev/null @@ -1,967 +0,0 @@ -// 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 "C2VdaBqBlockPool" - -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace android { -namespace { - -// The wait time for acquire fence in milliseconds. The normal display is 60Hz, -// which period is 16ms. We choose 2x period as timeout. -constexpr int kFenceWaitTimeMs = 32; - -// The default maximum dequeued buffer count of IGBP. Currently we don't use -// this value to restrict the count of allocated buffers, so we choose a huge -// enough value here. -constexpr int kMaxDequeuedBufferCount = 32u; - -} // namespace - -using namespace std::chrono_literals; - -// Type for IGBP slot index. -using slot_t = int32_t; - -using ::android::BufferQueueDefs::BUFFER_NEEDS_REALLOCATION; -using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS; -using ::android::hardware::Return; -using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener; - -static c2_status_t asC2Error(status_t err) { - switch (err) { - case OK: - return C2_OK; - case NO_INIT: - return C2_NO_INIT; - case BAD_VALUE: - return C2_BAD_VALUE; - case TIMED_OUT: - return C2_TIMED_OUT; - case WOULD_BLOCK: - return C2_BLOCKING; - case NO_MEMORY: - return C2_NO_MEMORY; - } - return C2_CORRUPTED; -} - -// Convert GraphicBuffer to C2GraphicAllocation and wrap producer id and slot index. -std::shared_ptr ConvertGraphicBuffer2C2Allocation( - sp graphicBuffer, const uint64_t igbpId, const slot_t slot, - C2Allocator* const allocator) { - ALOGV("%s(idbpId=0x%" PRIx64 ", slot=%d)", __func__, igbpId, slot); - - C2Handle* c2Handle = WrapNativeCodec2GrallocHandle( - graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height, - graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride, - graphicBuffer->getGenerationNumber(), igbpId, slot); - if (!c2Handle) { - ALOGE("WrapNativeCodec2GrallocHandle() failed"); - return nullptr; - } - - std::shared_ptr allocation; - const auto err = allocator->priorGraphicAllocation(c2Handle, &allocation); - if (err != C2_OK) { - ALOGE("C2Allocator::priorGraphicAllocation() failed: %d", err); - native_handle_close(c2Handle); - native_handle_delete(c2Handle); - return nullptr; - } - - return allocation; -} - -// This class is used to notify the listener when a certain event happens. -class EventNotifier : public virtual android::RefBase { -public: - class Listener { - public: - virtual ~Listener() = default; - - // Called by EventNotifier when a certain event happens. - virtual void onEventNotified() = 0; - }; - - explicit EventNotifier(std::weak_ptr listener) : mListener(std::move(listener)) {} - virtual ~EventNotifier() = default; - -protected: - void notify() { - ALOGV("%s()", __func__); - std::shared_ptr listener = mListener.lock(); - if (listener) { - listener->onEventNotified(); - } - } - - std::weak_ptr mListener; -}; - -// Notifies the listener when the connected IGBP releases buffers. -class BufferReleasedNotifier : public EventNotifier, public HProducerListener { -public: - using EventNotifier::EventNotifier; - ~BufferReleasedNotifier() override = default; - - // HProducerListener implementation - Return onBuffersReleased(uint32_t count) override { - ALOGV("%s(%u)", __func__, count); - if (count > 0) { - notify(); - } - return {}; - } -}; - -// IGBP expects its user (e.g. C2VdaBqBlockPool) to keep the mapping from dequeued slot index to -// graphic buffers. Also, C2VdaBqBlockPool guaratees to fetch N fixed set of buffers with buffer -// identifier. So this class stores the mapping from slot index to buffers and the mapping from -// buffer unique ID to buffers. -// This class also implements functionalities for buffer migration when surface switching. Buffers -// are owned by either component (i.e. local buffers) or CCodec framework (i.e. remote buffers). -// When switching surface, the ccodec framework migrates remote buffers to the new surfaces. Then -// C2VdaBqBlockPool migrates local buffers. However, some buffers might be lost during migration. -// We assume that there are enough buffers migrated to the new surface to continue the playback. -// After |NUM_BUFFER_SLOTS| amount of buffers are dequeued from new surface, all buffers should -// be dequeued at least once. Then we treat the missing buffer as lost, and attach these bufers to -// the new surface. -class TrackedGraphicBuffers { -public: - using value_type = std::tuple>; - - TrackedGraphicBuffers() = default; - ~TrackedGraphicBuffers() = default; - - void reset() { - mSlotId2GraphicBuffer.clear(); - mSlotId2PoolData.clear(); - mAllocationsRegistered.clear(); - mAllocationsToBeMigrated.clear(); - mMigrateLostBufferCounter = 0; - mGenerationToBeMigrated = 0; - } - - void registerUniqueId(unique_id_t uniqueId, std::shared_ptr allocation) { - ALOGV("%s(uniqueId=%u)", __func__, uniqueId); - ALOG_ASSERT(allocation != nullptr); - - mAllocationsRegistered[uniqueId] = std::move(allocation); - } - - std::shared_ptr getRegisteredAllocation(unique_id_t uniqueId) { - const auto iter = mAllocationsRegistered.find(uniqueId); - ALOG_ASSERT(iter != mAllocationsRegistered.end()); - - return iter->second; - } - - bool hasUniqueId(unique_id_t uniqueId) const { - return mAllocationsRegistered.find(uniqueId) != mAllocationsRegistered.end() || - mAllocationsToBeMigrated.find(uniqueId) != mAllocationsToBeMigrated.end(); - } - - void updateSlotBuffer(slot_t slotId, unique_id_t uniqueId, sp slotBuffer) { - ALOGV("%s(slotId=%d)", __func__, slotId); - ALOG_ASSERT(slotBuffer != nullptr); - - mSlotId2GraphicBuffer[slotId] = std::make_pair(uniqueId, std::move(slotBuffer)); - } - - std::pair> getSlotBuffer(slot_t slotId) const { - const auto iter = mSlotId2GraphicBuffer.find(slotId); - ALOG_ASSERT(iter != mSlotId2GraphicBuffer.end()); - - return iter->second; - } - - bool hasSlotId(slot_t slotId) const { - return mSlotId2GraphicBuffer.find(slotId) != mSlotId2GraphicBuffer.end(); - } - - void updatePoolData(slot_t slotId, std::weak_ptr poolData) { - ALOGV("%s(slotId=%d)", __func__, slotId); - ALOG_ASSERT(hasSlotId(slotId)); - - mSlotId2PoolData[slotId] = std::move(poolData); - } - - bool migrateLocalBuffers(H2BGraphicBufferProducer* const producer, uint64_t producerId, - uint32_t generation, uint64_t usage) { - ALOGV("%s(producerId=%" PRIx64 ", generation=%u, usage=%" PRIx64 ")", __func__, producerId, - generation, usage); - - mGenerationToBeMigrated = generation; - mUsageToBeMigrated = usage; - - // Move all buffers to mAllocationsToBeMigrated. - for (auto& pair : mAllocationsRegistered) { - if (!mAllocationsToBeMigrated.insert(pair).second) { - ALOGE("%s() duplicated uniqueId=%u", __func__, pair.first); - return false; - } - } - mAllocationsRegistered.clear(); - - ALOGV("%s(producerId=%" PRIx64 ", generation=%u, usage=%" PRIx64 ") before %s", __func__, - producerId, generation, usage, debugString().c_str()); - - // Migrate local buffers. - std::map>> newSlotId2GraphicBuffer; - std::map> newSlotId2PoolData; - for (const auto& pair : mSlotId2PoolData) { - auto oldSlot = pair.first; - auto poolData = pair.second.lock(); - if (!poolData) { - continue; - } - - unique_id_t uniqueId; - sp slotBuffer; - std::shared_ptr syncMem; - std::tie(uniqueId, slotBuffer) = getSlotBuffer(oldSlot); - slot_t newSlot = poolData->migrate(producer->getBase(), mGenerationToBeMigrated, - mUsageToBeMigrated, producerId, slotBuffer, - slotBuffer->getGenerationNumber(), - syncMem); - if (newSlot < 0) { - ALOGW("%s() Failed to migrate local buffer: uniqueId=%u, oldSlot=%d", __func__, - uniqueId, oldSlot); - continue; - } - - ALOGV("%s() migrated buffer: uniqueId=%u, oldSlot=%d, newSlot=%d", __func__, uniqueId, - oldSlot, newSlot); - newSlotId2GraphicBuffer[newSlot] = std::make_pair(uniqueId, std::move(slotBuffer)); - newSlotId2PoolData[newSlot] = std::move(poolData); - - if (!moveBufferToRegistered(uniqueId)) { - ALOGE("%s() failed to move buffer to registered, uniqueId=%u", __func__, uniqueId); - return false; - } - } - mSlotId2GraphicBuffer = std::move(newSlotId2GraphicBuffer); - mSlotId2PoolData = std::move(newSlotId2PoolData); - - // Choose a big enough number to ensure all buffer should be dequeued at least once. - mMigrateLostBufferCounter = NUM_BUFFER_SLOTS; - ALOGD("%s() migrated %zu local buffers", __func__, mAllocationsRegistered.size()); - return true; - } - - bool needMigrateLostBuffers() const { - return mMigrateLostBufferCounter == 0 && !mAllocationsToBeMigrated.empty(); - } - - status_t migrateLostBuffer(C2Allocator* const allocator, - H2BGraphicBufferProducer* const producer, const uint64_t producerId, - slot_t* newSlot) { - ALOGV("%s() %s", __func__, debugString().c_str()); - - if (!needMigrateLostBuffers()) { - return NO_INIT; - } - - auto iter = mAllocationsToBeMigrated.begin(); - const unique_id_t uniqueId = iter->first; - const C2Handle* c2Handle = iter->second->handle(); - - // Convert C2GraphicAllocation to GraphicBuffer, and update generation and usage. - uint32_t width, height, format, stride, igbpSlot, generation; - uint64_t usage, igbpId; - _UnwrapNativeCodec2GrallocMetadata(c2Handle, &width, &height, &format, &usage, &stride, - &generation, &igbpId, &igbpSlot); - native_handle_t* grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle); - sp graphicBuffer = - new GraphicBuffer(grallocHandle, GraphicBuffer::CLONE_HANDLE, width, height, format, - 1, mUsageToBeMigrated, stride); - native_handle_delete(grallocHandle); - if (graphicBuffer->initCheck() != android::NO_ERROR) { - ALOGE("Failed to create GraphicBuffer: %d", graphicBuffer->initCheck()); - return false; - } - graphicBuffer->setGenerationNumber(mGenerationToBeMigrated); - - // Attach GraphicBuffer to producer. - const auto attachStatus = producer->attachBuffer(graphicBuffer, newSlot); - if (attachStatus == TIMED_OUT || attachStatus == INVALID_OPERATION) { - ALOGV("%s(): No free slot yet.", __func__); - return TIMED_OUT; - } - if (attachStatus != OK) { - ALOGE("%s(): Failed to attach buffer to new producer: %d", __func__, attachStatus); - return attachStatus; - } - ALOGD("%s(), migrated lost buffer uniqueId=%u to slot=%d", __func__, uniqueId, *newSlot); - updateSlotBuffer(*newSlot, uniqueId, graphicBuffer); - - // Wrap the new GraphicBuffer to C2GraphicAllocation and register it. - std::shared_ptr allocation = - ConvertGraphicBuffer2C2Allocation(graphicBuffer, producerId, *newSlot, allocator); - if (!allocation) { - return UNKNOWN_ERROR; - } - registerUniqueId(uniqueId, std::move(allocation)); - - // Note: C2ArcProtectedGraphicAllocator releases the protected buffers if all the - // corrresponding C2GraphicAllocations are released. To prevent the protected buffer is - // released and then allocated again, we release the old C2GraphicAllocation after the new - // one has been created. - mAllocationsToBeMigrated.erase(iter); - - return OK; - } - - void onBufferDequeued(slot_t slotId) { - ALOGV("%s(slotId=%d)", __func__, slotId); - unique_id_t uniqueId; - std::tie(uniqueId, std::ignore) = getSlotBuffer(slotId); - - moveBufferToRegistered(uniqueId); - if (mMigrateLostBufferCounter > 0) { - --mMigrateLostBufferCounter; - } - } - - size_t size() const { return mAllocationsRegistered.size() + mAllocationsToBeMigrated.size(); } - - std::string debugString() const { - std::stringstream ss; - ss << "tracked size: " << size() << std::endl; - ss << " registered uniqueIds: "; - for (const auto& pair : mAllocationsRegistered) { - ss << pair.first << ", "; - } - ss << std::endl; - ss << " to-be-migrated uniqueIds: "; - for (const auto& pair : mAllocationsToBeMigrated) { - ss << pair.first << ", "; - } - ss << std::endl; - ss << " Count down for lost buffer migration: " << mMigrateLostBufferCounter; - return ss.str(); - } - -private: - bool moveBufferToRegistered(unique_id_t uniqueId) { - ALOGV("%s(uniqueId=%u)", __func__, uniqueId); - auto iter = mAllocationsToBeMigrated.find(uniqueId); - if (iter == mAllocationsToBeMigrated.end()) { - return false; - } - if (!mAllocationsRegistered.insert(*iter).second) { - ALOGE("%s() duplicated uniqueId=%u", __func__, uniqueId); - return false; - } - mAllocationsToBeMigrated.erase(iter); - - return true; - } - - // Mapping from IGBP slots to the corresponding graphic buffers. - std::map>> mSlotId2GraphicBuffer; - - // Mapping from IGBP slots to the corresponding pool data. - std::map> mSlotId2PoolData; - - // Track the buffers registered at the current producer. - std::map> mAllocationsRegistered; - - // Track the buffers that should be migrated to the current producer. - std::map> mAllocationsToBeMigrated; - - // The counter for migrating lost buffers. Count down when a buffer is - // dequeued from IGBP. When it goes to 0, then we treat the remaining - // buffers at |mAllocationsToBeMigrated| lost, and migrate them to - // current IGBP. - size_t mMigrateLostBufferCounter = 0; - - // The generation and usage of the current IGBP, used to migrate buffers. - uint32_t mGenerationToBeMigrated = 0; - uint64_t mUsageToBeMigrated = 0; -}; - -class C2VdaBqBlockPool::Impl : public std::enable_shared_from_this, - public EventNotifier::Listener { -public: - using HGraphicBufferProducer = C2VdaBqBlockPool::HGraphicBufferProducer; - - explicit Impl(const std::shared_ptr& allocator); - // TODO: should we detach buffers on producer if any on destructor? - ~Impl() = default; - - // EventNotifier::Listener implementation. - void onEventNotified() override; - - c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, - std::shared_ptr* block /* nonnull */); - void setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback& renderCallback); - void configureProducer(const sp& producer); - c2_status_t requestNewBufferSet(int32_t bufferCount, uint32_t width, uint32_t height, - uint32_t format, C2MemoryUsage usage); - bool setNotifyBlockAvailableCb(::base::OnceClosure cb); - std::optional getBufferIdFromGraphicBlock(const C2Block2D& block); - -private: - // Requested buffer formats. - struct BufferFormat { - BufferFormat(uint32_t width, uint32_t height, uint32_t pixelFormat, - C2AndroidMemoryUsage androidUsage) - : mWidth(width), mHeight(height), mPixelFormat(pixelFormat), mUsage(androidUsage) {} - BufferFormat() = default; - - uint32_t mWidth = 0; - uint32_t mHeight = 0; - uint32_t mPixelFormat = 0; - C2AndroidMemoryUsage mUsage = C2MemoryUsage(0); - }; - - status_t getFreeSlotLocked(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, slot_t* slot, sp* fence); - - // Queries the generation and usage flags from the given producer by dequeuing and requesting a - // buffer (the buffer is then detached and freed). - status_t queryGenerationAndUsageLocked(uint32_t width, uint32_t height, uint32_t pixelFormat, - C2AndroidMemoryUsage androidUsage, uint32_t* generation, - uint64_t* usage); - - // Wait the fence. If any error occurs, cancel the buffer back to the producer. - status_t waitFence(slot_t slot, sp fence); - - // Call mProducer's allowAllocation if needed. - status_t allowAllocation(bool allow); - - const std::shared_ptr mAllocator; - - std::unique_ptr mProducer; - uint64_t mProducerId = 0; - bool mAllowAllocation = false; - - C2BufferQueueBlockPool::OnRenderCallback mRenderCallback; - - // Function mutex to lock at the start of each API function call for protecting the - // synchronization of all member variables. - std::mutex mMutex; - - TrackedGraphicBuffers mTrackedGraphicBuffers; - - // Number of buffers requested on requestNewBufferSet() call. - size_t mBuffersRequested = 0u; - // Currently requested buffer formats. - BufferFormat mBufferFormat; - - // Listener for buffer release events. - sp mFetchBufferNotifier; - - std::mutex mBufferReleaseMutex; - // Set to true when the buffer release event is triggered after dequeueing buffer from IGBP - // times out. Reset when fetching new slot times out, or |mNotifyBlockAvailableCb| is executed. - bool mBufferReleasedAfterTimedOut GUARDED_BY(mBufferReleaseMutex) = false; - // The callback to notify the caller the buffer is available. - ::base::OnceClosure mNotifyBlockAvailableCb GUARDED_BY(mBufferReleaseMutex); - - // Set to true if any error occurs at previous configureProducer(). - bool mConfigureProducerError = false; -}; - -C2VdaBqBlockPool::Impl::Impl(const std::shared_ptr& allocator) - : mAllocator(allocator) {} - -c2_status_t C2VdaBqBlockPool::Impl::fetchGraphicBlock( - uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage, - std::shared_ptr* block /* nonnull */) { - ALOGV("%s(%ux%u)", __func__, width, height); - std::lock_guard lock(mMutex); - - if (width != mBufferFormat.mWidth || height != mBufferFormat.mHeight || - format != mBufferFormat.mPixelFormat || usage.expected != mBufferFormat.mUsage.expected) { - ALOGE("%s(): buffer format (%ux%u, format=%u, usage=%" PRIx64 - ") is different from requested format (%ux%u, format=%u, usage=%" PRIx64 ")", - __func__, width, height, format, usage.expected, mBufferFormat.mWidth, - mBufferFormat.mHeight, mBufferFormat.mPixelFormat, mBufferFormat.mUsage.expected); - return C2_BAD_VALUE; - } - if (mConfigureProducerError || !mProducer) { - ALOGE("%s(): error occurred at previous configureProducer()", __func__); - return C2_CORRUPTED; - } - - slot_t slot; - sp fence = new Fence(); - const auto status = getFreeSlotLocked(width, height, format, usage, &slot, &fence); - if (status != OK) { - return asC2Error(status); - } - - unique_id_t uniqueId; - sp slotBuffer; - std::tie(uniqueId, slotBuffer) = mTrackedGraphicBuffers.getSlotBuffer(slot); - ALOGV("%s(): dequeued slot=%d uniqueId=%u", __func__, slot, uniqueId); - - if (!mTrackedGraphicBuffers.hasUniqueId(uniqueId)) { - if (mTrackedGraphicBuffers.size() >= mBuffersRequested) { - // The dequeued slot has a pre-allocated buffer whose size and format is as same as - // currently requested (but was not dequeued during allocation cycle). Just detach it to - // free this slot. And try dequeueBuffer again. - ALOGD("dequeued a new slot %d but already allocated enough buffers. Detach it.", slot); - - if (mProducer->detachBuffer(slot) != OK) { - return C2_CORRUPTED; - } - - const auto allocationStatus = allowAllocation(false); - if (allocationStatus != OK) { - return asC2Error(allocationStatus); - } - return C2_TIMED_OUT; - } - - std::shared_ptr allocation = - ConvertGraphicBuffer2C2Allocation(slotBuffer, mProducerId, slot, mAllocator.get()); - if (!allocation) { - return C2_CORRUPTED; - } - mTrackedGraphicBuffers.registerUniqueId(uniqueId, std::move(allocation)); - - ALOGV("%s(): mTrackedGraphicBuffers.size=%zu", __func__, mTrackedGraphicBuffers.size()); - if (mTrackedGraphicBuffers.size() == mBuffersRequested) { - ALOGV("Tracked IGBP slots: %s", mTrackedGraphicBuffers.debugString().c_str()); - // Already allocated enough buffers, set allowAllocation to false to restrict the - // eligible slots to allocated ones for future dequeue. - const auto allocationStatus = allowAllocation(false); - if (allocationStatus != OK) { - return asC2Error(allocationStatus); - } - } - } - - std::shared_ptr syncMem; - // TODO: the |owner| argument should be set correctly. - std::shared_ptr allocation = - mTrackedGraphicBuffers.getRegisteredAllocation(uniqueId); - auto poolData = std::make_shared( - slotBuffer->getGenerationNumber(), mProducerId, slot, std::make_shared(0), - mProducer->getBase(), syncMem); - mTrackedGraphicBuffers.updatePoolData(slot, poolData); - *block = _C2BlockFactory::CreateGraphicBlock(std::move(allocation), std::move(poolData)); - if (*block == nullptr) { - ALOGE("failed to create GraphicBlock: no memory"); - return C2_NO_MEMORY; - } - - // Wait for acquire fence at the last point of returning buffer. - if (fence) { - const auto fenceStatus = waitFence(slot, fence); - if (fenceStatus != OK) { - return asC2Error(fenceStatus); - } - - if (mRenderCallback) { - nsecs_t signalTime = fence->getSignalTime(); - if (signalTime >= 0 && signalTime < INT64_MAX) { - mRenderCallback(mProducerId, slot, signalTime); - } else { - ALOGV("got fence signal time of %" PRId64 " nsec", signalTime); - } - } - } - - return C2_OK; -} - -status_t C2VdaBqBlockPool::Impl::getFreeSlotLocked(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, slot_t* slot, - sp* fence) { - if (mTrackedGraphicBuffers.needMigrateLostBuffers()) { - slot_t newSlot; - if (mTrackedGraphicBuffers.migrateLostBuffer(mAllocator.get(), mProducer.get(), mProducerId, - &newSlot) == OK) { - ALOGV("%s(): migrated buffer: slot=%d", __func__, newSlot); - *slot = newSlot; - return OK; - } - } - - // Dequeue a free slot from IGBP. - ALOGV("%s(): try to dequeue free slot from IGBP.", __func__); - const auto dequeueStatus = mProducer->dequeueBuffer(width, height, format, usage, slot, fence); - if (dequeueStatus == TIMED_OUT) { - std::lock_guard lock(mBufferReleaseMutex); - mBufferReleasedAfterTimedOut = false; - } - if (dequeueStatus != OK && dequeueStatus != BUFFER_NEEDS_REALLOCATION) { - return dequeueStatus; - } - - // Call requestBuffer to update GraphicBuffer for the slot and obtain the reference. - if (!mTrackedGraphicBuffers.hasSlotId(*slot) || dequeueStatus == BUFFER_NEEDS_REALLOCATION) { - sp slotBuffer = new GraphicBuffer(); - const auto requestStatus = mProducer->requestBuffer(*slot, &slotBuffer); - if (requestStatus != OK) { - mProducer->cancelBuffer(*slot, *fence); - return requestStatus; - } - - const auto uniqueId = getDmabufId(slotBuffer->handle->data[0]); - if (!uniqueId) { - ALOGE("%s(): failed to get uniqueId of GraphicBuffer from slot=%d", __func__, *slot); - return UNKNOWN_ERROR; - } - mTrackedGraphicBuffers.updateSlotBuffer(*slot, *uniqueId, std::move(slotBuffer)); - } - - ALOGV("%s(%ux%u): dequeued slot=%d", __func__, mBufferFormat.mWidth, mBufferFormat.mHeight, - *slot); - mTrackedGraphicBuffers.onBufferDequeued(*slot); - return OK; -} - -void C2VdaBqBlockPool::Impl::onEventNotified() { - ALOGV("%s()", __func__); - ::base::OnceClosure outputCb; - { - std::lock_guard lock(mBufferReleaseMutex); - - mBufferReleasedAfterTimedOut = true; - if (mNotifyBlockAvailableCb) { - mBufferReleasedAfterTimedOut = false; - outputCb = std::move(mNotifyBlockAvailableCb); - } - } - - // Calling the callback outside the lock to avoid the deadlock. - if (outputCb) { - std::move(outputCb).Run(); - } -} - -status_t C2VdaBqBlockPool::Impl::queryGenerationAndUsageLocked(uint32_t width, uint32_t height, - uint32_t pixelFormat, - C2AndroidMemoryUsage androidUsage, - uint32_t* generation, - uint64_t* usage) { - ALOGV("%s()", __func__); - - sp fence = new Fence(); - slot_t slot; - const auto dequeueStatus = - mProducer->dequeueBuffer(width, height, pixelFormat, androidUsage, &slot, &fence); - if (dequeueStatus != OK && dequeueStatus != BUFFER_NEEDS_REALLOCATION) { - return dequeueStatus; - } - - // Call requestBuffer to allocate buffer for the slot and obtain the reference. - // Get generation number here. - sp slotBuffer = new GraphicBuffer(); - const auto requestStatus = mProducer->requestBuffer(slot, &slotBuffer); - - // Detach and delete the temporary buffer. - const auto detachStatus = mProducer->detachBuffer(slot); - if (detachStatus != OK) { - return detachStatus; - } - - // Check requestBuffer return flag. - if (requestStatus != OK) { - return requestStatus; - } - - // Get generation number and usage from the slot buffer. - *usage = slotBuffer->getUsage(); - *generation = slotBuffer->getGenerationNumber(); - ALOGV("Obtained from temp buffer: generation = %u, usage = %" PRIu64 "", *generation, *usage); - return OK; -} - -status_t C2VdaBqBlockPool::Impl::waitFence(slot_t slot, sp fence) { - const auto fenceStatus = fence->wait(kFenceWaitTimeMs); - if (fenceStatus == OK) { - return OK; - } - - const auto cancelStatus = mProducer->cancelBuffer(slot, fence); - if (cancelStatus != OK) { - ALOGE("%s(): failed to cancelBuffer(slot=%d)", __func__, slot); - return cancelStatus; - } - - if (fenceStatus == -ETIME) { // fence wait timed out - ALOGV("%s(): buffer (slot=%d) fence wait timed out", __func__, slot); - return TIMED_OUT; - } - ALOGE("buffer fence wait error: %d", fenceStatus); - return fenceStatus; -} - -void C2VdaBqBlockPool::Impl::setRenderCallback( - const C2BufferQueueBlockPool::OnRenderCallback& renderCallback) { - ALOGV("setRenderCallback"); - std::lock_guard lock(mMutex); - mRenderCallback = renderCallback; -} - -c2_status_t C2VdaBqBlockPool::Impl::requestNewBufferSet(int32_t bufferCount, uint32_t width, - uint32_t height, uint32_t format, - C2MemoryUsage usage) { - ALOGV("%s(bufferCount=%d, size=%ux%u, format=0x%x, usage=%" PRIu64 ")", __func__, bufferCount, - width, height, format, usage.expected); - - if (bufferCount <= 0) { - ALOGE("Invalid requested buffer count = %d", bufferCount); - return C2_BAD_VALUE; - } - - std::lock_guard lock(mMutex); - if (!mProducer) { - ALOGD("No HGraphicBufferProducer is configured..."); - return C2_NO_INIT; - } - if (mBuffersRequested == static_cast(bufferCount) && mBufferFormat.mWidth == width && - mBufferFormat.mHeight == height && mBufferFormat.mPixelFormat == format && - mBufferFormat.mUsage.expected == usage.expected) { - ALOGD("%s() Request the same format and amount of buffers, skip", __func__); - return C2_OK; - } - - const auto status = allowAllocation(true); - if (status != OK) { - return asC2Error(status); - } - - // Release all remained slot buffer references here. CCodec should either cancel or queue its - // owned buffers from this set before the next resolution change. - mTrackedGraphicBuffers.reset(); - - mBuffersRequested = static_cast(bufferCount); - - // Store buffer formats for future usage. - mBufferFormat = BufferFormat(width, height, format, C2AndroidMemoryUsage(usage)); - - return C2_OK; -} - -void C2VdaBqBlockPool::Impl::configureProducer(const sp& producer) { - ALOGV("%s(producer=%p)", __func__, producer.get()); - - std::lock_guard lock(mMutex); - if (producer == nullptr) { - ALOGI("input producer is nullptr..."); - - mProducer = nullptr; - mProducerId = 0; - mTrackedGraphicBuffers.reset(); - return; - } - - auto newProducer = std::make_unique(producer); - uint64_t newProducerId; - if (newProducer->getUniqueId(&newProducerId) != OK) { - ALOGE("%s(): failed to get IGBP ID", __func__); - mConfigureProducerError = true; - return; - } - if (newProducerId == mProducerId) { - ALOGI("%s(): configure the same producer, ignore", __func__); - return; - } - - ALOGI("Producer (Surface) is going to switch... ( 0x%" PRIx64 " -> 0x%" PRIx64 " )", - mProducerId, newProducerId); - mProducer = std::move(newProducer); - mProducerId = newProducerId; - mConfigureProducerError = false; - mAllowAllocation = false; - - // Set allowAllocation to new producer. - if (allowAllocation(true) != OK) { - ALOGE("%s(): failed to allowAllocation(true)", __func__); - mConfigureProducerError = true; - return; - } - if (mProducer->setDequeueTimeout(0) != OK) { - ALOGE("%s(): failed to setDequeueTimeout(0)", __func__); - mConfigureProducerError = true; - return; - } - if (mProducer->setMaxDequeuedBufferCount(kMaxDequeuedBufferCount) != OK) { - ALOGE("%s(): failed to setMaxDequeuedBufferCount(%d)", __func__, kMaxDequeuedBufferCount); - mConfigureProducerError = true; - return; - } - - // Migrate existing buffers to the new producer. - if (mTrackedGraphicBuffers.size() > 0) { - uint32_t newGeneration = 0; - uint64_t newUsage = 0; - const status_t err = queryGenerationAndUsageLocked( - mBufferFormat.mWidth, mBufferFormat.mHeight, mBufferFormat.mPixelFormat, - mBufferFormat.mUsage, &newGeneration, &newUsage); - if (err != OK) { - ALOGE("failed to query generation and usage: %d", err); - mConfigureProducerError = true; - return; - } - - if (!mTrackedGraphicBuffers.migrateLocalBuffers(mProducer.get(), mProducerId, newGeneration, - newUsage)) { - ALOGE("%s(): failed to migrateLocalBuffers()", __func__); - mConfigureProducerError = true; - return; - } - - if (mTrackedGraphicBuffers.size() == mBuffersRequested) { - if (allowAllocation(false) != OK) { - ALOGE("%s(): failed to allowAllocation(false)", __func__); - mConfigureProducerError = true; - return; - } - } - } - - // hack(b/146409777): Try to connect ARC-specific listener first. - sp listener = new BufferReleasedNotifier(weak_from_this()); - if (mProducer->connect(listener, 'ARC\0', false) == OK) { - ALOGI("connected to ARC-specific IGBP listener."); - mFetchBufferNotifier = listener; - } - - // There might be free buffers at the new producer, notify the client if needed. - onEventNotified(); -} - -bool C2VdaBqBlockPool::Impl::setNotifyBlockAvailableCb(::base::OnceClosure cb) { - ALOGV("%s()", __func__); - if (mFetchBufferNotifier == nullptr) { - return false; - } - - ::base::OnceClosure outputCb; - { - std::lock_guard lock(mBufferReleaseMutex); - - // If there is any buffer released after dequeueBuffer() timed out, then we could notify the - // caller directly. - if (mBufferReleasedAfterTimedOut) { - mBufferReleasedAfterTimedOut = false; - outputCb = std::move(cb); - } else { - mNotifyBlockAvailableCb = std::move(cb); - } - } - - // Calling the callback outside the lock to avoid the deadlock. - if (outputCb) { - std::move(outputCb).Run(); - } - return true; -} - -std::optional C2VdaBqBlockPool::Impl::getBufferIdFromGraphicBlock( - const C2Block2D& block) { - return getDmabufId(block.handle()->data[0]); -} - -status_t C2VdaBqBlockPool::Impl::allowAllocation(bool allow) { - ALOGV("%s(%d)", __func__, allow); - - if (!mProducer) { - ALOGW("%s() mProducer is not initiailzed", __func__); - return NO_INIT; - } - if (mAllowAllocation == allow) { - return OK; - } - - const auto status = mProducer->allowAllocation(allow); - if (status == OK) { - mAllowAllocation = allow; - } - return status; -} - -C2VdaBqBlockPool::C2VdaBqBlockPool(const std::shared_ptr& allocator, - const local_id_t localId) - : C2BufferQueueBlockPool(allocator, localId), mLocalId(localId), mImpl(new Impl(allocator)) {} - -c2_status_t C2VdaBqBlockPool::fetchGraphicBlock( - uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage, - std::shared_ptr* block /* nonnull */) { - if (mImpl) { - return mImpl->fetchGraphicBlock(width, height, format, usage, block); - } - return C2_NO_INIT; -} - -c2_status_t C2VdaBqBlockPool::fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, - std::shared_ptr* block, - C2Fence* fence) { - if (mImpl) { - return mImpl->fetchGraphicBlock(width, height, format, usage, block); - } - return C2_NO_INIT; -} - -void C2VdaBqBlockPool::setRenderCallback( - const C2BufferQueueBlockPool::OnRenderCallback& renderCallback) { - if (mImpl) { - mImpl->setRenderCallback(renderCallback); - } -} - -c2_status_t C2VdaBqBlockPool::requestNewBufferSet(int32_t bufferCount, uint32_t width, - uint32_t height, uint32_t format, - C2MemoryUsage usage) { - if (mImpl) { - return mImpl->requestNewBufferSet(bufferCount, width, height, format, usage); - } - return C2_NO_INIT; -} - -void C2VdaBqBlockPool::configureProducer(const sp& producer) { - if (mImpl) { - mImpl->configureProducer(producer); - } -} - -bool C2VdaBqBlockPool::setNotifyBlockAvailableCb(::base::OnceClosure cb) { - if (mImpl) { - return mImpl->setNotifyBlockAvailableCb(std::move(cb)); - } - return false; -} - -std::optional C2VdaBqBlockPool::getBufferIdFromGraphicBlock(const C2Block2D& block) { - if (mImpl) { - return mImpl->getBufferIdFromGraphicBlock(block); - } - return std::nullopt; -} - -} // namespace android diff --git a/plugin_store/C2VdaPooledBlockPool.cpp b/plugin_store/C2VdaPooledBlockPool.cpp deleted file mode 100644 index 2b9104b..0000000 --- a/plugin_store/C2VdaPooledBlockPool.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// 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 - -#include - -#include -#include -#include - -namespace android { - -using android::hardware::media::bufferpool::BufferPoolData; - -// static -std::optional C2VdaPooledBlockPool::getBufferIdFromGraphicBlock(const C2Block2D& block) { - std::shared_ptr<_C2BlockPoolData> blockPoolData = - _C2BlockFactory::GetGraphicBlockPoolData(block); - if (blockPoolData->getType() != _C2BlockPoolData::TYPE_BUFFERPOOL) { - ALOGE("Obtained C2GraphicBlock is not bufferpool-backed."); - return std::nullopt; - } - std::shared_ptr bpData; - if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData) || !bpData) { - ALOGE("BufferPoolData unavailable in block."); - return std::nullopt; - } - return bpData->mId; -} - -// 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* block) { - ALOG_ASSERT(block != nullptr); - std::lock_guard lock(mMutex); - - std::shared_ptr 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; - } - - std::optional bufferId = getBufferIdFromGraphicBlock(*fetchBlock); - if (!bufferId) { - ALOGE("Failed to getBufferIdFromGraphicBlock"); - return C2_CORRUPTED; - } - - 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..."); - 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 lock(mMutex); - mBufferIds.clear(); - mBufferCount = bufferCount; - return C2_OK; -} - -} // namespace android diff --git a/plugin_store/H2BGraphicBufferProducer.cpp b/plugin_store/H2BGraphicBufferProducer.cpp deleted file mode 100644 index 95251de..0000000 --- a/plugin_store/H2BGraphicBufferProducer.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2021 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 "H2BGraphicBuferProducer" - -#include - -#include -#include -#include - -namespace android { - -using ::android::BufferQueueDefs::BUFFER_NEEDS_REALLOCATION; -using ::android::BufferQueueDefs::RELEASE_ALL_BUFFERS; -using ::android::hardware::Return; - -using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer; -using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status; -using HConnectionType = hardware::graphics::bufferqueue::V2_0::ConnectionType; -using HQueueBufferOutput = - ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferOutput; - -using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h; -using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b; -using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper; - -H2BGraphicBufferProducer::H2BGraphicBufferProducer(sp base) : mBase(base) {} - -status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp* buf) { - bool converted = false; - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->requestBuffer( - slot, [&converted, &status, buf](HStatus hStatus, HBuffer const& hBuffer, - uint32_t generationNumber) { - converted = h2b(hStatus, &status) && h2b(hBuffer, buf); - if (*buf) { - (*buf)->setGenerationNumber(generationNumber); - } - }); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!converted) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers) { - status_t status = UNKNOWN_ERROR; - Return transResult = - mBase->setMaxDequeuedBufferCount(static_cast(maxDequeuedBuffers)); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!h2b(static_cast(transResult), &status)) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::dequeueBuffer(uint32_t width, uint32_t height, - uint32_t pixelFormat, - C2AndroidMemoryUsage androidUsage, int* slot, - sp* fence) { - using Input = HGraphicBufferProducer::DequeueBufferInput; - using Output = HGraphicBufferProducer::DequeueBufferOutput; - Input input{width, height, pixelFormat, androidUsage.asGrallocUsage()}; - - bool converted = false; - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->dequeueBuffer( - input, [&converted, &status, &slot, &fence](HStatus hStatus, int32_t hSlot, - Output const& hOutput) { - converted = h2b(hStatus, &status); - if (!converted || status != OK) { - return; - } - - *slot = hSlot; - if (hOutput.bufferNeedsReallocation) { - status = BUFFER_NEEDS_REALLOCATION; - } - converted = h2b(hOutput.fence, fence); - }); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!converted) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - // The C2VdaBqBlockPool does not fully own the bufferqueue. After buffers are dequeued here, - // they are passed into the codec2 framework, processed, and eventually queued into the - // bufferqueue. The C2VdaBqBlockPool cannot determine exactly when a buffer gets queued. - // However, if every buffer is being processed by the codec2 framework, then dequeueBuffer() - // will return INVALID_OPERATION because of an attempt to dequeue too many buffers. - // The C2VdaBqBlockPool cannot prevent this from happening, so just map it to TIMED_OUT - // and let the C2VdaBqBlockPool's caller's timeout retry logic handle the failure. - if (status == INVALID_OPERATION) { - status = TIMED_OUT; - } - if (status != OK && status != BUFFER_NEEDS_REALLOCATION && status != TIMED_OUT) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::detachBuffer(int slot) { - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->detachBuffer(static_cast(slot)); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!h2b(static_cast(transResult), &status)) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::attachBuffer(const sp& buffer, int* outSlot) { - HBuffer hBuffer; - uint32_t hGenerationNumber; - if (!b2h(buffer, &hBuffer, &hGenerationNumber)) { - ALOGE("%s: invalid input buffer.", __func__); - return BAD_VALUE; - } - - bool converted = false; - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->attachBuffer( - hBuffer, hGenerationNumber, - [&converted, &status, outSlot](HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) { - converted = h2b(hStatus, &status); - *outSlot = static_cast(hSlot); - if (converted && releaseAllBuffers && status == OK) { - status = RELEASE_ALL_BUFFERS; - } - }); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!converted) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::cancelBuffer(int slot, const sp& fence) { - HFenceWrapper hFenceWrapper; - if (!b2h(fence, &hFenceWrapper)) { - ALOGE("%s(): corrupted input fence.", __func__); - return UNKNOWN_ERROR; - } - - status_t status = UNKNOWN_ERROR; - Return transResult = - mBase->cancelBuffer(static_cast(slot), hFenceWrapper.getHandle()); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!h2b(static_cast(transResult), &status)) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -int H2BGraphicBufferProducer::query(int what, int* value) { - int result = 0; - Return transResult = - mBase->query(static_cast(what), [&result, value](int32_t r, int32_t v) { - result = static_cast(r); - *value = static_cast(v); - }); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - return result; -} - -status_t H2BGraphicBufferProducer::allowAllocation(bool allow) { - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->allowAllocation(allow); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!h2b(static_cast(transResult), &status)) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - if (status != OK) { - ALOGD("%s() failed: %d", __func__, status); - } - return status; -} - -status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { - Return transResult = mBase->getUniqueId(); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - - *outId = static_cast(transResult); - return OK; -} - -// android::IProducerListener cannot be depended by vendor library, so we use HProducerListener -// directly. -status_t H2BGraphicBufferProducer::connect(sp const& hListener, int32_t api, - bool producerControlledByApp) { - bool converted = false; - status_t status = UNKNOWN_ERROR; - // hack(b/146409777): We pass self-defined api, so we don't use b2h() here. - Return transResult = mBase->connect( - hListener, static_cast(api), producerControlledByApp, - [&converted, &status](HStatus hStatus, HQueueBufferOutput const& /* hOutput */) { - converted = h2b(hStatus, &status); - }); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!converted) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - return status; -} - -status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) { - status_t status = UNKNOWN_ERROR; - Return transResult = mBase->setDequeueTimeout(static_cast(timeout)); - - if (!transResult.isOk()) { - ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); - return FAILED_TRANSACTION; - } - if (!h2b(static_cast(transResult), &status)) { - ALOGE("%s(): corrupted transaction.", __func__); - return FAILED_TRANSACTION; - } - return status; -} - -} // namespace android diff --git a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h deleted file mode 100644 index addc23d..0000000 --- a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaBqBlockPool.h +++ /dev/null @@ -1,108 +0,0 @@ -// 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_BQ_BLOCK_POOL_H -#define ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_BQ_BLOCK_POOL_H - -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -/** - * The BufferQueue-backed block pool design which supports to request arbitrary count of graphic - * buffers from IGBP, and use this buffer set among codec component and client. - * - * The block pool should restore the mapping table between slot indices and GraphicBuffer (or - * C2GraphicAllocation). When component requests a new buffer, the block pool calls dequeueBuffer - * to IGBP to obtain a valid slot index, and returns the corresponding buffer from map. - */ -class C2VdaBqBlockPool : public C2BufferQueueBlockPool { -public: - C2VdaBqBlockPool(const std::shared_ptr& allocator, const local_id_t localId); - - ~C2VdaBqBlockPool() override = default; - - /** - * It's a trick here. Return C2PlatformAllocatorStore::BUFFERQUEUE instead of the ID of backing - * allocator for client's query. It's because in platform side this ID is recognized as - * BufferQueue-backed block pool which is only allowed to set surface. - */ - C2Allocator::id_t getAllocatorId() const override { - return android::C2PlatformAllocatorStore::BUFFERQUEUE; - }; - - local_id_t getLocalId() const override { return mLocalId; }; - - /** - * Tries to dequeue a buffer from producer. If the producer is allowed allocation now, call - * requestBuffer of dequeued slot for allocating new buffer and storing the reference into - * |mSlotAllocations|. - * - * When the size of |mSlotAllocations| reaches the requested buffer count, set disallow - * allocation to producer. After that buffer set is started to be recycled by dequeue. - * - * \retval C2_BAD_STATE informs the caller producer is switched. - */ - c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, - std::shared_ptr* block /* nonnull */) override; - - c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format, - C2MemoryUsage usage, std::shared_ptr* block, - C2Fence* fence) override; - - void setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback& renderCallback = - C2BufferQueueBlockPool::OnRenderCallback()) override; - void configureProducer(const android::sp& producer) override; - - /** - * Sends the request of arbitrary number of graphic buffers allocation. If producer is given, - * it will set maxDequeuedBufferCount with regard to the requested buffer count and allow - * allocation to producer. - * - * \note C2VdaBqBlockPool-specific function - * \note caller should release all buffer references obtained from fetchGraphicBlock() before - * calling this function. - * - * \param bufferCount the number of requested buffers - * - * \retval C2_OK the operation was successful. - * \retval C2_NO_INIT this class is not initialized, or producer is not assigned. - * \retval C2_BAD_VALUE |bufferCount| is not greater than zero. - * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected). - */ - c2_status_t requestNewBufferSet(int32_t bufferCount, uint32_t width, uint32_t height, - uint32_t format, C2MemoryUsage usage); - - /** - * Set the callback that will be triggered when there is block available. - * - * \note C2VdaBqBlockPool-specific function - * - * \param cb the callback function that will be triggered when there is block available. - * - * Return false if we don't support to notify the caller when a buffer is available. - * - */ - bool setNotifyBlockAvailableCb(base::OnceClosure cb); - - std::optional getBufferIdFromGraphicBlock(const C2Block2D& block); - -private: - friend struct C2VdaBqBlockPoolData; - class Impl; - - const local_id_t mLocalId; - std::shared_ptr mImpl; -}; - -} // namespace android -#endif // ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_BQ_BLOCK_POOL_H diff --git a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h b/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h deleted file mode 100644 index 749ff47..0000000 --- a/plugin_store/include/v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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 -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -class C2VdaPooledBlockPool : public C2PooledBlockPool { -public: - using C2PooledBlockPool::C2PooledBlockPool; - ~C2VdaPooledBlockPool() override = default; - - // Extracts the buffer ID from BufferPoolData of the graphic block. - // |block| is the graphic block allocated by bufferpool block pool. - static std::optional getBufferIdFromGraphicBlock(const C2Block2D& block); - - // 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* 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 mBufferIds GUARDED_BY(mMutex); - // The maximum count of allocated buffers. - size_t mBufferCount GUARDED_BY(mMutex){0}; -}; - -} // namespace android -#endif // ANDROID_V4L2_CODEC2_PLUGIN_STORE_C2_VDA_POOLED_BLOCK_POOL_H diff --git a/plugin_store/include/v4l2_codec2/plugin_store/H2BGraphicBufferProducer.h b/plugin_store/include/v4l2_codec2/plugin_store/H2BGraphicBufferProducer.h deleted file mode 100644 index 11185bb..0000000 --- a/plugin_store/include/v4l2_codec2/plugin_store/H2BGraphicBufferProducer.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2021 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_H2B_GRAPHIC_BUFFER_PRODUCER_H -#define ANDROID_V4L2_CODEC2_PLUGIN_STORE_H2B_GRAPHIC_BUFFER_PRODUCER_H - -#include -#include -#include -#include -#include -#include - -namespace android { - -class H2BGraphicBufferProducer { -public: - using HGraphicBufferProducer = - ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer; - using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener; - - explicit H2BGraphicBufferProducer(sp base); - ~H2BGraphicBufferProducer() = default; - - // Convert HIDL interface of IGraphicBufferProducer. - status_t requestBuffer(int slot, sp* buf); - status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); - status_t dequeueBuffer(uint32_t width, uint32_t height, uint32_t pixelFormat, - C2AndroidMemoryUsage androidUsage, int* slot, sp* fence); - status_t detachBuffer(int slot); - status_t attachBuffer(const sp& buffer, int* outSlot); - status_t cancelBuffer(int slot, const sp& fence); - int query(int what, int* value); - status_t allowAllocation(bool allow); - status_t getUniqueId(uint64_t* outId) const; - status_t connect(sp const& hListener, int32_t api, - bool producerControlledByApp); - status_t setDequeueTimeout(nsecs_t timeout); - - sp getBase() { return mBase; } - -private: - const sp mBase; -}; - -} // namespace android -#endif // ANDROID_V4L2_CODEC2_PLUGIN_STORE_H2B_GRAPHIC_BUFFER_PRODUCER_H -- cgit v1.2.3 From ede4c41a59dac5439cb82fb43cd0ca6b483b949b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Thu, 9 Mar 2023 13:50:08 +0000 Subject: V4L2DecodeInterface: Switch to GRALLOC allocator This CL switches to output allocator to C2PlatformAllocatorStore::GRALLOC that enforces use of C2PooledBufferPool without need of allocating a separate allocator ID. For this reason V4L2AllocatorId::V4L2_BUFFERPOOL is no longer used and is removed in this change. Bug: 268301611 Bug: 268305422 Bug: 270329448 Bug: 238710012 Bug: 238390060 Bug: 270331759 Bug: 238709912 Test: CtsMediaCodecTestCases Test: CtsMediaDecoderTestCases Test: CtsMediaV2TestCases Test: GtsExoPlayerTestCases com.google.android.exoplayer.gts.CommonEncryptionDrmTest#cencSchemeTypeV* Change-Id: Ife2fbb6ac4ff2dc25e006792f8dad2d8ec6f4ac4 (cherry picked from commit 210185e4071e84c508fab3305477e96137507b06) --- components/V4L2DecodeInterface.cpp | 2 +- components/VideoFramePool.cpp | 4 ++-- plugin_store/V4L2PluginStore.cpp | 3 --- plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/components/V4L2DecodeInterface.cpp b/components/V4L2DecodeInterface.cpp index fb384c6..32483be 100644 --- a/components/V4L2DecodeInterface.cpp +++ b/components/V4L2DecodeInterface.cpp @@ -267,7 +267,7 @@ V4L2DecodeInterface::V4L2DecodeInterface(const std::string& name, const C2Allocator::id_t inputAllocators[] = {secureMode ? V4L2AllocatorId::SECURE_LINEAR : C2AllocatorStore::DEFAULT_LINEAR}; - const C2Allocator::id_t outputAllocators[] = {V4L2AllocatorId::V4L2_BUFFERPOOL}; + const C2Allocator::id_t outputAllocators[] = {C2PlatformAllocatorStore::GRALLOC}; const C2Allocator::id_t surfaceAllocator = secureMode ? V4L2AllocatorId::SECURE_GRAPHIC : C2PlatformAllocatorStore::BUFFERQUEUE; const C2BlockPool::local_id_t outputBlockPools[] = {C2BlockPool::BASIC_GRAPHIC}; diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index 070cc40..4bf45f3 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -43,7 +43,7 @@ std::optional VideoFramePool::getBufferIdFromGraphicBlock(C2BlockPool& } return dmabufId.value(); } - case V4L2AllocatorId::V4L2_BUFFERPOOL: + case C2PlatformAllocatorStore::GRALLOC: FALLTHROUGH; case V4L2AllocatorId::SECURE_LINEAR: { std::shared_ptr<_C2BlockPoolData> blockPoolData = @@ -75,7 +75,7 @@ std::unique_ptr VideoFramePool::Create( uint64_t usage = static_cast(BufferUsage::VIDEO_DECODER); if (isSecure) { usage |= C2MemoryUsage::READ_PROTECTED; - } else if (blockPool->getAllocatorId() == android::V4L2AllocatorId::V4L2_BUFFERPOOL) { + } else if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::GRALLOC) { // CPU access to buffers is only required in byte buffer mode. usage |= C2MemoryUsage::CPU_READ; } diff --git a/plugin_store/V4L2PluginStore.cpp b/plugin_store/V4L2PluginStore.cpp index a8cdab6..9f9f262 100644 --- a/plugin_store/V4L2PluginStore.cpp +++ b/plugin_store/V4L2PluginStore.cpp @@ -66,9 +66,6 @@ C2BlockPool* createBlockPool(C2Allocator::id_t allocatorId, C2BlockPool::local_i } switch (allocatorId) { - case V4L2AllocatorId::V4L2_BUFFERPOOL: - return new C2PooledBlockPool(allocator, poolId); - case V4L2AllocatorId::SECURE_LINEAR: return new C2PooledBlockPool(allocator, poolId); diff --git a/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h b/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h index 45a470c..2353076 100644 --- a/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h +++ b/plugin_store/include/v4l2_codec2/plugin_store/V4L2AllocatorId.h @@ -12,8 +12,7 @@ namespace V4L2AllocatorId { // The allocator ids used for V4L2DecodeComponent. enum : C2AllocatorStore::id_t { - V4L2_BUFFERPOOL = C2PlatformAllocatorStore::PLATFORM_END, - SECURE_LINEAR, + SECURE_LINEAR = C2PlatformAllocatorStore::PLATFORM_END, SECURE_GRAPHIC, }; -- cgit v1.2.3 From 885767a755bd2f21dae8b9785ba36f8cf547e5d8 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Thu, 13 Jul 2023 17:45:01 -0700 Subject: Move v4l2_codec HAL from the manifest to a vintf fragment The code owner then owns the manifest the vintf fragment. Remove IConfigurable because it isn't declared in the compatibility matrix. It isn't registered to hwservice_manager either in the implementation. Bug: 291157411 Test: ARC++ boots. Change-Id: I1616bf2ae90327e87bf13cc379e85927333eb0ed --- README.md | 20 -------------------- service/Android.bp | 1 + .../android.hardware.media.c2@1.2-service-v4l2.xml | 11 +++++++++++ 3 files changed, 12 insertions(+), 20 deletions(-) create mode 100644 service/android.hardware.media.c2@1.2-service-v4l2.xml diff --git a/README.md b/README.md index aa59a40..7b4455d 100644 --- a/README.md +++ b/README.md @@ -74,26 +74,6 @@ PRODUCT_COPY_FILES += \ :$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/codec2.vendor.ext.policy ``` -Enable codec2 hidl in manifest.xml - -```xml - - - android.hardware.media.c2 - hwbinder - 1.0 - - IComponentStore - default - - - IConfigurable - default - - - -``` - Add decode and encode components in media\_codecs\_c2.xml ```xml diff --git a/service/Android.bp b/service/Android.bp index a690f08..72e0a8f 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -44,4 +44,5 @@ cc_binary { init_rc: ["android.hardware.media.c2@1.2-service-v4l2-64.rc"], }, }, + vintf_fragments: ["android.hardware.media.c2@1.2-service-v4l2.xml"], } diff --git a/service/android.hardware.media.c2@1.2-service-v4l2.xml b/service/android.hardware.media.c2@1.2-service-v4l2.xml new file mode 100644 index 0000000..7976a59 --- /dev/null +++ b/service/android.hardware.media.c2@1.2-service-v4l2.xml @@ -0,0 +1,11 @@ + + + android.hardware.media.c2 + hwbinder + 1.2 + + IComponentStore + default + + + -- cgit v1.2.3 From 0378da79c37e9d7c63224e91657fc5f2bb732666 Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Mon, 4 Dec 2023 17:24:16 +0900 Subject: Explicitly specify ::base The upstream includes these headers after declaring android::base namespace, which resulted in confusing the compiler libchrome's ::base v.s. android::base Bug: 314693926 Test: m Change-Id: I25a226b8eb962138489f30cd0fa1a42c3e599bdf --- common/include/v4l2_codec2/common/V4L2Device.h | 45 +++++++++++----------- .../include/v4l2_codec2/common/V4L2DevicePoller.h | 12 +++--- .../include/v4l2_codec2/components/VideoDecoder.h | 8 ++-- .../include/v4l2_codec2/components/VideoEncoder.h | 10 ++--- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/common/include/v4l2_codec2/common/V4L2Device.h b/common/include/v4l2_codec2/common/V4L2Device.h index 77d7ddb..9824221 100644 --- a/common/include/v4l2_codec2/common/V4L2Device.h +++ b/common/include/v4l2_codec2/common/V4L2Device.h @@ -105,7 +105,7 @@ private: // Do the actual queue operation once the v4l2_buffer structure is properly filled. bool doQueue() &&; - V4L2WritableBufferRef(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr queue); + V4L2WritableBufferRef(const struct v4l2_buffer& v4l2Buffer, ::base::WeakPtr queue); V4L2WritableBufferRef(const V4L2WritableBufferRef&) = delete; V4L2WritableBufferRef& operator=(const V4L2WritableBufferRef&) = delete; @@ -124,7 +124,7 @@ private: // buffers they originate from. This flexibility is required because V4L2ReadableBufferRefs can be // embedded into VideoFrames, which are then passed to other threads and not necessarily destroyed // before the V4L2Queue buffers are freed. -class V4L2ReadableBuffer : public base::RefCountedThreadSafe { +class V4L2ReadableBuffer : public ::base::RefCountedThreadSafe { public: // Returns whether the V4L2_BUF_FLAG_LAST flag is set for this buffer. bool isLast() const; @@ -148,11 +148,11 @@ public: private: friend class V4L2BufferRefFactory; - friend class base::RefCountedThreadSafe; + friend class ::base::RefCountedThreadSafe; ~V4L2ReadableBuffer(); - V4L2ReadableBuffer(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr queue); + V4L2ReadableBuffer(const struct v4l2_buffer& v4l2Buffer, ::base::WeakPtr queue); V4L2ReadableBuffer(const V4L2ReadableBuffer&) = delete; V4L2ReadableBuffer& operator=(const V4L2ReadableBuffer&) = delete; @@ -183,7 +183,7 @@ class V4L2Buffer; // metadata, as well as making other references to it. The buffer will not be reused until all // the references are dropped. Once this happens, the buffer goes back to the free list described // in 1). -class V4L2Queue : public base::RefCountedThreadSafe { +class V4L2Queue : public ::base::RefCountedThreadSafe { public: // Set |fourcc| as the current format on this queue. |size| corresponds to the desired buffer's // dimensions (i.e. width and height members of v4l2_pix_format_mplane (if not applicable, pass @@ -206,10 +206,10 @@ public: size_t bufferSize) WARN_UNUSED_RESULT; // Returns the currently set format on the queue. The result is returned as a std::pair where - // the first member is the format, or base::nullopt if the format could not be obtained due to - // an ioctl error. The second member is only used in case of an error and contains the |errno| - // set by the failing ioctl. If the first member is not base::nullopt, the second member will - // always be zero. + // the first member is the format, or ::base::nullopt if the format could not be obtained due + // to an ioctl error. The second member is only used in case of an error and contains the + // |errno| set by the failing ioctl. If the first member is not ::base::nullopt, the second + // member will always be zero. // // If the second member is 0, then the first member is guaranteed to have a valid value. So // clients that are not interested in the precise error message can just check that the first @@ -304,19 +304,20 @@ private: scoped_refptr mDevice; // Callback to call in this queue's destructor. - base::OnceClosure mDestroyCb; + ::base::OnceClosure mDestroyCb; - V4L2Queue(scoped_refptr dev, enum v4l2_buf_type type, base::OnceClosure destroyCb); + V4L2Queue(scoped_refptr dev, enum v4l2_buf_type type, + ::base::OnceClosure destroyCb); friend class V4L2QueueFactory; friend class V4L2BufferRefBase; - friend class base::RefCountedThreadSafe; + friend class ::base::RefCountedThreadSafe; SEQUENCE_CHECKER(mSequenceChecker); - base::WeakPtrFactory mWeakThisFactory{this}; + ::base::WeakPtrFactory mWeakThisFactory{this}; }; -class V4L2Device : public base::RefCountedThreadSafe { +class V4L2Device : public ::base::RefCountedThreadSafe { public: // Specification of an encoding profile supported by an encoder. struct SupportedEncodeProfile { @@ -364,7 +365,7 @@ public: // Composes human readable string of v4l2_buffer. static std::string v4L2BufferToString(const struct v4l2_buffer& buffer); - // Composes VideoFrameLayout based on v4l2_format. If error occurs, it returns base::nullopt. + // Composes VideoFrameLayout based on v4l2_format. If error occurs, it returns ::base::nullopt. static std::optional v4L2FormatToVideoFrameLayout( const struct v4l2_format& format); @@ -411,8 +412,8 @@ public: // Return a vector of dmabuf file descriptors, exported for V4L2 buffer with |index|, assuming // the buffer contains |numPlanes| V4L2 planes and is of |bufType|. Return an empty vector on // failure. The caller is responsible for closing the file descriptors after use. - std::vector getDmabufsForV4L2Buffer(int index, size_t numPlanes, - enum v4l2_buf_type bufType); + std::vector<::base::ScopedFD> getDmabufsForV4L2Buffer(int index, size_t numPlanes, + enum v4l2_buf_type bufType); // Returns the preferred V4L2 input formats for |type| or empty if none. std::vector preferredInputFormat(Type type); @@ -440,7 +441,7 @@ public: // be posted to the client's // sequence if a polling error has occurred. bool startPolling(android::V4L2DevicePoller::EventCallback eventCallback, - base::RepeatingClosure errorCallback); + ::base::RepeatingClosure errorCallback); // Stop polling this V4L2Device if polling was active. No new events will be posted after this // method has returned. bool stopPolling(); @@ -463,7 +464,7 @@ private: // Vector of video device node paths and corresponding pixelformats supported by each device node. using Devices = std::vector>>; - friend class base::RefCountedThreadSafe; + friend class ::base::RefCountedThreadSafe; V4L2Device(); ~V4L2Device(); @@ -500,13 +501,13 @@ private: std::map mDevicesByType; // The actual device fd. - base::ScopedFD mDeviceFd; + ::base::ScopedFD mDeviceFd; // eventfd fd to signal device poll thread when its poll() should be interrupted. - base::ScopedFD mDevicePollInterruptFd; + ::base::ScopedFD mDevicePollInterruptFd; // Associates a v4l2_buf_type to its queue. - base::flat_map mQueues; + ::base::flat_map mQueues; // Used if EnablePolling() is called to signal the user that an event happened or a buffer is // ready to be dequeued. diff --git a/common/include/v4l2_codec2/common/V4L2DevicePoller.h b/common/include/v4l2_codec2/common/V4L2DevicePoller.h index ad256be..53b4b3f 100644 --- a/common/include/v4l2_codec2/common/V4L2DevicePoller.h +++ b/common/include/v4l2_codec2/common/V4L2DevicePoller.h @@ -32,7 +32,7 @@ class V4L2DevicePoller { public: // Callback to be called when buffer ready/V4L2 event has potentially been polled. |event| is // set if a V4L2 event has been detected. - using EventCallback = base::RepeatingCallback; + using EventCallback = ::base::RepeatingCallback; // Create a poller for |device|, using a thread named |threadName|. Notification won't start // until |startPolling()| is called. @@ -45,7 +45,7 @@ public: // again in order to be notified for them. // // If an error occurs during polling, |mErrorCallback| will be posted on the caller's sequence. - bool startPolling(EventCallback eventCallback, base::RepeatingClosure errorCallback); + bool startPolling(EventCallback eventCallback, ::base::RepeatingClosure errorCallback); // Stop polling and stop the thread. The poller won't post any new event to the caller's // sequence after this method has returned. bool stopPolling(); @@ -66,19 +66,19 @@ private: // V4L2 device we are polling. V4L2Device* const mDevice; // Thread on which polling is done. - base::Thread mPollThread; + ::base::Thread mPollThread; // Callback to post to the client's sequence when an event occurs. EventCallback mEventCallback; // Closure to post to the client's sequence when an error occurs. - base::RepeatingClosure mErrorCallback; + ::base::RepeatingClosure mErrorCallback; // Client sequence's task runner, where closures are posted. - scoped_refptr mClientTaskTunner; + scoped_refptr<::base::SequencedTaskRunner> mClientTaskTunner; // Since poll() returns immediately if no buffers have been queued, we cannot rely on it to // pause the polling thread until an event occurs. Instead, // the polling thread will wait on this WaitableEvent (signaled by |schedulePoll| before calling // poll(), so we only call it when we are actually waiting for an event. - base::WaitableEvent mTriggerPoll; + ::base::WaitableEvent mTriggerPoll; // Set to true when we wish to stop polling, instructing the poller thread to break its loop. std::atomic_bool mStopPolling; }; diff --git a/components/include/v4l2_codec2/components/VideoDecoder.h b/components/include/v4l2_codec2/components/VideoDecoder.h index 5b2da41..3e3fec4 100644 --- a/components/include/v4l2_codec2/components/VideoDecoder.h +++ b/components/include/v4l2_codec2/components/VideoDecoder.h @@ -26,11 +26,11 @@ public: }; static const char* DecodeStatusToString(DecodeStatus status); - using GetPoolCB = base::RepeatingCallback( + using GetPoolCB = ::base::RepeatingCallback( const ui::Size& size, HalPixelFormat pixelFormat, size_t numOutputBuffers)>; - using DecodeCB = base::OnceCallback; - using OutputCB = base::RepeatingCallback)>; - using ErrorCB = base::RepeatingCallback; + using DecodeCB = ::base::OnceCallback; + using OutputCB = ::base::RepeatingCallback)>; + using ErrorCB = ::base::RepeatingCallback; virtual ~VideoDecoder(); diff --git a/components/include/v4l2_codec2/components/VideoEncoder.h b/components/include/v4l2_codec2/components/VideoEncoder.h index 5f23541..7e5a3c2 100644 --- a/components/include/v4l2_codec2/components/VideoEncoder.h +++ b/components/include/v4l2_codec2/components/VideoEncoder.h @@ -47,13 +47,13 @@ public: }; using FetchOutputBufferCB = - base::RepeatingCallback* buffer)>; + ::base::RepeatingCallback* buffer)>; // TODO(dstaessens): Change callbacks to OnceCallback provided when requesting encode/drain. - using InputBufferDoneCB = base::RepeatingCallback; - using OutputBufferDoneCB = base::RepeatingCallback; + using OutputBufferDoneCB = ::base::RepeatingCallback buffer)>; - using DrainDoneCB = base::RepeatingCallback; - using ErrorCB = base::RepeatingCallback; + using DrainDoneCB = ::base::RepeatingCallback; + using ErrorCB = ::base::RepeatingCallback; virtual ~VideoEncoder() = default; -- cgit v1.2.3