• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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