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
DecideMode(bool supportPassthrough,bool isSecure)48 static bool DecideMode(bool supportPassthrough, bool isSecure)
49 {
50 #ifdef BUILD_ENG_VERSION
51 string mode = OHOS::system::GetParameter("persist.hcodec.usePassthrough", "");
52 if (mode == "1") {
53 LOGI("force passthrough");
54 return true;
55 } else if (mode == "0") {
56 LOGI("force ipc");
57 return false;
58 } else if (mode == "-1") {
59 if (isSecure) {
60 LOGI("secure, supportPassthrough = %d", supportPassthrough);
61 return supportPassthrough;
62 } else {
63 static int g_cnt = 0;
64 bool passthrough = (g_cnt++ % 3 == 0);
65 LOGI("g_cnt=%d, %s mode", g_cnt, passthrough ? "passthrough" : "ipc");
66 return passthrough;
67 }
68 }
69 #endif
70 LOGD("supportPassthrough = %d", supportPassthrough);
71 return supportPassthrough;
72 }
73
GetManager(bool getCap,bool supportPassthrough,bool isSecure)74 sptr<ICodecComponentManager> GetManager(bool getCap, bool supportPassthrough, bool isSecure)
75 {
76 lock_guard<mutex> lk(g_mtx);
77 bool isPassthrough = getCap ? true : DecideMode(supportPassthrough, isSecure);
78 sptr<ICodecComponentManager>& mng = (isPassthrough ? g_compMgrPassthru : g_compMgrIpc);
79 if (mng) {
80 return mng;
81 }
82 LOGI("need to get ICodecComponentManager");
83 if (!isPassthrough) {
84 sptr<IServiceManager> serviceMng = IServiceManager::Get();
85 if (serviceMng) {
86 serviceMng->RegisterServiceStatusListener(new Listener(), DEVICE_CLASS_DEFAULT);
87 }
88 }
89 mng = ICodecComponentManager::Get(isPassthrough);
90 return mng;
91 }
92
GetCapList()93 vector<CodecCompCapability> GetCapList()
94 {
95 sptr<ICodecComponentManager> mnger = GetManager(true);
96 if (mnger == nullptr) {
97 LOGE("failed to create codec component manager");
98 return {};
99 }
100 int32_t compCnt = 0;
101 int32_t ret = mnger->GetComponentNum(compCnt);
102 if (ret != HDF_SUCCESS || compCnt <= 0) {
103 LOGE("failed to query component number, ret=%d", ret);
104 return {};
105 }
106 std::vector<CodecCompCapability> capList(compCnt);
107 ret = mnger->GetComponentCapabilityList(capList, compCnt);
108 if (ret != HDF_SUCCESS) {
109 LOGE("failed to query component capability list, ret=%d", ret);
110 return {};
111 }
112 if (capList.empty()) {
113 LOGE("GetComponentCapabilityList return empty");
114 } else {
115 LOGD("GetComponentCapabilityList return %zu components", capList.size());
116 }
117 return capList;
118 }
119
GetCapabilityList(std::vector<CapabilityData> & caps)120 int32_t HCodecList::GetCapabilityList(std::vector<CapabilityData>& caps)
121 {
122 caps.clear();
123 vector<CodecCompCapability> capList = GetCapList();
124 for (const CodecCompCapability& one : capList) {
125 if (IsSupportedVideoCodec(one)) {
126 caps.emplace_back(HdiCapToUserCap(one));
127 }
128 }
129 return AVCS_ERR_OK;
130 }
131
IsSupportedVideoCodec(const CodecCompCapability & hdiCap)132 bool HCodecList::IsSupportedVideoCodec(const CodecCompCapability &hdiCap)
133 {
134 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC || hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC ||
135 hdiCap.role == MEDIA_ROLETYPE_VIDEO_VVC) {
136 return true;
137 }
138 return false;
139 }
140
HdiCapToUserCap(const CodecCompCapability & hdiCap)141 CapabilityData HCodecList::HdiCapToUserCap(const CodecCompCapability &hdiCap)
142 {
143 constexpr int32_t MAX_ENCODE_QUALITY = 100;
144 constexpr int32_t MAX_ENCODE_SQRFACTOR = 51;
145 const CodecVideoPortCap& hdiVideoCap = hdiCap.port.video;
146 CapabilityData userCap;
147 userCap.codecName = hdiCap.compName;
148 userCap.codecType = TypeConverter::HdiCodecTypeToInnerCodecType(hdiCap.type).value_or(AVCODEC_TYPE_NONE);
149 userCap.mimeType = TypeConverter::HdiRoleToMime(hdiCap.role);
150 userCap.isVendor = true;
151 userCap.maxInstance = hdiCap.maxInst;
152 userCap.bitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
153 userCap.alignment = {hdiVideoCap.whAlignment.widthAlignment, hdiVideoCap.whAlignment.heightAlignment};
154 userCap.width = {hdiVideoCap.minSize.width, hdiVideoCap.maxSize.width};
155 userCap.height = {hdiVideoCap.minSize.height, hdiVideoCap.maxSize.height};
156 userCap.frameRate = {hdiVideoCap.frameRate.min, hdiVideoCap.frameRate.max};
157 userCap.blockPerFrame = {hdiVideoCap.blockCount.min, hdiVideoCap.blockCount.max};
158 userCap.blockPerSecond = {hdiVideoCap.blocksPerSecond.min, hdiVideoCap.blocksPerSecond.max};
159 userCap.blockSize = {hdiVideoCap.blockSize.width, hdiVideoCap.blockSize.height};
160 userCap.pixFormat = GetSupportedFormat(hdiVideoCap);
161 userCap.bitrateMode = GetSupportedBitrateMode(hdiVideoCap);
162 if (IsSupportSQR(userCap.bitrateMode)) {
163 userCap.maxBitrate = {hdiCap.bitRate.min, hdiCap.bitRate.max};
164 userCap.sqrFactor = {0, MAX_ENCODE_SQRFACTOR};
165 }
166 GetCodecProfileLevels(hdiCap, userCap);
167 userCap.measuredFrameRate = GetMeasuredFrameRate(hdiVideoCap);
168 userCap.supportSwapWidthHeight = hdiCap.canSwapWidthHeight;
169 userCap.encodeQuality = {0, MAX_ENCODE_QUALITY};
170 GetSupportedFeatureParam(hdiVideoCap, userCap);
171 LOGI("----- codecName: %s -----", userCap.codecName.c_str());
172 LOGI("codecType: %d, mimeType: %s, maxInstance %d",
173 userCap.codecType, userCap.mimeType.c_str(), userCap.maxInstance);
174 LOGI("bitrate: [%d, %d], alignment: [%d x %d]",
175 userCap.bitrate.minVal, userCap.bitrate.maxVal, userCap.alignment.width, userCap.alignment.height);
176 LOGI("width: [%d, %d], height: [%d, %d]",
177 userCap.width.minVal, userCap.width.maxVal, userCap.height.minVal, userCap.height.maxVal);
178 LOGI("frameRate: [%d, %d], blockSize: [%d x %d]",
179 userCap.frameRate.minVal, userCap.frameRate.maxVal, userCap.blockSize.width, userCap.blockSize.height);
180 LOGI("blockPerFrame: [%d, %d], blockPerSecond: [%d, %d]",
181 userCap.blockPerFrame.minVal, userCap.blockPerFrame.maxVal,
182 userCap.blockPerSecond.minVal, userCap.blockPerSecond.maxVal);
183 LOGI("isSupportPassthrough: %d", hdiVideoCap.isSupportPassthrough);
184 LOGI("isSupportWaterMark: %d, isSupportLowLatency: %d, isSupportTSVC: %d, isSupportLTR %d and maxLTRFrameNum %d",
185 hdiVideoCap.isSupportWaterMark, hdiVideoCap.isSupportLowLatency, hdiVideoCap.isSupportTSVC,
186 hdiVideoCap.isSupportLTR, hdiVideoCap.maxLTRFrameNum);
187 return userCap;
188 }
189
GetSupportedBitrateMode(const CodecVideoPortCap & hdiVideoCap)190 vector<int32_t> HCodecList::GetSupportedBitrateMode(const CodecVideoPortCap& hdiVideoCap)
191 {
192 vector<int32_t> vec;
193 for (BitRateMode mode : hdiVideoCap.bitRatemode) {
194 OMX_VIDEO_CONTROLRATETYPE omxMode = static_cast<OMX_VIDEO_CONTROLRATETYPE>(mode);
195 optional<VideoEncodeBitrateMode> innerMode = TypeConverter::OmxBitrateModeToInnerMode(omxMode);
196 if (innerMode.has_value()) {
197 vec.push_back(innerMode.value());
198 LOGI("support (inner) bitRateMode %d", innerMode.value());
199 }
200 }
201 return vec;
202 }
203
IsSupportSQR(const vector<int32_t> & supportBitrateMode)204 bool HCodecList::IsSupportSQR(const vector<int32_t>& supportBitrateMode)
205 {
206 VideoEncodeBitrateMode innerMode = SQR;
207 auto it = std::find(supportBitrateMode.begin(), supportBitrateMode.end(), static_cast<int32_t>(innerMode));
208 if (it != supportBitrateMode.end()) {
209 LOGI("support SQR bitRateMode!");
210 return true;
211 }
212 return false;
213 }
214
GetSupportedFormat(const CodecVideoPortCap & hdiVideoCap)215 vector<int32_t> HCodecList::GetSupportedFormat(const CodecVideoPortCap& hdiVideoCap)
216 {
217 vector<int32_t> vec;
218 for (int32_t fmt : hdiVideoCap.supportPixFmts) {
219 optional<VideoPixelFormat> innerFmt =
220 TypeConverter::DisplayFmtToInnerFmt(static_cast<GraphicPixelFormat>(fmt));
221 if (innerFmt.has_value()) {
222 vec.push_back(static_cast<int32_t>(innerFmt.value()));
223 }
224 }
225 return vec;
226 }
227
GetMeasuredFrameRate(const CodecVideoPortCap & hdiVideoCap)228 map<ImgSize, Range> HCodecList::GetMeasuredFrameRate(const CodecVideoPortCap& hdiVideoCap)
229 {
230 enum MeasureStep {
231 WIDTH = 0,
232 HEIGHT = 1,
233 MIN_RATE = 2,
234 MAX_RATE = 3,
235 STEP_BUTT = 4
236 };
237 map<ImgSize, Range> userRateMap;
238 for (size_t index = 0; index < hdiVideoCap.measuredFrameRate.size(); index += STEP_BUTT) {
239 if (hdiVideoCap.measuredFrameRate[index] <= 0) {
240 continue;
241 }
242 ImgSize imageSize(hdiVideoCap.measuredFrameRate[index + WIDTH], hdiVideoCap.measuredFrameRate[index + HEIGHT]);
243 Range range(hdiVideoCap.measuredFrameRate[index + MIN_RATE], hdiVideoCap.measuredFrameRate[index + MAX_RATE]);
244 userRateMap[imageSize] = range;
245 }
246 return userRateMap;
247 }
248
GetCodecProfileLevels(const CodecCompCapability & hdiCap,CapabilityData & userCap)249 void HCodecList::GetCodecProfileLevels(const CodecCompCapability& hdiCap, CapabilityData& userCap)
250 {
251 for (size_t i = 0; i + 1 < hdiCap.supportProfiles.size(); i += 2) { // 2 means profile & level pair
252 int32_t profile = hdiCap.supportProfiles[i];
253 int32_t maxLevel = hdiCap.supportProfiles[i + 1];
254 optional<int32_t> innerProfile;
255 optional<int32_t> innerLevel;
256 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_AVC) {
257 innerProfile = TypeConverter::OmxAvcProfileToInnerProfile(static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile));
258 innerLevel = TypeConverter::OmxAvcLevelToInnerLevel(static_cast<OMX_VIDEO_AVCLEVELTYPE>(maxLevel));
259 } else if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_HEVC) {
260 innerProfile = TypeConverter::OmxHevcProfileToInnerProfile(static_cast<CodecHevcProfile>(profile));
261 innerLevel = TypeConverter::OmxHevcLevelToInnerLevel(static_cast<CodecHevcLevel>(maxLevel));
262 }
263 if (innerProfile.has_value() && innerLevel.has_value() && innerLevel.value() >= 0) {
264 userCap.profiles.emplace_back(innerProfile.value());
265 vector<int32_t> allLevel(innerLevel.value() + 1);
266 std::iota(allLevel.begin(), allLevel.end(), 0);
267 userCap.profileLevelsMap[innerProfile.value()] = allLevel;
268 LOGI("role %d support (inner) profile %d and level up to %d",
269 hdiCap.role, innerProfile.value(), innerLevel.value());
270 }
271
272 if (hdiCap.role == MEDIA_ROLETYPE_VIDEO_VVC) {
273 optional<int32_t> innerProfileVvc;
274 optional<int32_t> innerLevelVvc;
275 innerProfileVvc = TypeConverter::OmxVvcProfileToInnerProfile(static_cast<CodecVvcProfile>(profile));
276 innerLevelVvc = TypeConverter::OmxVvcLevelToInnerLevel(static_cast<CodecVvcLevel>(maxLevel));
277 if (innerProfileVvc.has_value() && innerLevelVvc.has_value() && innerLevelVvc.value() >= 0) {
278 userCap.profiles.emplace_back(innerProfileVvc.value());
279 optional<vector<int32_t>> allLevel =
280 TypeConverter::InnerVvcMaxLevelToAllLevels(static_cast<VVCLevel>(innerLevelVvc.value()));
281 userCap.profileLevelsMap[innerProfileVvc.value()] = allLevel.value();
282 LOGI("role %d support (inner) profile %d and level up to %d",
283 hdiCap.role, innerProfileVvc.value(), innerLevelVvc.value());
284 }
285 }
286 }
287 }
288
GetSupportedFeatureParam(const CodecVideoPortCap & hdiVideoCap,CapabilityData & userCap)289 void HCodecList::GetSupportedFeatureParam(const CodecVideoPortCap& hdiVideoCap,
290 CapabilityData& userCap)
291 {
292 if (hdiVideoCap.isSupportLowLatency) {
293 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_LOW_LATENCY)] = Format();
294 }
295 if (hdiVideoCap.isSupportTSVC) {
296 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_TEMPORAL_SCALABILITY)] = Format();
297 }
298 if (hdiVideoCap.isSupportLTR) {
299 Format format;
300 int32_t maxLTRFrameNum = hdiVideoCap.maxLTRFrameNum;
301 if (maxLTRFrameNum >= 0) {
302 format.PutIntValue(OHOS::Media::Tag::FEATURE_PROPERTY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, maxLTRFrameNum);
303 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_LONG_TERM_REFERENCE)] = format;
304 }
305 }
306 if (hdiVideoCap.isSupportWaterMark) {
307 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_WATERMARK)] = Format();
308 }
309 if (hdiVideoCap.isSupportSeekWithoutFlush) {
310 userCap.featuresMap[static_cast<int32_t>(AVCapabilityFeature::VIDEO_DECODER_SEEK_WITHOUT_FLUSH)] = Format();
311 }
312 }
313 } // namespace OHOS::MediaAVCodec