1 // Copyright 2023 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 "V4L2DecodeComponent"
7
8 #include <v4l2_codec2/v4l2/V4L2DecodeComponent.h>
9 #include <v4l2_codec2/v4l2/V4L2Decoder.h>
10
11 #include <base/bind.h>
12 #include <base/callback_helpers.h>
13
14 #include <cutils/properties.h>
15 #include <utils/Trace.h>
16
17 namespace android {
18
19 namespace {
20 // CCBC pauses sending input buffers to the component when all the output slots are filled by
21 // pending decoded buffers. If the available output buffers are exhausted before CCBC pauses sending
22 // input buffers, CCodec may timeout due to waiting for a available output buffer.
23 // This function returns the minimum number of output buffers to prevent the buffers from being
24 // exhausted before CCBC pauses sending input buffers.
getMinNumOutputBuffers(VideoCodec codec)25 size_t getMinNumOutputBuffers(VideoCodec codec) {
26 // The constant values copied from CCodecBufferChannel.cpp.
27 // (b/184020290): Check the value still sync when seeing error message from CCodec:
28 // "previous call to queue exceeded timeout".
29 constexpr size_t kSmoothnessFactor = 4;
30 constexpr size_t kRenderingDepth = 3;
31 // Extra number of needed output buffers for V4L2Decoder.
32 constexpr size_t kExtraNumOutputBuffersForDecoder = 2;
33
34 // The total needed number of output buffers at pipeline are:
35 // - MediaCodec output slots: output delay + kSmoothnessFactor
36 // - Surface: kRenderingDepth
37 // - Component: kExtraNumOutputBuffersForDecoder
38 return DecodeInterface::getOutputDelay(codec) + kSmoothnessFactor + kRenderingDepth +
39 kExtraNumOutputBuffersForDecoder;
40 }
41 } // namespace
42
43 // static
44 std::atomic<int32_t> V4L2DecodeComponent::sConcurrentInstances = 0;
45
46 // static
47 std::atomic<uint32_t> V4L2DecodeComponent::sNextDebugStreamId = 0;
48
49 // static
create(const std::string & name,c2_node_id_t id,std::shared_ptr<DecodeInterface> intfImpl,C2ComponentFactory::ComponentDeleter deleter)50 std::shared_ptr<C2Component> V4L2DecodeComponent::create(
51 const std::string& name, c2_node_id_t id, std::shared_ptr<DecodeInterface> intfImpl,
52 C2ComponentFactory::ComponentDeleter deleter) {
53 static const int32_t kMaxConcurrentInstances =
54 property_get_int32("ro.vendor.v4l2_codec2.decode_concurrent_instances", -1);
55 static std::mutex mutex;
56
57 std::lock_guard<std::mutex> lock(mutex);
58
59 if (kMaxConcurrentInstances >= 0 && sConcurrentInstances.load() >= kMaxConcurrentInstances) {
60 ALOGW("Reject to Initialize() due to too many instances: %d", sConcurrentInstances.load());
61 return nullptr;
62 } else if (sConcurrentInstances.load() == 0) {
63 sNextDebugStreamId.store(0, std::memory_order_relaxed);
64 }
65
66 uint32_t debugStreamId = sNextDebugStreamId.fetch_add(1, std::memory_order_relaxed);
67 return std::shared_ptr<C2Component>(
68 new V4L2DecodeComponent(debugStreamId, name, id, std::move(intfImpl)), deleter);
69 }
70
V4L2DecodeComponent(uint32_t debugStreamId,const std::string & name,c2_node_id_t id,std::shared_ptr<DecodeInterface> intfImpl)71 V4L2DecodeComponent::V4L2DecodeComponent(uint32_t debugStreamId, const std::string& name,
72 c2_node_id_t id, std::shared_ptr<DecodeInterface> intfImpl)
73 : DecodeComponent(debugStreamId, name, id, intfImpl) {
74 ALOGV("%s(): ", __func__);
75 sConcurrentInstances.fetch_add(1, std::memory_order_relaxed);
76 }
77
~V4L2DecodeComponent()78 V4L2DecodeComponent::~V4L2DecodeComponent() {
79 ALOGV("%s(): ", __func__);
80 sConcurrentInstances.fetch_sub(1, std::memory_order_relaxed);
81 }
82
startTask(c2_status_t * status,::base::WaitableEvent * done)83 void V4L2DecodeComponent::startTask(c2_status_t* status, ::base::WaitableEvent* done) {
84 ATRACE_CALL();
85 ALOGV("%s()", __func__);
86 ALOG_ASSERT(mDecoderTaskRunner->RunsTasksInCurrentSequence());
87
88 ::base::ScopedClosureRunner done_caller(
89 ::base::BindOnce(&::base::WaitableEvent::Signal, ::base::Unretained(done)));
90 *status = C2_CORRUPTED;
91
92 const auto codec = mIntfImpl->getVideoCodec();
93 if (!codec) {
94 ALOGE("Failed to get video codec.");
95 return;
96 }
97 const size_t inputBufferSize = mIntfImpl->getInputBufferSize();
98 const size_t minNumOutputBuffers = getMinNumOutputBuffers(*codec);
99
100 // ::base::Unretained(this) is safe here because |mDecoder| is always destroyed before
101 // |mDecoderThread| is stopped, so |*this| is always valid during |mDecoder|'s lifetime.
102 mDecoder = V4L2Decoder::Create(mDebugStreamId, *codec, inputBufferSize, minNumOutputBuffers,
103 ::base::BindRepeating(&V4L2DecodeComponent::getVideoFramePool,
104 ::base::Unretained(this)),
105 ::base::BindRepeating(&V4L2DecodeComponent::onOutputFrameReady,
106 ::base::Unretained(this)),
107 ::base::BindRepeating(&V4L2DecodeComponent::reportError,
108 ::base::Unretained(this), C2_CORRUPTED),
109 mDecoderTaskRunner, mIsSecure);
110 if (!mDecoder) {
111 ALOGE("Failed to create V4L2Decoder for %s", VideoCodecToString(*codec));
112 return;
113 }
114
115 // Get default color aspects on start.
116 if (!mIsSecure && *codec == VideoCodec::H264) {
117 if (mIntfImpl->queryColorAspects(&mCurrentColorAspects) != C2_OK) return;
118 mPendingColorAspectsChange = false;
119 }
120
121 *status = C2_OK;
122 }
123
124 } // namespace android
125