From d81926adf9cd0acf305f73aab9dd6e3b9a43314d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= <bgrzesik@google.com> Date: Tue, 7 Mar 2023 09:50:09 +0000 Subject: [PATCH] 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<C2GraphicBlock> block; - c2_status_t err = mBlockPool->fetchGraphicBlock( - mSize.width, mSize.height, static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<VideoFrame> frame = VideoFrame::Create(std::move(block)); std::optional<FrameWithBlockId> frameWithBlockId; - if (err == C2_OK) { - ALOG_ASSERT(block != nullptr); - std::optional<uint32_t> bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); - std::unique_ptr<VideoFrame> frame = VideoFrame::Create(std::move(block)); + std::optional<uint32_t> 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( -- GitLab