• 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 <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