blob: 33e01e917de7bd0aa059461b7a5d59f9fbd7d434 [file] [log] [blame]
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +09001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//#define LOG_NDEBUG 0
6#define LOG_TAG "VideoFramePool"
7
8#include <v4l2_codec2/components/VideoFramePool.h>
9
10#include <stdint.h>
11#include <memory>
12
13#include <android/hardware/graphics/common/1.0/types.h>
14#include <base/bind.h>
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090015#include <base/memory/ptr_util.h>
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090016#include <base/time/time.h>
17#include <log/log.h>
18
19#include <v4l2_codec2/components/VideoTypes.h>
20
21using android::hardware::graphics::common::V1_0::BufferUsage;
22
23namespace android {
24namespace {
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090025// The number of times and timeout used between subsequent calls when fetching graphic blocks.
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090026constexpr size_t kAllocateBufferMaxRetries = 32;
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090027constexpr size_t kFetchRetryDelayUs = 1000;
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090028} // namespace
29
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090030// static
31std::unique_ptr<VideoFramePool> VideoFramePool::Create(
32 std::shared_ptr<C2BlockPool> blockPool, const media::Size& size, HalPixelFormat pixelFormat,
33 bool isSecure, scoped_refptr<::base::SequencedTaskRunner> taskRunner) {
34 std::unique_ptr<VideoFramePool> pool = ::base::WrapUnique(new VideoFramePool(
35 std::move(blockPool), size, pixelFormat, isSecure, std::move(taskRunner)));
36 if (!pool->initialize()) return nullptr;
37 return pool;
38}
39
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090040VideoFramePool::VideoFramePool(std::shared_ptr<C2BlockPool> blockPool, const media::Size& size,
41 HalPixelFormat pixelFormat, bool isSecure,
42 scoped_refptr<::base::SequencedTaskRunner> taskRunner)
43 : mBlockPool(std::move(blockPool)),
44 mSize(size),
45 mPixelFormat(pixelFormat),
46 mMemoryUsage(isSecure ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ,
47 static_cast<uint64_t>(BufferUsage::VIDEO_DECODER)),
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090048 mClientTaskRunner(std::move(taskRunner)) {
Chih-Yu Huangfa546d32020-07-02 16:26:52 +090049 ALOGV("%s(size=%dx%d)", __func__, size.width(), size.height());
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090050 ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090051 DCHECK(mBlockPool);
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090052 DCHECK(mClientTaskRunner);
53}
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090054
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090055bool VideoFramePool::initialize() {
56 if (!mFetchThread.Start()) {
57 ALOGE("Fetch thread failed to start.");
58 return false;
59 }
60 mFetchTaskRunner = mFetchThread.task_runner();
61
62 mClientWeakThis = mClientWeakThisFactory.GetWeakPtr();
63 mFetchWeakThis = mFetchWeakThisFactory.GetWeakPtr();
64
65 return true;
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090066}
67
68VideoFramePool::~VideoFramePool() {
69 ALOGV("%s()", __func__);
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090070 ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090071
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090072 mClientWeakThisFactory.InvalidateWeakPtrs();
73
74 if (mFetchThread.IsRunning()) {
75 mFetchTaskRunner->PostTask(FROM_HERE,
76 ::base::BindOnce(&VideoFramePool::destroyTask, mFetchWeakThis));
77 mFetchThread.Stop();
78 }
79}
80
81void VideoFramePool::destroyTask() {
82 ALOGV("%s()", __func__);
83 ALOG_ASSERT(mFetchTaskRunner->RunsTasksInCurrentSequence());
84
85 mFetchWeakThisFactory.InvalidateWeakPtrs();
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090086}
87
88void VideoFramePool::getVideoFrame(GetVideoFrameCB cb) {
89 ALOGV("%s()", __func__);
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090090 ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090091
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090092 ++mNumPendingRequests;
93 mFetchTaskRunner->PostTask(FROM_HERE, ::base::BindOnce(&VideoFramePool::getVideoFrameTask,
94 mFetchWeakThis, std::move(cb)));
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +090095}
96
97bool VideoFramePool::hasPendingRequests() const {
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +090098 ALOGV("%s()", __func__);
99 ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
100
101 return mNumPendingRequests > 0;
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900102}
103
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900104void VideoFramePool::getVideoFrameTask(GetVideoFrameCB cb) {
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900105 ALOGV("%s()", __func__);
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900106 ALOG_ASSERT(mFetchTaskRunner->RunsTasksInCurrentSequence());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900107
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900108 std::unique_ptr<VideoFrame> frame = nullptr;
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900109
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900110 size_t numRetries = 0;
111 while (numRetries < kAllocateBufferMaxRetries) {
112 std::shared_ptr<C2GraphicBlock> block;
113 c2_status_t err = mBlockPool->fetchGraphicBlock(mSize.width(), mSize.height(),
114 static_cast<uint32_t>(mPixelFormat),
115 mMemoryUsage, &block);
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900116
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900117 if (err == C2_OK) {
118 frame = VideoFrame::Create(std::move(block));
119 break;
120 } else if (err != C2_TIMED_OUT && err != C2_BLOCKING) {
121 ALOGE("Failed to fetch block, err=%d, retry %zu times", err, numRetries);
122 break;
123 } else {
124 ++numRetries;
125 ALOGD("fetchGraphicBlock() timeout. retry %zu times", numRetries);
126 usleep(kFetchRetryDelayUs);
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900127 }
128 }
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900129 if (numRetries == kAllocateBufferMaxRetries) {
130 ALOGE("Timeout to fetch block, retry %zu times", numRetries);
131 }
132
133 mClientTaskRunner->PostTask(
134 FROM_HERE, ::base::BindOnce(&VideoFramePool::onVideoFrameReady, mClientWeakThis,
135 std::move(cb), std::move(frame)));
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900136}
137
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900138void VideoFramePool::onVideoFrameReady(GetVideoFrameCB cb, std::unique_ptr<VideoFrame> frame) {
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900139 ALOGV("%s()", __func__);
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900140 ALOG_ASSERT(mClientTaskRunner->RunsTasksInCurrentSequence());
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900141
Chih-Yu Huangbe8f8422020-05-29 16:53:12 +0900142 --mNumPendingRequests;
143
144 if (!frame) {
145 ALOGE("Failed to get GraphicBlock, abandoning all pending requests.");
146 mClientWeakThisFactory.InvalidateWeakPtrs();
147 mClientWeakThis = mClientWeakThisFactory.GetWeakPtr();
148
149 mNumPendingRequests = 0;
150 }
151
Chih-Yu Huang6a7255a2020-03-25 17:01:47 +0900152 std::move(cb).Run(std::move(frame));
153}
154
155} // namespace android