aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorChih-Yu Huang <akahuang@google.com>2020-05-29 16:53:12 +0900
committerChih-Yu Huang <akahuang@google.com>2020-06-05 14:26:04 +0900
commitbe8f84242f32f07347ffb74e1bee3856f57a227b (patch)
tree3df8f1042c7ada68ad0ac1d2c647f876b7921167 /components
parentb65c212ff004cce1b383c3d3002914a1ab507937 (diff)
downloadv4l2_codec2-be8f84242f32f07347ffb74e1bee3856f57a227b.tar.gz
components: VideoFramePool uses dedicated thread to fetch GraphicBlock
Originally VideoFramePool shared the same thread with V4L2Decoder. It turned out the performance is pretty bad, many frames were dropped. In this CL, VideoFramePool creates a dedicated thread and fetch GraphicBlock on this thread. Bug: 146406514 Test: pass e2e test Change-Id: I3c51cf1ce1d8e40fb52ad947d779e8c0ad2f754c
Diffstat (limited to 'components')
-rw-r--r--components/V4L2DecodeComponent.cpp4
-rw-r--r--components/VideoFramePool.cpp134
-rw-r--r--components/include/v4l2_codec2/components/VideoFramePool.h42
3 files changed, 121 insertions, 59 deletions
diff --git a/components/V4L2DecodeComponent.cpp b/components/V4L2DecodeComponent.cpp
index 64cb4ba..4c657e5 100644
--- a/components/V4L2DecodeComponent.cpp
+++ b/components/V4L2DecodeComponent.cpp
@@ -275,8 +275,8 @@ void V4L2DecodeComponent::getVideoFramePool(std::unique_ptr<VideoFramePool>* poo
return;
}
- *pool = std::make_unique<VideoFramePool>(std::move(blockPool), size, pixelFormat, mIsSecure,
- mDecoderTaskRunner);
+ *pool = VideoFramePool::Create(std::move(blockPool), size, pixelFormat, mIsSecure,
+ mDecoderTaskRunner);
}
c2_status_t V4L2DecodeComponent::stop() {
diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp
index c2f68fc..acda536 100644
--- a/components/VideoFramePool.cpp
+++ b/components/VideoFramePool.cpp
@@ -12,6 +12,7 @@
#include <android/hardware/graphics/common/1.0/types.h>
#include <base/bind.h>
+#include <base/memory/ptr_util.h>
#include <base/time/time.h>
#include <log/log.h>
@@ -21,10 +22,21 @@ using android::hardware::graphics::common::V1_0::BufferUsage;
namespace android {
namespace {
+// The number of times and timeout used between subsequent calls when fetching graphic blocks.
constexpr size_t kAllocateBufferMaxRetries = 32;
-constexpr size_t kFetchRetryDelayUs = 500;
+constexpr size_t kFetchRetryDelayUs = 1000;
} // namespace
+// static
+std::unique_ptr<VideoFramePool> VideoFramePool::Create(
+ std::shared_ptr<C2BlockPool> blockPool, const media::Size& size, HalPixelFormat pixelFormat,
+ bool isSecure, scoped_refptr<::base::SequencedTaskRunner> taskRunner) {
+ std::unique_ptr<VideoFramePool> pool = ::base::WrapUnique(new VideoFramePool(
+ std::move(blockPool), size, pixelFormat, isSecure, std::move(taskRunner)));
+ if (!pool->initialize()) return nullptr;
+ return pool;
+}
+
VideoFramePool::VideoFramePool(std::shared_ptr<C2BlockPool> blockPool, const media::Size& size,
HalPixelFormat pixelFormat, bool isSecure,
scoped_refptr<::base::SequencedTaskRunner> taskRunner)
@@ -33,72 +45,110 @@ VideoFramePool::VideoFramePool(std::shared_ptr<C2BlockPool> blockPool, const med
mPixelFormat(pixelFormat),
mMemoryUsage(isSecure ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ,
static_cast<uint64_t>(BufferUsage::VIDEO_DECODER)),
- mTaskRunner(std::move(taskRunner)) {
+ mClientTaskRunner(std::move(taskRunner)) {
ALOGV("%s()", __func__);
- ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+ ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
DCHECK(mBlockPool);
- DCHECK(mTaskRunner);
+ DCHECK(mClientTaskRunner);
+}
+
+bool VideoFramePool::initialize() {
+ if (!mFetchThread.Start()) {
+ ALOGE("Fetch thread failed to start.");
+ return false;
+ }
+ mFetchTaskRunner = mFetchThread.task_runner();
- mWeakThis = mWeakThisFactory.GetWeakPtr();
+ mClientWeakThis = mClientWeakThisFactory.GetWeakPtr();
+ mFetchWeakThis = mFetchWeakThisFactory.GetWeakPtr();
+
+ return true;
}
VideoFramePool::~VideoFramePool() {
ALOGV("%s()", __func__);
- ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+ ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
+
+ mClientWeakThisFactory.InvalidateWeakPtrs();
+
+ if (mFetchThread.IsRunning()) {
+ mFetchTaskRunner->PostTask(FROM_HERE,
+ ::base::BindOnce(&VideoFramePool::destroyTask, mFetchWeakThis));
+ mFetchThread.Stop();
+ }
+}
+
+void VideoFramePool::destroyTask() {
+ ALOGV("%s()", __func__);
+ ALOG_ASSERT(mFetchTaskRunner->RunsTasksInCurrentSequence());
- mWeakThisFactory.InvalidateWeakPtrs();
+ mFetchWeakThisFactory.InvalidateWeakPtrs();
}
void VideoFramePool::getVideoFrame(GetVideoFrameCB cb) {
ALOGV("%s()", __func__);
- ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+ ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
- bool isRunning = !mCbQueue.empty();
- mCbQueue.push(std::move(cb));
- if (!isRunning) tryFetchGraphicBlock();
+ ++mNumPendingRequests;
+ mFetchTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(&VideoFramePool::getVideoFrameTask,
+ mFetchWeakThis, std::move(cb)));
}
bool VideoFramePool::hasPendingRequests() const {
- return !mCbQueue.empty();
+ ALOGV("%s()", __func__);
+ ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
+
+ return mNumPendingRequests > 0;
}
-void VideoFramePool::tryFetchGraphicBlock() {
+void VideoFramePool::getVideoFrameTask(GetVideoFrameCB cb) {
ALOGV("%s()", __func__);
- ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
-
- if (mCbQueue.empty()) return;
-
- std::shared_ptr<C2GraphicBlock> block;
- auto err = mBlockPool->fetchGraphicBlock(mSize.width(), mSize.height(),
- static_cast<uint32_t>(mPixelFormat), mMemoryUsage,
- &block);
-
- if ((err == C2_TIMED_OUT || err == C2_BLOCKING) && mNumRetries++ < kAllocateBufferMaxRetries) {
- ALOGD("fetchGraphicBlock() timeout. retry %zu times", mNumRetries);
- mTaskRunner->PostDelayedTask(
- FROM_HERE, ::base::BindOnce(&VideoFramePool::tryFetchGraphicBlock, mWeakThis),
- ::base::TimeDelta::FromMicroseconds(kFetchRetryDelayUs));
- } else if (err != C2_OK) {
- ALOGE("Failed to fetch block, err=%d, retry %zu times", err, mNumRetries);
- sendVideoFrame(nullptr);
- } else {
- mNumRetries = 0;
- sendVideoFrame(VideoFrame::Create(std::move(block)));
-
- if (!mCbQueue.empty()) {
- mTaskRunner->PostTask(
- FROM_HERE, ::base::BindOnce(&VideoFramePool::tryFetchGraphicBlock, mWeakThis));
+ ALOG_ASSERT(mFetchTaskRunner->RunsTasksInCurrentSequence());
+
+ std::unique_ptr<VideoFrame> frame = nullptr;
+
+ size_t numRetries = 0;
+ while (numRetries < kAllocateBufferMaxRetries) {
+ 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) {
+ frame = VideoFrame::Create(std::move(block));
+ break;
+ } else if (err != C2_TIMED_OUT && err != C2_BLOCKING) {
+ ALOGE("Failed to fetch block, err=%d, retry %zu times", err, numRetries);
+ break;
+ } else {
+ ++numRetries;
+ ALOGD("fetchGraphicBlock() timeout. retry %zu times", numRetries);
+ usleep(kFetchRetryDelayUs);
}
}
+ if (numRetries == kAllocateBufferMaxRetries) {
+ ALOGE("Timeout to fetch block, retry %zu times", numRetries);
+ }
+
+ mClientTaskRunner->PostTask(
+ FROM_HERE, ::base::BindOnce(&VideoFramePool::onVideoFrameReady, mClientWeakThis,
+ std::move(cb), std::move(frame)));
}
-void VideoFramePool::sendVideoFrame(std::unique_ptr<VideoFrame> frame) {
+void VideoFramePool::onVideoFrameReady(GetVideoFrameCB cb, std::unique_ptr<VideoFrame> frame) {
ALOGV("%s()", __func__);
- ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
- ALOG_ASSERT(!mCbQueue.empty());
+ ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
+
+ --mNumPendingRequests;
+
+ if (!frame) {
+ ALOGE("Failed to get GraphicBlock, abandoning all pending requests.");
+ mClientWeakThisFactory.InvalidateWeakPtrs();
+ mClientWeakThis = mClientWeakThisFactory.GetWeakPtr();
+
+ mNumPendingRequests = 0;
+ }
- auto cb = std::move(mCbQueue.front());
- mCbQueue.pop();
std::move(cb).Run(std::move(frame));
}
diff --git a/components/include/v4l2_codec2/components/VideoFramePool.h b/components/include/v4l2_codec2/components/VideoFramePool.h
index 64e9d71..079e640 100644
--- a/components/include/v4l2_codec2/components/VideoFramePool.h
+++ b/components/include/v4l2_codec2/components/VideoFramePool.h
@@ -12,6 +12,7 @@
#include <base/callback.h>
#include <base/memory/weak_ptr.h>
#include <base/sequenced_task_runner.h>
+#include <base/threading/thread.h>
#include <size.h>
#include <v4l2_codec2/components/VideoFrame.h>
@@ -26,14 +27,10 @@ class VideoFramePool {
public:
using GetVideoFrameCB = base::OnceCallback<void(std::unique_ptr<VideoFrame>)>;
- // |blockPool| is the C2BlockPool that we fetch graphic blocks from.
- // |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<C2BlockPool> blockPool, const media::Size& size,
- HalPixelFormat pixelFormat, bool isSecure,
- scoped_refptr<::base::SequencedTaskRunner> taskRunner);
+ static std::unique_ptr<VideoFramePool> Create(
+ std::shared_ptr<C2BlockPool> blockPool, const media::Size& size,
+ HalPixelFormat pixelFormat, bool isSecure,
+ scoped_refptr<::base::SequencedTaskRunner> taskRunner);
~VideoFramePool();
// Get a VideoFrame instance, which will be passed via |cb|.
@@ -44,20 +41,35 @@ public:
bool hasPendingRequests() const;
private:
- void tryFetchGraphicBlock();
- void sendVideoFrame(std::unique_ptr<VideoFrame> frame);
+ // |blockPool| is the C2BlockPool that we fetch graphic blocks from.
+ // |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<C2BlockPool> blockPool, const media::Size& size,
+ HalPixelFormat pixelFormat, bool isSecure,
+ scoped_refptr<::base::SequencedTaskRunner> taskRunner);
+ bool initialize();
+ void destroyTask();
+
+ void getVideoFrameTask(GetVideoFrameCB cb);
+ void onVideoFrameReady(GetVideoFrameCB cb, std::unique_ptr<VideoFrame> frame);
std::shared_ptr<C2BlockPool> mBlockPool;
const media::Size mSize;
const HalPixelFormat mPixelFormat;
const C2MemoryUsage mMemoryUsage;
- std::queue<GetVideoFrameCB> mCbQueue;
- size_t mNumRetries = 0;
+ size_t mNumPendingRequests = 0;
+
+ scoped_refptr<::base::SequencedTaskRunner> mClientTaskRunner;
+ ::base::Thread mFetchThread{"VideoFramePoolFetchThread"};
+ scoped_refptr<::base::SequencedTaskRunner> mFetchTaskRunner;
- scoped_refptr<::base::SequencedTaskRunner> mTaskRunner;
- base::WeakPtr<VideoFramePool> mWeakThis;
- base::WeakPtrFactory<VideoFramePool> mWeakThisFactory{this};
+ ::base::WeakPtr<VideoFramePool> mClientWeakThis;
+ ::base::WeakPtr<VideoFramePool> mFetchWeakThis;
+ ::base::WeakPtrFactory<VideoFramePool> mClientWeakThisFactory{this};
+ ::base::WeakPtrFactory<VideoFramePool> mFetchWeakThisFactory{this};
};
} // namespace android