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