1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hcodec_list.h"
17 #include <map>
18 #include <numeric>
19 #include "syspara/parameters.h"
20 #include "utils/hdf_base.h"
21 #include "hdi/iservmgr_hdi.h"
22 #include "hcodec_log.h"
23 #include "type_converter.h"
24 #include "avcodec_info.h"
25 #include "meta/meta.h"
26
27 namespace OHOS::MediaAVCodec {
28 using namespace std;
29 using namespace CodecHDI;
30 using namespace OHOS::HDI::ServiceManager::V1_0;
31
32 static mutex g_mtx;
33 static sptr<ICodecComponentManager> g_compMgrIpc;
34 static sptr<ICodecComponentManager> g_compMgrPassthru;
35
36 class Listener : public ServStatListenerStub {
37 public:
OnReceive(const ServiceStatus & status)38 void OnReceive(const ServiceStatus &status) override
39 {
40 if (status.serviceName == "codec_component_manager_service" && status.status == SERVIE_STATUS_STOP) {
41 LOGW("codec_component_manager_service died");
42 lock_guard<mutex> lk(g_mtx);
43 g_compMgrIpc = nullptr;
44 }
45 }
46 };
47
IsPassthroughFromParam()48 static std::optional<bool> IsPassthroughFromParam()
49 {
50 #ifdef BUILD_ENG_VERSION
51 string para = OHOS::system::GetParameter("hcodec.usePassthrough", "-1");
52 if (para == "1") {
53 return true;
54 }
55 if (para == "0") {
56 return false;
57 }
58 #endif
59 return std::nullopt;
60 }
61
GetManager(bool getCap,bool supportPassthrough)62 sptr<ICodecComponentManager> GetManager(bool getCap, bool supportPassthrough)
63 {
64 lock_guard<mutex> lk(g_mtx);
65 bool isPassthrough = false;
66 if (getCap) {
67 isPassthrough = true;
68 } else {
69 optional<bool> para = IsPassthroughFromParam();
70 isPassthrough = para.has_value() ? para.value() : supportPassthrough;
71 LOGI("%s mode", isPassthrough ? "passthrough" : "ipc");
72 }
73 sptr<ICodecComponentManager>& mng = (isPassthrough ? g_compMgrPassthru : g_compMgrIpc);
74 if (mng) {
75 return mng;
76 }
77 LOGI("need to get ICodecComponentManager");
78 if (!isPassthrough) {
79 sptr<IServiceManager> serviceMng = IServiceManager::Get();
80 if (serviceMng) {
81 serviceMng->RegisterServiceStatusListener(new Listener(), DEVICE_CLASS_DEFAULT);
82 }
83 }
84 mng = ICodecComponentManager::Get(isPassthrough);
85 return mng;
86 }
87
GetCapList()88 vector<CodecCompCapability> GetCapList()
89 {
90 sptr<ICodecComponentManager> mnger = GetManager(true);
91 if (mnger == nullptr) {
92 LOGE("failed to create codec component manager");
93 return {};
94 }
95 int32_t compCnt = 0;
96 int32_t ret = mnger->GetComponentNum(compCnt);
97 if (ret != HDF_SUCCESS || compCnt <= 0) {
98 LOGE("failed to query component number, ret=%d", ret);
99 return {};
100 }
101 std::vector<CodecCompCapability> capList(compCnt);
102 ret = mnger->GetComponentCapabilityList(capList, compCnt);
103 if (ret != HDF_SUCCESS) {
104 LOGE("failed to query component capability list, ret=%d", ret);
105 return {};
106 }
107 if (capList.empty()) {
108 LOGE("GetComponentCapabilityList return empty");
109 } else {
110 LOGI("GetComponentCapabilityList return %zu components", capList.size());
111 }
112 return capList;
113 }
114
GetCapabilityList(std::vector<CapabilityData> & caps)115 int32_t HCodecList::GetCapabilityList(std::vector<CapabilityData>& caps)
116 {
117 caps.clear();
118 vector<CodecCompCapability> capList = GetCapList();
119 for (const CodecCompCapability& one : capList) {
120 if (IsSupportedVideoCodec(one)) {
121 caps.emplace_back(HdiCapToUserCap(one));
122 }
123 }
124 return AVCS_ERR_OK;
125 }
126
IsSupportedVideoCodec(const CodecCompCapability & hdiCap)127 bool HCodecList::IsSupportedVideoCodec(const CodecCompCapability &hdiCap)
128 {
129 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC || hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC ||
130 hdiCap.role == MEDIA_ROLETYPE_VIDEO_VVC) {
131 return true;
132 }
133 return false;
134 }
135
HdiCapToUserCap(const CodecCompCapability & hdiCap)136 CapabilityData HCodecList::HdiCapToUserCap(const CodecCompCapability &hdiCap)
137 {
138 constexpr int32_t MAX_ENCODE_QUALITY = 100;
139 const CodecVideoPortCap& hdiVideoCap = hdiCap.port.video;
140 CapabilityData userCap;
141 userCap.codecName = hdiCap.compName;
142 userCap.codecType = TypeConverter::HdiCodecTypeToInnerCodecType(hdiCap.type).value_or(AVCODEC_TYPE_NONE);
143 userCap.mimeType = TypeConverter::HdiRoleToMime(hdiCap.role);
144 userCap.isVendor = true;
145 userCap.maxInstance = hdiCap.maxInst;
146 userCap.bitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
147 userCap.alignment = {hdiVideoCap.whAlignment.widthAlignment, hdiVideoCap.whAlignment.heightAlignment};
148 userCap.width = {hdiVideoCap.minSize.width, hdiVideoCap.maxSize.width};
149 userCap.height = {hdiVideoCap.minSize.height, hdiVideoCap.maxSize.height};
150 userCap.frameRate = {hdiVideoCap.frameRate.min, hdiVideoCap.frameRate.max};
151 userCap.blockPerFrame = {hdiVideoCap.blockCount.min, hdiVideoCap.blockCount.max};
152 userCap.blockPerSecond = {hdiVideoCap.blocksPerSecond.min, hdiVideoCap.blocksPerSecond.max};
153 userCap.blockSize = {hdiVideoCap.blockSize.width, hdiVideoCap.blockSize.height};
154 userCap.pixFormat = GetSupportedFormat(hdiVideoCap);
155 userCap.bitrateMode = GetSupportedBitrateMode(hdiVideoCap);
156 GetCodecProfileLevels(hdiCap, userCap);
157 userCap.measuredFrameRate = GetMeasuredFrameRate(hdiVideoCap);
158 userCap.supportSwapWidthHeight = hdiCap.canSwapWidthHeight;
159 userCap.encodeQuality = {0, MAX_ENCODE_QUALITY};
160 GetSupportedFeatureParam(hdiVideoCap, userCap);
161 LOGI("----- codecName: %s -----", userCap.codecName.c_str());
162 LOGI("codecType: %d, mimeType: %s, maxInstance %d",
163 userCap.codecType, userCap.mimeType.c_str(), userCap.maxInstance);
164 LOGI("bitrate: [%d, %d], alignment: [%d x %d]",
165 userCap.bitrate.minVal, userCap.bitrate.maxVal, userCap.alignment.width, userCap.alignment.height);
166 LOGI("width: [%d, %d], height: [%d, %d]",
167 userCap.width.minVal, userCap.width.maxVal, userCap.height.minVal, userCap.height.maxVal);
168 LOGI("frameRate: [%d, %d], blockSize: [%d x %d]",
169 userCap.frameRate.minVal, userCap.frameRate.maxVal, userCap.blockSize.width, userCap.blockSize.height);
170 LOGI("blockPerFrame: [%d, %d], blockPerSecond: [%d, %d]",
171 userCap.blockPerFrame.minVal, userCap.blockPerFrame.maxVal,
172 userCap.blockPerSecond.minVal, userCap.blockPerSecond.maxVal);
173 LOGI("isSupportPassthrough: %d", hdiVideoCap.isSupportPassthrough);
174 LOGI("isSupportWaterMark: %d, isSupportLowLatency: %d, isSupportTSVC: %d, isSupportLTR %d and maxLTRFrameNum %d",
175 hdiVideoCap.isSupportWaterMark, hdiVideoCap.isSupportLowLatency, hdiVideoCap.isSupportTSVC,
176 hdiVideoCap.isSupportLTR, hdiVideoCap.maxLTRFrameNum);
177 return userCap;
178 }
179
GetSupportedBitrateMode(const CodecVideoPortCap & hdiVideoCap)180 vector<int32_t> HCodecList::GetSupportedBitrateMode(const CodecVideoPortCap& hdiVideoCap)
181 {
182 vector<int32_t> vec;
183 for (BitRateMode mode : hdiVideoCap.bitRatemode) {
184 optional<VideoEncodeBitrateMode> innerMode = TypeConverter::HdiBitrateModeToInnerMode(mode);
185 if (innerMode.has_value()) {
186 vec.push_back(innerMode.value());
187 }
188 }
189 return vec;
190 }
191
GetSupportedFormat(const CodecVideoPortCap & hdiVideoCap)192 vector<int32_t> HCodecList::GetSupportedFormat(const CodecVideoPortCap& hdiVideoCap)
193 {
194 vector<int32_t> vec;
195 for (int32_t fmt : hdiVideoCap.supportPixFmts) {
196 optional<VideoPixelFormat> innerFmt =
197 TypeConverter::DisplayFmtToInnerFmt(static_cast<GraphicPixelFormat>(fmt));
198 if (innerFmt.has_value()) {
199 vec.push_back(static_cast<int32_t>(innerFmt.value()));
200 }
201 }
202 return vec;
203 }
204
GetMeasuredFrameRate(const CodecVideoPortCap & hdiVideoCap)205 map<ImgSize, Range> HCodecList::GetMeasuredFrameRate(const CodecVideoPortCap& hdiVideoCap)
206 {
207 enum MeasureStep {
208 WIDTH = 0,
209 HEIGHT = 1,
210 MIN_RATE = 2,
211 MAX_RATE = 3,
212 STEP_BUTT = 4
213 };
214 map<ImgSize, Range> userRateMap;
215 for (size_t index = 0; index < hdiVideoCap.measuredFrameRate.size(); index += STEP_BUTT) {
216 if (hdiVideoCap.measuredFrameRate[index] <= 0) {
217 continue;
218 }
219 ImgSize imageSize(hdiVideoCap.measuredFrameRate[index + WIDTH], hdiVideoCap.measuredFrameRate[index + HEIGHT]);
220 Range range(hdiVideoCap.measuredFrameRate[index + MIN_RATE], hdiVideoCap.measuredFrameRate[index + MAX_RATE]);
221 userRateMap[imageSize] = range;
222 }
223 return userRateMap;
224 }
225
GetCodecProfileLevels(const CodecCompCapability & hdiCap,CapabilityData & userCap)226 void HCodecList::GetCodecProfileLevels(const CodecCompCapability& hdiCap, CapabilityData& userCap)
227 {
228 for (size_t i = 0; i + 1 < hdiCap.supportProfiles.size(); i += 2) { // 2 means profile & level pair
229 int32_t profile = hdiCap.supportProfiles[i];
230 int32_t maxLevel = hdiCap.supportProfiles[i + 1];
231 optional<int32_t> innerProfile;
232 optional<int32_t> innerLevel;
233 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC) {
234 innerProfile = TypeConverter::OmxAvcProfileToInnerProfile(static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile));
235 innerLevel = TypeConverter::OmxAvcLevelToInnerLevel(static_cast<OMX_VIDEO_AVCLEVELTYPE>(maxLevel));
236 } else if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC) {
237 innerProfile = TypeConverter::OmxHevcProfileToInnerProfile(static_cast<CodecHevcProfile>(profile));
238 innerLevel = TypeConverter::OmxHevcLevelToInnerLevel(static_cast<CodecHevcLevel>(maxLevel));
239 }
240 if (innerProfile.has_value() && innerLevel.has_value() && innerLevel.value() >= 0) {
241 userCap.profiles.emplace_back(innerProfile.value());
242 vector<int32_t> allLevel(innerLevel.value() + 1);
243 std::iota(allLevel.begin(), allLevel.end(), 0);
244 userCap.profileLevelsMap[innerProfile.value()] = allLevel;
245 LOGI("role %d support (inner) profile %d and level up to %d",
246 hdiCap.role, innerProfile.value(), innerLevel.value());
247 }
248
249 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_VVC) {
250 optional<int32_t> innerProfileVvc;
251 optional<int32_t> innerLevelVvc;
252 innerProfileVvc = TypeConverter::OmxVvcProfileToInnerProfile(static_cast<CodecVvcProfile>(profile));
253 innerLevelVvc = TypeConverter::OmxVvcLevelToInnerLevel(static_cast<CodecVvcLevel>(maxLevel));
254 if (innerProfileVvc.has_value() && innerLevelVvc.has_value() && innerLevelVvc.value() >= 0) {
255 userCap.profiles.emplace_back(innerProfileVvc.value());
256 optional<vector<int32_t>> allLevel =
257 TypeConverter::InnerVvcMaxLevelToAllLevels(static_cast<VVCLevel>(innerLevelVvc.value()));
258 userCap.profileLevelsMap[innerProfileVvc.value()] = allLevel.value();
259 LOGI("role %d support (inner) profile %d and level up to %d",
260 hdiCap.role, innerProfileVvc.value(), innerLevelVvc.value());
261 }
262 }
263 }
264 }
265
GetSupportedFeatureParam(const CodecVideoPortCap & hdiVideoCap,CapabilityData & userCap)266 void HCodecList::GetSupportedFeatureParam(const CodecVideoPortCap& hdiVideoCap,
267 CapabilityData& userCap)
268 {
269 if (hdiVideoCap.isSupportLowLatency) {
270 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_LOW_LATENCY)] = Format();
271 }
272 if (hdiVideoCap.isSupportTSVC) {
273 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_TEMPORAL_SCALABILITY)] = Format();
274 }
275 if (hdiVideoCap.isSupportLTR) {
276 Format format;
277 int32_t maxLTRFrameNum = hdiVideoCap.maxLTRFrameNum;
278 if (maxLTRFrameNum >= 0) {
279 format.PutIntValue(OHOS::Media::Tag::FEATURE_PROPERTY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, maxLTRFrameNum);
280 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_LONG_TERM_REFERENCE)] = format;
281 }
282 }
283 if (hdiVideoCap.isSupportWaterMark) {
284 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_WATERMARK)] = Format();
285 }
286 }
287 } // namespace OHOS::MediaAVCodec