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 "codeclist_core.h"
17 #include <cmath> // fabs
18 #include "avcodec_errors.h"
19 #include "avcodec_log.h"
20 #include "codec_ability_singleton.h"
21 
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "CodecListCore"};
24 constexpr float EPSINON = 0.0001;
25 } // namespace
26 
27 namespace OHOS {
28 namespace MediaAVCodec {
29 using namespace Media;
CodecListCore()30 CodecListCore::CodecListCore()
31 {
32     AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
33 }
34 
~CodecListCore()35 CodecListCore::~CodecListCore()
36 {
37     AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
38 }
39 
CheckBitrate(const Format & format,const CapabilityData & data)40 bool CodecListCore::CheckBitrate(const Format &format, const CapabilityData &data)
41 {
42     int64_t targetBitrate;
43     if (!format.ContainKey("bitrate")) {
44         AVCODEC_LOGD("The bitrate of the format are not specified");
45         return true;
46     }
47     (void)format.GetLongValue("bitrate", targetBitrate);
48     if (data.bitrate.minVal > targetBitrate || data.bitrate.maxVal < targetBitrate) {
49         return false;
50     }
51     return true;
52 }
53 
CheckVideoResolution(const Format & format,const CapabilityData & data)54 bool CodecListCore::CheckVideoResolution(const Format &format, const CapabilityData &data)
55 {
56     int32_t targetWidth;
57     int32_t targetHeight;
58     if ((!format.ContainKey("width")) || (!format.ContainKey("height"))) {
59         AVCODEC_LOGD("The width and height of the format are not specified");
60         return true;
61     }
62     (void)format.GetIntValue("width", targetWidth);
63     (void)format.GetIntValue("height", targetHeight);
64     if (data.width.minVal > targetWidth || data.width.maxVal < targetWidth || data.height.minVal > targetHeight ||
65         data.height.maxVal < targetHeight) {
66         return false;
67     }
68     return true;
69 }
70 
CheckVideoPixelFormat(const Format & format,const CapabilityData & data)71 bool CodecListCore::CheckVideoPixelFormat(const Format &format, const CapabilityData &data)
72 {
73     int32_t targetPixelFormat;
74     if (!format.ContainKey("pixel_format")) {
75         AVCODEC_LOGD("The pixel_format of the format are not specified");
76         return true;
77     }
78     (void)format.GetIntValue("pixel_format", targetPixelFormat);
79     if (find(data.pixFormat.begin(), data.pixFormat.end(), targetPixelFormat) == data.pixFormat.end()) {
80         return false;
81     }
82     return true;
83 }
84 
CheckVideoFrameRate(const Format & format,const CapabilityData & data)85 bool CodecListCore::CheckVideoFrameRate(const Format &format, const CapabilityData &data)
86 {
87     if (!format.ContainKey("frame_rate")) {
88         AVCODEC_LOGD("The frame_rate of the format are not specified");
89         return true;
90     }
91 
92     switch (format.GetValueType(std::string_view("frame_rate"))) {
93         case FORMAT_TYPE_INT32: {
94             int32_t targetFrameRateInt;
95             (void)format.GetIntValue("frame_rate", targetFrameRateInt);
96             if (data.frameRate.minVal > targetFrameRateInt || data.frameRate.maxVal < targetFrameRateInt) {
97                 return false;
98             }
99             break;
100         }
101         case FORMAT_TYPE_DOUBLE: {
102             double targetFrameRateDouble;
103             (void)format.GetDoubleValue("frame_rate", targetFrameRateDouble);
104             double minValDouble {data.frameRate.minVal};
105             double maxValDouble {data.frameRate.maxVal};
106             if ((minValDouble > targetFrameRateDouble && fabs(minValDouble - targetFrameRateDouble) >= EPSINON) ||
107                 (maxValDouble < targetFrameRateDouble && fabs(maxValDouble - targetFrameRateDouble) >= EPSINON)) {
108                 return false;
109             }
110             break;
111         }
112         default:
113             break;
114     }
115     return true;
116 }
117 
CheckAudioChannel(const Format & format,const CapabilityData & data)118 bool CodecListCore::CheckAudioChannel(const Format &format, const CapabilityData &data)
119 {
120     int32_t targetChannel;
121     if (!format.ContainKey("channel_count")) {
122         AVCODEC_LOGD("The channel_count of the format are not specified");
123         return true;
124     }
125     (void)format.GetIntValue("channel_count", targetChannel);
126     if (data.channels.minVal > targetChannel || data.channels.maxVal < targetChannel) {
127         return false;
128     }
129     return true;
130 }
131 
CheckAudioSampleRate(const Format & format,const CapabilityData & data)132 bool CodecListCore::CheckAudioSampleRate(const Format &format, const CapabilityData &data)
133 {
134     int32_t targetSampleRate;
135     if (!format.ContainKey("samplerate")) {
136         AVCODEC_LOGD("The samplerate of the format are not specified");
137         return true;
138     }
139     (void)format.GetIntValue("samplerate", targetSampleRate);
140     if (find(data.sampleRate.begin(), data.sampleRate.end(), targetSampleRate) == data.sampleRate.end()) {
141         return false;
142     }
143     return true;
144 }
145 
IsVideoCapSupport(const Format & format,const CapabilityData & data)146 bool CodecListCore::IsVideoCapSupport(const Format &format, const CapabilityData &data)
147 {
148     return CheckVideoResolution(format, data) && CheckVideoPixelFormat(format, data) &&
149            CheckVideoFrameRate(format, data) && CheckBitrate(format, data);
150 }
151 
IsAudioCapSupport(const Format & format,const CapabilityData & data)152 bool CodecListCore::IsAudioCapSupport(const Format &format, const CapabilityData &data)
153 {
154     return CheckAudioChannel(format, data) && CheckAudioSampleRate(format, data) && CheckBitrate(format, data);
155 }
156 
157 // mime是必要参数
FindCodec(const Format & format,bool isEncoder)158 std::string CodecListCore::FindCodec(const Format &format, bool isEncoder)
159 {
160     std::lock_guard<std::mutex> lock(mutex_);
161     if (!format.ContainKey("codec_mime")) {
162         AVCODEC_LOGD("Get MimeType from format failed");
163         return "";
164     }
165     std::string targetMimeType;
166     (void)format.GetStringValue("codec_mime", targetMimeType);
167 
168     AVCodecType codecType = AVCODEC_TYPE_NONE;
169     bool isVideo = targetMimeType.find("video") != std::string::npos;
170     if (isVideo) {
171         codecType = isEncoder ? AVCODEC_TYPE_VIDEO_ENCODER : AVCODEC_TYPE_VIDEO_DECODER;
172     } else {
173         codecType = isEncoder ? AVCODEC_TYPE_AUDIO_ENCODER : AVCODEC_TYPE_AUDIO_DECODER;
174     }
175 
176     int isVendor = -1;
177     bool isVendorKey = format.ContainKey("codec_vendor_flag");
178     if (isVendorKey) {
179         (void)format.GetIntValue("codec_vendor_flag", isVendor);
180     }
181     std::vector<CapabilityData> capabilityDataArray = CodecAbilitySingleton::GetInstance().GetCapabilityArray();
182     std::unordered_map<std::string, std::vector<size_t>> mimeCapIdxMap =
183         CodecAbilitySingleton::GetInstance().GetMimeCapIdxMap();
184     if (mimeCapIdxMap.find(targetMimeType) == mimeCapIdxMap.end()) {
185         return "";
186     }
187     std::vector<size_t> capsIdx = mimeCapIdxMap.at(targetMimeType);
188     for (auto iter = capsIdx.begin(); iter != capsIdx.end(); iter++) {
189         CapabilityData capsData = capabilityDataArray[*iter];
190         if (capsData.codecType != codecType || capsData.mimeType != targetMimeType ||
191             (isVendorKey && capsData.isVendor != isVendor)) {
192             continue;
193         }
194         if (isVideo) {
195             if (IsVideoCapSupport(format, capsData)) {
196                 return capsData.codecName;
197             }
198         } else {
199             if (IsAudioCapSupport(format, capsData)) {
200                 return capsData.codecName;
201             }
202         }
203     }
204     return "";
205 }
206 
FindEncoder(const Format & format)207 std::string CodecListCore::FindEncoder(const Format &format)
208 {
209     return FindCodec(format, true);
210 }
211 
FindDecoder(const Format & format)212 std::string CodecListCore::FindDecoder(const Format &format)
213 {
214     return FindCodec(format, false);
215 }
216 
FindCodecType(std::string codecName)217 CodecType CodecListCore::FindCodecType(std::string codecName)
218 {
219     std::lock_guard<std::mutex> lock(mutex_);
220     if (codecName.empty()) {
221         return CodecType::AVCODEC_INVALID;
222     }
223     std::unordered_map<std::string, CodecType> nameCodecTypeMap =
224         CodecAbilitySingleton::GetInstance().GetNameCodecTypeMap();
225     if (nameCodecTypeMap.find(codecName) != nameCodecTypeMap.end()) {
226         return nameCodecTypeMap.at(codecName);
227     }
228     return CodecType::AVCODEC_INVALID;
229 }
230 
GetCapability(CapabilityData & capData,const std::string & mime,const bool isEncoder,const AVCodecCategory & category)231 int32_t CodecListCore::GetCapability(CapabilityData &capData, const std::string &mime, const bool isEncoder,
232                                      const AVCodecCategory &category)
233 {
234     std::lock_guard<std::mutex> lock(mutex_);
235     if (mime.empty()) {
236         return AVCS_ERR_INVALID_VAL;
237     }
238     AVCodecType codecType = AVCODEC_TYPE_NONE;
239     bool isVideo = mime.find("video") != std::string::npos;
240     if (isVideo) {
241         codecType = isEncoder ? AVCODEC_TYPE_VIDEO_ENCODER : AVCODEC_TYPE_VIDEO_DECODER;
242     } else {
243         codecType = isEncoder ? AVCODEC_TYPE_AUDIO_ENCODER : AVCODEC_TYPE_AUDIO_DECODER;
244     }
245     bool isVendor = (category == AVCodecCategory::AVCODEC_HARDWARE) ? true : false;
246     std::vector<CapabilityData> capsDataArray = CodecAbilitySingleton::GetInstance().GetCapabilityArray();
247     std::unordered_map<std::string, std::vector<size_t>> mimeCapIdxMap =
248         CodecAbilitySingleton::GetInstance().GetMimeCapIdxMap();
249     if (mimeCapIdxMap.find(mime) == mimeCapIdxMap.end()) {
250         return AVCS_ERR_INVALID_VAL;
251     }
252     std::vector<size_t> capsIdx = mimeCapIdxMap.at(mime);
253     for (auto iter = capsIdx.begin(); iter != capsIdx.end(); iter++) {
254         if (capsDataArray[*iter].codecType == codecType && capsDataArray[*iter].mimeType == mime) {
255             if (category != AVCodecCategory::AVCODEC_NONE && capsDataArray[*iter].isVendor != isVendor) {
256                 continue;
257             }
258             capData = capsDataArray[*iter];
259             AVCODEC_LOGI("Get capability of codec successful: %{public}s", mime.c_str());
260             break;
261         }
262     }
263     return AVCS_ERR_OK;
264 }
265 
FindCodecNameArray(const std::string & mime,bool isEncoder)266 std::vector<std::string> CodecListCore::FindCodecNameArray(const std::string &mime, bool isEncoder)
267 {
268     std::lock_guard<std::mutex> lock(mutex_);
269     auto &codecAbility = CodecAbilitySingleton::GetInstance();
270 
271     std::unordered_map<std::string, std::vector<size_t>> mimeCapIdxMap = codecAbility.GetMimeCapIdxMap();
272     std::vector<CapabilityData> capabilityArray = codecAbility.GetCapabilityArray();
273     std::vector<std::string> nameArray;
274     auto iter = mimeCapIdxMap.find(mime);
275     CHECK_AND_RETURN_RET_LOG(iter != mimeCapIdxMap.end(), nameArray, "Can not find input mime type, %{public}s.",
276                              mime.c_str());
277     AVCodecType codecType = AVCODEC_TYPE_NONE;
278     bool isVideo = mime.find("video") != std::string::npos;
279     if (isVideo) {
280         codecType = isEncoder ? AVCODEC_TYPE_VIDEO_ENCODER : AVCODEC_TYPE_VIDEO_DECODER;
281     } else {
282         codecType = isEncoder ? AVCODEC_TYPE_AUDIO_ENCODER : AVCODEC_TYPE_AUDIO_DECODER;
283     }
284 
285     for (auto index : iter->second) {
286         if (capabilityArray[index].codecType == codecType) {
287             nameArray.push_back(capabilityArray[index].codecName);
288         }
289     }
290     return nameArray;
291 }
292 } // namespace MediaAVCodec
293 } // namespace OHOS