diff options
author | Chih-Yu Huang <akahuang@google.com> | 2020-08-31 17:31:45 +0900 |
---|---|---|
committer | Chih-Yu Huang <akahuang@google.com> | 2020-09-03 18:10:54 +0900 |
commit | 9cf0ab57d14d9f74e834c36a2a1e0324e0482e89 (patch) | |
tree | 15b302105bc458b9189b9ea1fa3c39e9966c7183 /components | |
parent | 842849a0ac0d2825f9af76357dcd8967150ff583 (diff) | |
download | v4l2_codec2-9cf0ab57d14d9f74e834c36a2a1e0324e0482e89.tar.gz |
Make VideoFramePool and C2VdaBqBlockPool non-blocking when fetching
Originally, when C2VdaBqBlockPool timed out to fetch a block, the
method is blocking to wait for buffer released. If this blocking
waiting also timed out, then VideoFramePool would retry again with
exponential backoff. We have 2 retry mechanisms for timed out in both
VideoFramePool and C2VdaBqBlockPool, which is redundant.
In this CL, the C2VdaBqBlockPool method return C2_TIMED_OUT directly
when there is no available block. Then VideoFramePool set a callback
to C2VdaBqBlockPool. When there is an available block,
C2VdaBqBlockPool will notify VideoFramePool via the callback.
Bug: 166072201
Test: pass tast.arc.VideoDecodeAccel.h264_vm
Change-Id: I27380f144a496457349799cf5ad15c5f8986e307
Diffstat (limited to 'components')
-rw-r--r-- | components/VideoFramePool.cpp | 100 | ||||
-rw-r--r-- | components/include/v4l2_codec2/components/VideoFramePool.h | 11 |
2 files changed, 72 insertions, 39 deletions
diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp index 22b622d..b6bbfab 100644 --- a/components/VideoFramePool.cpp +++ b/components/VideoFramePool.cpp @@ -57,6 +57,17 @@ 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<C2VdaBqBlockPool*>(&blockPool); + return bqPool->setNotifyBlockAvailableCb(std::move(cb)); + } + return false; +} + +// static std::unique_ptr<VideoFramePool> VideoFramePool::Create( std::shared_ptr<C2BlockPool> blockPool, const size_t numBuffers, const media::Size& size, HalPixelFormat pixelFormat, bool isSecure, @@ -106,7 +117,6 @@ VideoFramePool::~VideoFramePool() { ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence()); mClientWeakThisFactory.InvalidateWeakPtrs(); - mCancelGetFrame = true; if (mFetchThread.IsRunning()) { mFetchTaskRunner->PostTask(FROM_HERE, @@ -136,48 +146,68 @@ bool VideoFramePool::getVideoFrame(GetVideoFrameCB cb) { return true; } +// static +void VideoFramePool::getVideoFrameTaskThunk( + scoped_refptr<::base::SequencedTaskRunner> taskRunner, + std::optional<::base::WeakPtr<VideoFramePool>> weakPool) { + ALOGV("%s()", __func__); + ALOG_ASSERT(weakPool); + + taskRunner->PostTask(FROM_HERE, + ::base::BindOnce(&VideoFramePool::getVideoFrameTask, *weakPool)); +} + void VideoFramePool::getVideoFrameTask() { ALOGV("%s()", __func__); ALOG_ASSERT(mFetchTaskRunner->RunsTasksInCurrentSequence()); - // Initial delay: 64us - constexpr size_t kFetchRetryDelayInit = 64; - // Max delay: 16ms (1 frame at 60fps) - constexpr size_t kFetchRetryDelayMax = 16384; - std::optional<FrameWithBlockId> frameWithBlockId; - size_t numRetries = 0; - size_t delay = kFetchRetryDelayInit; - while (true) { - if (mCancelGetFrame) { - ALOGW("Request to get frame canceled after %zu retries", numRetries); - break; + // 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) + static size_t sNumRetries = 0; + static size_t sDelay = kFetchRetryDelayInit; + + 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++; } - 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_OK) { - ALOG_ASSERT(block != nullptr); - std::optional<uint32_t> bufferId = getBufferIdFromGraphicBlock(*mBlockPool, *block); - std::unique_ptr<VideoFrame> frame = VideoFrame::Create(std::move(block)); - // 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); - } - break; - } else if (err != C2_TIMED_OUT && err != C2_BLOCKING) { - ALOGE("Failed to fetch block, err=%d, retry %zu times", err, numRetries); - break; + return; + } + + // Reset to the default value. + sNumRetries = 0; + sDelay = kFetchRetryDelayInit; + + 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)); + // 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 { - ++numRetries; - ALOGV("fetchGraphicBlock() timeout, waiting %zuus (%zu retry)", delay, numRetries); - usleep(delay); - // Exponential backoff - delay = std::min(delay * 2, kFetchRetryDelayMax); + ALOGE("%s(): Failed to generate VideoFrame or get the buffer id.", __func__); } + } else { + ALOGE("%s(): Failed to fetch block, err=%d", __func__, err); } mClientTaskRunner->PostTask( diff --git a/components/include/v4l2_codec2/components/VideoFramePool.h b/components/include/v4l2_codec2/components/VideoFramePool.h index c05c4ff..71bfe27 100644 --- a/components/include/v4l2_codec2/components/VideoFramePool.h +++ b/components/include/v4l2_codec2/components/VideoFramePool.h @@ -28,7 +28,7 @@ namespace android { class VideoFramePool { public: using FrameWithBlockId = std::pair<std::unique_ptr<VideoFrame>, uint32_t>; - using GetVideoFrameCB = base::OnceCallback<void(std::optional<FrameWithBlockId>)>; + using GetVideoFrameCB = ::base::OnceCallback<void(std::optional<FrameWithBlockId>)>; static std::unique_ptr<VideoFramePool> Create( std::shared_ptr<C2BlockPool> blockPool, const size_t numBuffers, @@ -54,6 +54,8 @@ private: bool initialize(); void destroyTask(); + static void getVideoFrameTaskThunk(scoped_refptr<::base::SequencedTaskRunner> taskRunner, + std::optional<::base::WeakPtr<VideoFramePool>> weakPool); void getVideoFrameTask(); void onVideoFrameReady(std::optional<FrameWithBlockId> frameWithBlockId); @@ -66,6 +68,10 @@ private: // |bufferCount| is the number of requested buffers. static c2_status_t requestNewBufferSet(C2BlockPool& blockPool, int32_t bufferCount); + // 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<C2BlockPool> mBlockPool; const media::Size mSize; const HalPixelFormat mPixelFormat; @@ -77,9 +83,6 @@ private: ::base::Thread mFetchThread{"VideoFramePoolFetchThread"}; scoped_refptr<::base::SequencedTaskRunner> mFetchTaskRunner; - // Set to true to unconditionally interrupt pending frame requests. - std::atomic<bool> mCancelGetFrame = false; - ::base::WeakPtr<VideoFramePool> mClientWeakThis; ::base::WeakPtr<VideoFramePool> mFetchWeakThis; ::base::WeakPtrFactory<VideoFramePool> mClientWeakThisFactory{this}; |