xref: /aosp_15_r20/external/v4l2_codec2/v4l2/V4L2DecodeComponent.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
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