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 <algorithm>
20 #include "syspara/parameters.h"
21 #include "hdf_base.h"
22 #include "iservmgr_hdi.h"
23 #include "hcodec_log.h"
24 #include "type_converter.h"
25 #include "avcodec_info.h"
26 #include "meta/meta.h"
27
28 namespace OHOS::MediaAVCodec {
29 using namespace std;
30 using namespace CodecHDI;
31 using namespace OHOS::HDI::ServiceManager::V1_0;
32
33 static mutex g_mtx;
34 static sptr<ICodecComponentManager> g_compMgrIpc;
35 static sptr<ICodecComponentManager> g_compMgrPassthru;
36
37 class Listener : public ServStatListenerStub {
38 public:
OnReceive(const ServiceStatus & status)39 void OnReceive(const ServiceStatus &status) override
40 {
41 if (status.serviceName == "codec_component_manager_service" && status.status == SERVIE_STATUS_STOP) {
42 LOGW("codec_component_manager_service died");
43 lock_guard<mutex> lk(g_mtx);
44 g_compMgrIpc = nullptr;
45 }
46 }
47 };
48
DecideMode(bool supportPassthrough,bool isSecure)49 static bool DecideMode(bool supportPassthrough, bool isSecure)
50 {
51 #ifdef BUILD_ENG_VERSION
52 string mode = OHOS::system::GetParameter("hcodec.usePassthrough", "");
53 if (mode == "1") {
54 LOGI("force passthrough");
55 return true;
56 } else if (mode == "0") {
57 LOGI("force ipc");
58 return false;
59 } else if (mode == "-1") {
60 if (isSecure) {
61 LOGI("secure, supportPassthrough = %d", supportPassthrough);
62 return supportPassthrough;
63 } else {
64 static int g_cnt = 0;
65 bool passthrough = (g_cnt++ % 3 == 0);
66 LOGI("g_cnt=%d, %s mode", g_cnt, passthrough ? "passthrough" : "ipc");
67 return passthrough;
68 }
69 }
70 #endif
71 LOGD("supportPassthrough = %d", supportPassthrough);
72 return supportPassthrough;
73 }
74
GetManager(bool getCap,bool supportPassthrough,bool isSecure)75 sptr<ICodecComponentManager> GetManager(bool getCap, bool supportPassthrough, bool isSecure)
76 {
77 lock_guard<mutex> lk(g_mtx);
78 bool isPassthrough = getCap ? true : DecideMode(supportPassthrough, isSecure);
79 sptr<ICodecComponentManager>& mng = (isPassthrough ? g_compMgrPassthru : g_compMgrIpc);
80 if (mng) {
81 return mng;
82 }
83 LOGI("need to get ICodecComponentManager");
84 if (!isPassthrough) {
85 sptr<IServiceManager> serviceMng = IServiceManager::Get();
86 if (serviceMng) {
87 serviceMng->RegisterServiceStatusListener(new Listener(), DEVICE_CLASS_DEFAULT);
88 }
89 }
90 mng = ICodecComponentManager::Get(isPassthrough);
91 return mng;
92 }
93
GetCapList()94 vector<CodecCompCapability> GetCapList()
95 {
96 sptr<ICodecComponentManager> mnger = GetManager(true);
97 if (mnger == nullptr) {
98 LOGE("failed to create codec component manager");
99 return {};
100 }
101 int32_t compCnt = 0;
102 int32_t ret = mnger->GetComponentNum(compCnt);
103 if (ret != HDF_SUCCESS || compCnt <= 0) {
104 LOGE("failed to query component number, ret=%d", ret);
105 return {};
106 }
107 std::vector<CodecCompCapability> capList(compCnt);
108 ret = mnger->GetComponentCapabilityList(capList, compCnt);
109 if (ret != HDF_SUCCESS) {
110 LOGE("failed to query component capability list, ret=%d", ret);
111 return {};
112 }
113 if (capList.empty()) {
114 LOGE("GetComponentCapabilityList return empty");
115 } else {
116 LOGD("GetComponentCapabilityList return %zu components", capList.size());
117 }
118 return capList;
119 }
120
GetCapabilityList(std::vector<CapabilityData> & caps)121 int32_t HCodecList::GetCapabilityList(std::vector<CapabilityData>& caps)
122 {
123 caps.clear();
124 vector<CodecCompCapability> capList = GetCapList();
125 for (const CodecCompCapability& one : capList) {
126 if (IsSupportedVideoCodec(one)) {
127 caps.emplace_back(HdiCapToUserCap(one));
128 }
129 }
130 return AVCS_ERR_OK;
131 }
132
FindFeature(const vector<VideoFeature> & features,const enum VideoFeatureKey & key)133 VideoFeature HCodecList::FindFeature(const vector<VideoFeature> &features, const enum VideoFeatureKey &key)
134 {
135 auto it = find_if(features.begin(), features.end(),
136 [&key](const VideoFeature& feature) { return feature.key == key; });
137 if (it == features.end()) {
138 return {key, false, {}};
139 }
140 return *it;
141 }
142
IsSupportedVideoCodec(const CodecCompCapability & hdiCap)143 bool HCodecList::IsSupportedVideoCodec(const CodecCompCapability &hdiCap)
144 {
145 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC || hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC ||
146 hdiCap.role == MEDIA_ROLETYPE_VIDEO_VVC) {
147 return true;
148 }
149 return false;
150 }
151
HdiCapToUserCap(const CodecCompCapability & hdiCap)152 CapabilityData HCodecList::HdiCapToUserCap(const CodecCompCapability &hdiCap)
153 {
154 constexpr int32_t MAX_ENCODE_QUALITY = 100;
155 constexpr int32_t MAX_ENCODE_SQRFACTOR = 51;
156 const CodecVideoPortCap& hdiVideoCap = hdiCap.port.video;
157 CapabilityData userCap;
158 userCap.codecName = hdiCap.compName;
159 userCap.codecType = TypeConverter::HdiCodecTypeToInnerCodecType(hdiCap.type).value_or(AVCODEC_TYPE_NONE);
160 userCap.mimeType = TypeConverter::HdiRoleToMime(hdiCap.role);
161 userCap.isVendor = true;
162 userCap.maxInstance = hdiCap.maxInst;
163 userCap.bitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
164 userCap.alignment = {hdiVideoCap.whAlignment.widthAlignment, hdiVideoCap.whAlignment.heightAlignment};
165 userCap.width = {hdiVideoCap.minSize.width, hdiVideoCap.maxSize.width};
166 userCap.height = {hdiVideoCap.minSize.height, hdiVideoCap.maxSize.height};
167 userCap.frameRate = {hdiVideoCap.frameRate.min, hdiVideoCap.frameRate.max};
168 userCap.blockPerFrame = {hdiVideoCap.blockCount.min, hdiVideoCap.blockCount.max};
169 userCap.blockPerSecond = {hdiVideoCap.blocksPerSecond.min, hdiVideoCap.blocksPerSecond.max};
170 userCap.blockSize = {hdiVideoCap.blockSize.width, hdiVideoCap.blockSize.height};
171 userCap.pixFormat = GetSupportedFormat(hdiVideoCap);
172 userCap.bitrateMode = GetSupportedBitrateMode(hdiVideoCap);
173 if (IsSupportSQR(userCap.bitrateMode)) {
174 userCap.maxBitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
175 userCap.sqrFactor = {0, MAX_ENCODE_SQRFACTOR};
176 }
177 GetCodecProfileLevels(hdiCap, userCap);
178 userCap.measuredFrameRate = GetMeasuredFrameRate(hdiVideoCap);
179 userCap.supportSwapWidthHeight = hdiCap.canSwapWidthHeight;
180 userCap.encodeQuality = {0, MAX_ENCODE_QUALITY};
181 LOGI("----- codecName: %s -----", userCap.codecName.c_str());
182 LOGI("codecType: %d, mimeType: %s, maxInstance %d",
183 userCap.codecType, userCap.mimeType.c_str(), userCap.maxInstance);
184 LOGI("bitrate: [%d, %d], alignment: [%d x %d]",
185 userCap.bitrate.minVal, userCap.bitrate.maxVal, userCap.alignment.width, userCap.alignment.height);
186 LOGI("width: [%d, %d], height: [%d, %d]",
187 userCap.width.minVal, userCap.width.maxVal, userCap.height.minVal, userCap.height.maxVal);
188 LOGI("frameRate: [%d, %d], blockSize: [%d x %d]",
189 userCap.frameRate.minVal, userCap.frameRate.maxVal, userCap.blockSize.width, userCap.blockSize.height);
190 LOGI("blockPerFrame: [%d, %d], blockPerSecond: [%d, %d]",
191 userCap.blockPerFrame.minVal, userCap.blockPerFrame.maxVal,
192 userCap.blockPerSecond.minVal, userCap.blockPerSecond.maxVal);
193 GetSupportedFeatureParam(hdiVideoCap, userCap);
194 GetSupportedLtrFeatureParam(hdiVideoCap, userCap);
195 GetSupportedBFrameFeatureParam(hdiVideoCap, userCap);
196 LOGI("isSupportPassthrough: %d", FindFeature(hdiVideoCap.features, VIDEO_FEATURE_PASS_THROUGH).support);
197 return userCap;
198 }
199
GetSupportedBitrateMode(const CodecVideoPortCap & hdiVideoCap)200 vector<int32_t> HCodecList::GetSupportedBitrateMode(const CodecVideoPortCap& hdiVideoCap)
201 {
202 vector<int32_t> vec;
203 for (BitRateMode mode : hdiVideoCap.bitRatemode) {
204 OMX_VIDEO_CONTROLRATETYPE omxMode = static_cast<OMX_VIDEO_CONTROLRATETYPE>(mode);
205 optional<VideoEncodeBitrateMode> innerMode = TypeConverter::OmxBitrateModeToInnerMode(omxMode);
206 if (innerMode.has_value()) {
207 vec.push_back(innerMode.value());
208 LOGI("support (inner) bitRateMode %d", innerMode.value());
209 }
210 }
211 return vec;
212 }
213
IsSupportSQR(const vector<int32_t> & supportBitrateMode)214 bool HCodecList::IsSupportSQR(const vector<int32_t>& supportBitrateMode)
215 {
216 VideoEncodeBitrateMode innerMode = SQR;
217 auto it = std::find(supportBitrateMode.begin(), supportBitrateMode.end(), static_cast<int32_t>(innerMode));
218 if (it != supportBitrateMode.end()) {
219 LOGI("support SQR bitRateMode!");
220 return true;
221 }
222 return false;
223 }
224
GetSupportedFormat(const CodecVideoPortCap & hdiVideoCap)225 vector<int32_t> HCodecList::GetSupportedFormat(const CodecVideoPortCap& hdiVideoCap)
226 {
227 vector<int32_t> vec;
228 for (int32_t fmt : hdiVideoCap.supportPixFmts) {
229 optional<VideoPixelFormat> innerFmt =
230 TypeConverter::DisplayFmtToInnerFmt(static_cast<GraphicPixelFormat>(fmt));
231 if (innerFmt.has_value() &&
232 find(vec.begin(), vec.end(), static_cast<int32_t>(innerFmt.value())) == vec.end()) {
233 vec.push_back(static_cast<int32_t>(innerFmt.value()));
234 }
235 }
236 return vec;
237 }
238
GetMeasuredFrameRate(const CodecVideoPortCap & hdiVideoCap)239 map<ImgSize, Range> HCodecList::GetMeasuredFrameRate(const CodecVideoPortCap& hdiVideoCap)
240 {
241 enum MeasureStep {
242 WIDTH = 0,
243 HEIGHT = 1,
244 MIN_RATE = 2,
245 MAX_RATE = 3,
246 STEP_BUTT = 4
247 };
248 map<ImgSize, Range> userRateMap;
249 for (size_t index = 0; index < hdiVideoCap.measuredFrameRate.size(); index += STEP_BUTT) {
250 if (hdiVideoCap.measuredFrameRate[index] <= 0) {
251 continue;
252 }
253 ImgSize imageSize(hdiVideoCap.measuredFrameRate[index + WIDTH], hdiVideoCap.measuredFrameRate[index + HEIGHT]);
254 Range range(hdiVideoCap.measuredFrameRate[index + MIN_RATE], hdiVideoCap.measuredFrameRate[index + MAX_RATE]);
255 userRateMap[imageSize] = range;
256 }
257 return userRateMap;
258 }
259
GetCodecProfileLevels(const CodecCompCapability & hdiCap,CapabilityData & userCap)260 void HCodecList::GetCodecProfileLevels(const CodecCompCapability& hdiCap, CapabilityData& userCap)
261 {
262 for (size_t i = 0; i + 1 < hdiCap.supportProfiles.size(); i += 2) { // 2 means profile & level pair
263 int32_t profile = hdiCap.supportProfiles[i];
264 int32_t maxLevel = hdiCap.supportProfiles[i + 1];
265 optional<int32_t> innerProfile;
266 optional<int32_t> innerLevel;
267 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC) {
268 innerProfile = TypeConverter::OmxAvcProfileToInnerProfile(static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile));
269 innerLevel = TypeConverter::OmxAvcLevelToInnerLevel(static_cast<OMX_VIDEO_AVCLEVELTYPE>(maxLevel));
270 } else if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC) {
271 innerProfile = TypeConverter::OmxHevcProfileToInnerProfile(static_cast<CodecHevcProfile>(profile));
272 innerLevel = TypeConverter::OmxHevcLevelToInnerLevel(static_cast<CodecHevcLevel>(maxLevel));
273 }
274 if (innerProfile.has_value() && innerLevel.has_value() && innerLevel.value() >= 0) {
275 userCap.profiles.emplace_back(innerProfile.value());
276 vector<int32_t> allLevel(innerLevel.value() + 1);
277 std::iota(allLevel.begin(), allLevel.end(), 0);
278 userCap.profileLevelsMap[innerProfile.value()] = allLevel;
279 LOGI("role %d support (inner) profile %d and level up to %d",
280 hdiCap.role, innerProfile.value(), innerLevel.value());
281 }
282
283 if (hdiCap.role != MEDIA_ROLETYPE_VIDEO_VVC) {
284 continue;
285 }
286 optional<int32_t> innerProfileVvc;
287 optional<int32_t> innerLevelVvc;
288 innerProfileVvc = TypeConverter::OmxVvcProfileToInnerProfile(static_cast<CodecVvcProfile>(profile));
289 innerLevelVvc = TypeConverter::OmxVvcLevelToInnerLevel(static_cast<CodecVvcLevel>(maxLevel));
290 if (innerProfileVvc.has_value() && innerLevelVvc.has_value() && innerLevelVvc.value() >= 0) {
291 userCap.profiles.emplace_back(innerProfileVvc.value());
292 optional<vector<int32_t>> allLevel =
293 TypeConverter::InnerVvcMaxLevelToAllLevels(static_cast<VVCLevel>(innerLevelVvc.value()));
294 if (allLevel.has_value()) {
295 userCap.profileLevelsMap[innerProfileVvc.value()] = allLevel.value();
296 }
297 LOGI("role %d support (inner) profile %d and level up to %d",
298 hdiCap.role, innerProfileVvc.value(), innerLevelVvc.value());
299 }
300 }
301 }
302
GetSupportedFeatureParam(const CodecVideoPortCap & hdiVideoCap,CapabilityData & userCap)303 void HCodecList::GetSupportedFeatureParam(const CodecVideoPortCap& hdiVideoCap,
304 CapabilityData& userCap)
305 {
306 // convert CodecHDI to AVCodec Feature
307 map<CodecHDI::VideoFeatureKey, pair<AVCapabilityFeature, string>> featureConvertMap = {
308 { CodecHDI::VIDEO_FEATURE_LOW_LATENCY,
309 {AVCapabilityFeature::VIDEO_LOW_LATENCY, "isSupportLowLatency"}
310 },
311 { CodecHDI::VIDEO_FEATURE_TSVC,
312 {AVCapabilityFeature::VIDEO_ENCODER_TEMPORAL_SCALABILITY, "isSupportTSVC"}
313 },
314 { CodecHDI::VIDEO_FEATURE_WATERMARK,
315 {AVCapabilityFeature::VIDEO_WATERMARK, "isSupportWaterMark"}
316 },
317 { CodecHDI::VIDEO_FEATURE_SEEK_WITHOUT_FLUSH,
318 {AVCapabilityFeature::VIDEO_DECODER_SEEK_WITHOUT_FLUSH, "isSupportSeekWithoutFlush"}
319 },
320 { CodecHDI::VIDEO_FEATURE_QP_MAP,
321 {AVCapabilityFeature::VIDEO_ENCODER_QP_MAP, "isSupportQPMap"}
322 },
323 };
324
325 for (auto featureInfo: featureConvertMap) {
326 VideoFeature feature = FindFeature(hdiVideoCap.features, featureInfo.first);
327 if (feature.support) {
328 userCap.featuresMap[static_cast<int32_t>(featureInfo.second.first)] = Format();
329 }
330 LOGI("%s: %d", featureInfo.second.second.c_str(), feature.support);
331 }
332 }
333
GetSupportedLtrFeatureParam(const CodecVideoPortCap & hdiVideoCap,CapabilityData & userCap)334 void HCodecList::GetSupportedLtrFeatureParam(const CodecVideoPortCap& hdiVideoCap,
335 CapabilityData& userCap)
336 {
337 VideoFeature feature = FindFeature(hdiVideoCap.features, VIDEO_FEATURE_LTR);
338 if (!feature.support || feature.extendInfo.empty()) {
339 LOGI("isSupportLTR: 0");
340 return;
341 }
342 Format format;
343 int32_t maxLTRFrameNum = feature.extendInfo[0];
344 if (maxLTRFrameNum >= 0) {
345 format.PutIntValue(OHOS::Media::Tag::FEATURE_PROPERTY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, maxLTRFrameNum);
346 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_LONG_TERM_REFERENCE)] = format;
347 LOGI("isSupportLTR: 1, maxLTRFrameNum: %d", maxLTRFrameNum);
348 return;
349 }
350 LOGI("isSupportLTR: 0");
351 }
352
GetSupportedBFrameFeatureParam(const CodecVideoPortCap & hdiVideoCap,CapabilityData & userCap)353 void HCodecList::GetSupportedBFrameFeatureParam(const CodecVideoPortCap& hdiVideoCap,
354 CapabilityData& userCap)
355 {
356 VideoFeature feature = FindFeature(hdiVideoCap.features, VIDEO_FEATURE_ENCODE_B_FRAME);
357 if (!feature.support || feature.extendInfo.empty()) {
358 LOGI("isSupportBFrame: 0");
359 return;
360 }
361 Format format;
362 int32_t maxBFrameCount = feature.extendInfo[0];
363 if (maxBFrameCount > 0) {
364 format.PutIntValue(OHOS::Media::Tag::VIDEO_ENCODER_MAX_B_FRAME, maxBFrameCount);
365 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_B_FRAME)] = format;
366 LOGI("isSupportBFrame: 1, maxSupportBFrameCnt: %u", maxBFrameCount);
367 return;
368 }
369 LOGI("isSupportBFrame: 0");
370 return;
371 }
372 } // namespace OHOS::MediaAVCodec