aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorChih-Yu Huang <akahuang@google.com>2020-08-31 17:31:45 +0900
committerChih-Yu Huang <akahuang@google.com>2020-09-03 18:10:54 +0900
commit9cf0ab57d14d9f74e834c36a2a1e0324e0482e89 (patch)
tree15b302105bc458b9189b9ea1fa3c39e9966c7183 /components
parent842849a0ac0d2825f9af76357dcd8967150ff583 (diff)
downloadv4l2_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.cpp100
-rw-r--r--components/include/v4l2_codec2/components/VideoFramePool.h11
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};