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