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