xref: /aosp_15_r20/external/v4l2_codec2/v4l2/V4L2EncodeComponent.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 "V4L2EncodeComponent"
7*0ec5a0ecSAndroid Build Coastguard Worker 
8*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2EncodeComponent.h>
9*0ec5a0ecSAndroid Build Coastguard Worker 
10*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind_helpers.h>
11*0ec5a0ecSAndroid Build Coastguard Worker 
12*0ec5a0ecSAndroid Build Coastguard Worker #include <cutils/properties.h>
13*0ec5a0ecSAndroid Build Coastguard Worker 
14*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/H264.h>
15*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/BitstreamBuffer.h>
16*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/components/EncodeInterface.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2Encoder.h>
18*0ec5a0ecSAndroid Build Coastguard Worker 
19*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
20*0ec5a0ecSAndroid Build Coastguard Worker 
21*0ec5a0ecSAndroid Build Coastguard Worker // static
22*0ec5a0ecSAndroid Build Coastguard Worker std::atomic<int32_t> V4L2EncodeComponent::sConcurrentInstances = 0;
23*0ec5a0ecSAndroid Build Coastguard Worker 
24*0ec5a0ecSAndroid Build Coastguard Worker // static
create(C2String name,c2_node_id_t id,std::shared_ptr<EncodeInterface> intfImpl,C2ComponentFactory::ComponentDeleter deleter)25*0ec5a0ecSAndroid Build Coastguard Worker std::shared_ptr<C2Component> V4L2EncodeComponent::create(
26*0ec5a0ecSAndroid Build Coastguard Worker         C2String name, c2_node_id_t id, std::shared_ptr<EncodeInterface> intfImpl,
27*0ec5a0ecSAndroid Build Coastguard Worker         C2ComponentFactory::ComponentDeleter deleter) {
28*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s(%s)", __func__, name.c_str());
29*0ec5a0ecSAndroid Build Coastguard Worker 
30*0ec5a0ecSAndroid Build Coastguard Worker     static const int32_t kMaxConcurrentInstances =
31*0ec5a0ecSAndroid Build Coastguard Worker             property_get_int32("ro.vendor.v4l2_codec2.encode_concurrent_instances", -1);
32*0ec5a0ecSAndroid Build Coastguard Worker 
33*0ec5a0ecSAndroid Build Coastguard Worker     static std::mutex mutex;
34*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mutex);
35*0ec5a0ecSAndroid Build Coastguard Worker     if (kMaxConcurrentInstances >= 0 && sConcurrentInstances.load() >= kMaxConcurrentInstances) {
36*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Cannot create additional encoder, maximum number of instances reached: %d",
37*0ec5a0ecSAndroid Build Coastguard Worker               kMaxConcurrentInstances);
38*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
39*0ec5a0ecSAndroid Build Coastguard Worker     }
40*0ec5a0ecSAndroid Build Coastguard Worker 
41*0ec5a0ecSAndroid Build Coastguard Worker     return std::shared_ptr<C2Component>(new V4L2EncodeComponent(name, id, std::move(intfImpl)),
42*0ec5a0ecSAndroid Build Coastguard Worker                                         deleter);
43*0ec5a0ecSAndroid Build Coastguard Worker }
44*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2EncodeComponent(C2String name,c2_node_id_t id,std::shared_ptr<EncodeInterface> interface)45*0ec5a0ecSAndroid Build Coastguard Worker V4L2EncodeComponent::V4L2EncodeComponent(C2String name, c2_node_id_t id,
46*0ec5a0ecSAndroid Build Coastguard Worker                                          std::shared_ptr<EncodeInterface> interface)
47*0ec5a0ecSAndroid Build Coastguard Worker       : EncodeComponent(name, id, interface) {
48*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s():", __func__);
49*0ec5a0ecSAndroid Build Coastguard Worker     sConcurrentInstances.fetch_add(1, std::memory_order_relaxed);
50*0ec5a0ecSAndroid Build Coastguard Worker }
51*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2EncodeComponent()52*0ec5a0ecSAndroid Build Coastguard Worker V4L2EncodeComponent::~V4L2EncodeComponent() {
53*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s():", __func__);
54*0ec5a0ecSAndroid Build Coastguard Worker     sConcurrentInstances.fetch_sub(1, std::memory_order_relaxed);
55*0ec5a0ecSAndroid Build Coastguard Worker }
56*0ec5a0ecSAndroid Build Coastguard Worker 
initializeEncoder()57*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2EncodeComponent::initializeEncoder() {
58*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
59*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mEncoderTaskRunner->RunsTasksInCurrentSequence());
60*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mInputFormatConverter);
61*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mEncoder);
62*0ec5a0ecSAndroid Build Coastguard Worker 
63*0ec5a0ecSAndroid Build Coastguard Worker     mLastFrameTime = std::nullopt;
64*0ec5a0ecSAndroid Build Coastguard Worker 
65*0ec5a0ecSAndroid Build Coastguard Worker     // Get the requested profile and level.
66*0ec5a0ecSAndroid Build Coastguard Worker     C2Config::profile_t outputProfile = mInterface->getOutputProfile();
67*0ec5a0ecSAndroid Build Coastguard Worker 
68*0ec5a0ecSAndroid Build Coastguard Worker     // CSD only needs to be extracted when using an H.264 profile.
69*0ec5a0ecSAndroid Build Coastguard Worker     mExtractCSD = isH264Profile(outputProfile);
70*0ec5a0ecSAndroid Build Coastguard Worker 
71*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<uint8_t> h264Level;
72*0ec5a0ecSAndroid Build Coastguard Worker     if (isH264Profile(outputProfile)) {
73*0ec5a0ecSAndroid Build Coastguard Worker         h264Level = c2LevelToV4L2Level(mInterface->getOutputLevel());
74*0ec5a0ecSAndroid Build Coastguard Worker     }
75*0ec5a0ecSAndroid Build Coastguard Worker 
76*0ec5a0ecSAndroid Build Coastguard Worker     // Get the stride used by the C2 framework, as this might be different from the stride used by
77*0ec5a0ecSAndroid Build Coastguard Worker     // the V4L2 encoder.
78*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<uint32_t> stride =
79*0ec5a0ecSAndroid Build Coastguard Worker             getVideoFrameStride(VideoEncoder::kInputPixelFormat, mInterface->getInputVisibleSize());
80*0ec5a0ecSAndroid Build Coastguard Worker     if (!stride) {
81*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to get video frame stride");
82*0ec5a0ecSAndroid Build Coastguard Worker         reportError(C2_CORRUPTED);
83*0ec5a0ecSAndroid Build Coastguard Worker         return false;
84*0ec5a0ecSAndroid Build Coastguard Worker     }
85*0ec5a0ecSAndroid Build Coastguard Worker 
86*0ec5a0ecSAndroid Build Coastguard Worker     // Get the requested bitrate mode and bitrate. The C2 framework doesn't offer a parameter to
87*0ec5a0ecSAndroid Build Coastguard Worker     // configure the peak bitrate, so we use a multiple of the target bitrate.
88*0ec5a0ecSAndroid Build Coastguard Worker     mBitrateMode = mInterface->getBitrateMode();
89*0ec5a0ecSAndroid Build Coastguard Worker     if (property_get_bool("persist.vendor.v4l2_codec2.disable_vbr", false)) {
90*0ec5a0ecSAndroid Build Coastguard Worker         // NOTE: This is a workaround for b/235771157.
91*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("VBR is disabled on this device");
92*0ec5a0ecSAndroid Build Coastguard Worker         mBitrateMode = C2Config::BITRATE_CONST;
93*0ec5a0ecSAndroid Build Coastguard Worker     }
94*0ec5a0ecSAndroid Build Coastguard Worker 
95*0ec5a0ecSAndroid Build Coastguard Worker     mBitrate = mInterface->getBitrate();
96*0ec5a0ecSAndroid Build Coastguard Worker 
97*0ec5a0ecSAndroid Build Coastguard Worker     mEncoder = V4L2Encoder::create(
98*0ec5a0ecSAndroid Build Coastguard Worker             outputProfile, h264Level, mInterface->getInputVisibleSize(), *stride,
99*0ec5a0ecSAndroid Build Coastguard Worker             mInterface->getKeyFramePeriod(), mBitrateMode, mBitrate,
100*0ec5a0ecSAndroid Build Coastguard Worker             mBitrate * VideoEncoder::kPeakBitrateMultiplier,
101*0ec5a0ecSAndroid Build Coastguard Worker             ::base::BindRepeating(&V4L2EncodeComponent::fetchOutputBlock, mWeakThis),
102*0ec5a0ecSAndroid Build Coastguard Worker             ::base::BindRepeating(&V4L2EncodeComponent::onInputBufferDone, mWeakThis),
103*0ec5a0ecSAndroid Build Coastguard Worker             ::base::BindRepeating(&V4L2EncodeComponent::onOutputBufferDone, mWeakThis),
104*0ec5a0ecSAndroid Build Coastguard Worker             ::base::BindRepeating(&V4L2EncodeComponent::onDrainDone, mWeakThis),
105*0ec5a0ecSAndroid Build Coastguard Worker             ::base::BindRepeating(&V4L2EncodeComponent::reportError, mWeakThis, C2_CORRUPTED),
106*0ec5a0ecSAndroid Build Coastguard Worker             mEncoderTaskRunner);
107*0ec5a0ecSAndroid Build Coastguard Worker     if (!mEncoder) {
108*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to create V4L2Encoder (profile: %s)", profileToString(outputProfile));
109*0ec5a0ecSAndroid Build Coastguard Worker         return false;
110*0ec5a0ecSAndroid Build Coastguard Worker     }
111*0ec5a0ecSAndroid Build Coastguard Worker 
112*0ec5a0ecSAndroid Build Coastguard Worker     return true;
113*0ec5a0ecSAndroid Build Coastguard Worker }
114*0ec5a0ecSAndroid Build Coastguard Worker 
115*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
116