1 /*
2  * Copyright (C) 2024 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 "codec_param_checker.h"
17 #include <unordered_map>
18 #include <vector>
19 #include <memory>
20 #include <string>
21 #include <algorithm>
22 #include "avcodec_log.h"
23 #include "avcodec_errors.h"
24 #include "avcodec_trace.h"
25 #include "meta/meta_key.h"
26 #include "codec_ability_singleton.h"
27 #include "media_description.h"
28 #include "meta/meta_key.h"
29 #include "temporal_scalability.h"
30 #include "meta/video_types.h"
31 #include "surface_type.h"
32 
33 namespace {
34 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "CodecParamChecker"};
35 using namespace OHOS::Media;
36 using namespace OHOS::MediaAVCodec;
37 
38 constexpr int32_t DEFAULT_QUALITY = 50;
39 constexpr int32_t DEFAULT_I_FRAME_INTERVAL = 1000;
40 
41 const std::unordered_map<CodecScenario, std::string_view> CODEC_SCENARIO_TO_STRING = {
42     {CodecScenario::CODEC_SCENARIO_ENC_NORMAL, "encoder normal"},
43     {CodecScenario::CODEC_SCENARIO_ENC_TEMPORAL_SCALABILITY, "encoder temporal scalability"},
44     {CodecScenario::CODEC_SCENARIO_DEC_NORMAL, "decoder normal"},
45 };
46 
PrintParam(bool paramExist,const std::string_view tag,T value)47 template<class T> void PrintParam(bool paramExist, const std::string_view tag, T value)
48 {
49     if (!paramExist) {
50         return;
51     }
52     using namespace std::string_literals;
53     std::string logMsg = "Param "s + tag.data() + " set, value: "s + std::to_string(value);
54     AVCODEC_LOGI("%{public}s", logMsg.c_str());
55 }
56 
PrintParam(bool paramExist,const std::string_view tag,T value1,T value2)57 template<class T> void PrintParam(bool paramExist, const std::string_view tag, T value1, T value2)
58 {
59     if (!paramExist) {
60         return;
61     }
62     using namespace std::string_literals;
63     std::string logMsg = "Param "s + tag.data() + " set, value: "s +
64         std::to_string(value1) + " - " + std::to_string(value2);
65     AVCODEC_LOGI("%{public}s", logMsg.c_str());
66 }
67 
PrintCodecScenario(CodecScenario scenario)68 inline void PrintCodecScenario(CodecScenario scenario)
69 {
70     auto scenarioName = CODEC_SCENARIO_TO_STRING.find(scenario);
71     if (scenarioName != CODEC_SCENARIO_TO_STRING.end()) {
72         AVCODEC_LOGI("Codec scenario is %{public}s", scenarioName->second.data());
73     } else {
74         AVCODEC_LOGI("Codec scenario is %{public}d", scenario);
75     }
76 }
77 
IsSupported(std::vector<T> cap,T value)78 template<class T> bool IsSupported(std::vector<T> cap, T value)
79 {
80     return std::find(cap.begin(), cap.end(), value) != cap.end();
81 }
82 
83 // Video scenario checker
84 std::optional<CodecScenario> TemporalScalabilityChecker(CapabilityData &capData, const Format &format,
85                                                         AVCodecType codecType);
86 
87 // Video codec checker
88 int32_t ResolutionChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
89 int32_t PixelFormatChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
90 int32_t FramerateChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
91 int32_t BitrateAndQualityChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
92 int32_t VideoProfileChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
93 int32_t RotaitonChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
94 int32_t QPChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
95 int32_t IFrameIntervalChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
96 int32_t TemporalGopSizeChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
97 int32_t TemporalGopReferenceModeChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
98 int32_t UniformlyScaledReferenceChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
99 int32_t ColorPrimariesChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
100 int32_t TransferCharacteristicsChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
101 int32_t MatrixCoefficientsChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
102 int32_t LTRFrameCountChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
103 int32_t ScalingModeChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
104 int32_t PostProcessingChecker(CapabilityData &capData, Format &format, CodecScenario scenario);
105 
106 // Checkers list define
107 using ScenarioCheckerType =
108     std::optional<CodecScenario> (*)(CapabilityData &capData, const Format &format, AVCodecType codecType);
109 using ParamCheckerType = int32_t (*)(CapabilityData &capData, Format &format, CodecScenario scenario);
110 using ScenarioCheckerListType = std::vector<ScenarioCheckerType>;
111 using ParamCheckerListType = std::vector<ParamCheckerType>;
112 const ParamCheckerListType VIDEO_ENCODER_CONFIGURE_CHECKER_LIST = {
113     ResolutionChecker,
114     PixelFormatChecker,
115     FramerateChecker,
116     BitrateAndQualityChecker,
117     VideoProfileChecker,
118     QPChecker,
119     IFrameIntervalChecker,
120     ColorPrimariesChecker,
121     TransferCharacteristicsChecker,
122     MatrixCoefficientsChecker,
123     LTRFrameCountChecker,
124 };
125 
126 const ParamCheckerListType VIDEO_ENCODER_TEMPORAL_SCALABILITY_CONFIGURE_CHECKER_LIST = {
127     ResolutionChecker,
128     PixelFormatChecker,
129     FramerateChecker,
130     BitrateAndQualityChecker,
131     VideoProfileChecker,
132     QPChecker,
133     IFrameIntervalChecker,
134     TemporalGopSizeChecker,
135     TemporalGopReferenceModeChecker,
136     UniformlyScaledReferenceChecker,
137     ColorPrimariesChecker,
138     TransferCharacteristicsChecker,
139     MatrixCoefficientsChecker,
140     LTRFrameCountChecker,
141 };
142 
143 const ParamCheckerListType VIDEO_DECODER_CONFIGURE_CHECKER_LIST = {
144     ResolutionChecker,
145     PixelFormatChecker,
146     FramerateChecker,
147     RotaitonChecker,
148     ScalingModeChecker,
149     PostProcessingChecker,
150 };
151 
152 const ParamCheckerListType VIDEO_ENCODER_PARAMETER_CHECKER_LIST = {
153     FramerateChecker,
154     BitrateAndQualityChecker,
155     QPChecker,
156 };
157 
158 const ParamCheckerListType VIDEO_DECODER_PARAMETER_CHECKER_LIST = {};
159 
160 const ScenarioCheckerListType VIDEO_SCENARIO_CHECKER_LIST = {
161     TemporalScalabilityChecker,
162 };
163 
164 const std::vector<std::string_view> FORMAT_MERGE_LIST = {
165     MediaDescriptionKey::MD_KEY_BITRATE,
166     MediaDescriptionKey::MD_KEY_QUALITY,
167     MediaDescriptionKey::MD_KEY_FRAME_RATE,
168     Tag::VIDEO_ENCODER_QP_MIN,
169     Tag::VIDEO_ENCODER_QP_MAX,
170 };
171 
172 // Checkers table
173 const std::unordered_map<CodecScenario, ParamCheckerListType> CONFIGURE_CHECKERS_TABLE = {
174     {CodecScenario::CODEC_SCENARIO_ENC_NORMAL, VIDEO_ENCODER_CONFIGURE_CHECKER_LIST},
175     {CodecScenario::CODEC_SCENARIO_ENC_TEMPORAL_SCALABILITY, VIDEO_ENCODER_TEMPORAL_SCALABILITY_CONFIGURE_CHECKER_LIST},
176     {CodecScenario::CODEC_SCENARIO_DEC_NORMAL, VIDEO_DECODER_CONFIGURE_CHECKER_LIST},
177 };
178 
179 const std::unordered_map<CodecScenario, ParamCheckerListType> PARAMETER_CHECKERS_TABLE = {
180     {CodecScenario::CODEC_SCENARIO_ENC_NORMAL, VIDEO_ENCODER_PARAMETER_CHECKER_LIST},
181     {CodecScenario::CODEC_SCENARIO_ENC_TEMPORAL_SCALABILITY, VIDEO_ENCODER_PARAMETER_CHECKER_LIST},
182     {CodecScenario::CODEC_SCENARIO_DEC_NORMAL, VIDEO_DECODER_PARAMETER_CHECKER_LIST},
183 };
184 
185 // Checkers implementation
TemporalScalabilityChecker(CapabilityData & capData,const Format & format,AVCodecType codecType)186 std::optional<CodecScenario> TemporalScalabilityChecker(CapabilityData &capData, const Format &format,
187                                                         AVCodecType codecType)
188 {
189     int32_t enable = 0;
190     std::optional<CodecScenario> scenario = std::nullopt;
191     bool enableExist = format.GetIntValue(Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, enable);
192     bool temporalGopSizeExist = format.ContainKey(Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE);
193     bool modeExist = format.ContainKey(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE);
194     PrintParam(enableExist, Tag::VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY, enable);
195 
196     if (codecType == AVCODEC_TYPE_VIDEO_DECODER) {
197         if (enableExist || temporalGopSizeExist || modeExist) {
198             AVCODEC_LOGW("Temporal scalability is only supported in video encoder!");
199         }
200         return scenario;
201     }
202     if (!enableExist || !enable) {
203         if (temporalGopSizeExist || modeExist) {
204             AVCODEC_LOGW("Please enable key VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY!");
205         }
206         return scenario;
207     }
208     CHECK_AND_RETURN_RET_LOGW(capData.featuresMap.count(
209         static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_TEMPORAL_SCALABILITY)),
210         scenario, "Not support temporal scalability");
211 
212     scenario = CodecScenario::CODEC_SCENARIO_ENC_TEMPORAL_SCALABILITY;
213     return scenario;
214 }
215 
ResolutionChecker(CapabilityData & capData,Format & format,CodecScenario scenario)216 int32_t ResolutionChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
217 {
218     (void)scenario;
219     int32_t width = 0;
220     int32_t height = 0;
221     bool widthExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width);
222     bool heightExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
223     CHECK_AND_RETURN_RET_LOG(widthExist && heightExist, AVCS_ERR_INVALID_VAL, "Key param missing, width or height");
224     PrintParam(widthExist && heightExist, "resolution", width, height);
225 
226     bool resolutionValid = true;
227     if (capData.supportSwapWidthHeight) {
228         AVCODEC_LOGI("Codec support swap width and height");
229         resolutionValid = (capData.width.InRange(width) && capData.height.InRange(height)) ||
230                           (capData.width.InRange(height) && capData.height.InRange(width));
231     } else {
232         resolutionValid = capData.width.InRange(width) && capData.height.InRange(height);
233     }
234     CHECK_AND_RETURN_RET_LOG(resolutionValid, AVCS_ERR_INVALID_VAL,
235         "Param invalid, resolution: %{public}d*%{public}d, range: [%{public}d*%{public}d]-[%{public}d*%{public}d]",
236         width, height, capData.width.minVal, capData.height.minVal, capData.width.maxVal, capData.height.maxVal);
237     return AVCS_ERR_OK;
238 }
239 
PixelFormatChecker(CapabilityData & capData,Format & format,CodecScenario scenario)240 int32_t PixelFormatChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
241 {
242     (void)scenario;
243     int32_t pixelFormat;
244     bool paramExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, pixelFormat);
245     if (!paramExist || pixelFormat == static_cast<int32_t>(VideoPixelFormat::SURFACE_FORMAT)) {
246         return AVCS_ERR_OK;
247     }
248     PrintParam(paramExist, MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, pixelFormat);
249 
250     bool paramValid = IsSupported(capData.pixFormat, pixelFormat);
251     CHECK_AND_RETURN_RET_LOG(paramValid, AVCS_ERR_UNSUPPORT,
252         "Param invalid, %{public}s: %{public}d, please check codec capabilities",
253         MediaDescriptionKey::MD_KEY_PIXEL_FORMAT.data(), pixelFormat);     // Invalid pixel format
254 
255     return AVCS_ERR_OK;
256 }
257 
FramerateChecker(CapabilityData & capData,Format & format,CodecScenario scenario)258 int32_t FramerateChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
259 {
260     (void)capData;
261     (void)scenario;
262     double framerate;
263     bool paramExist = format.GetDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, framerate);
264     PrintParam(paramExist, MediaDescriptionKey::MD_KEY_FRAME_RATE, framerate);
265     if (paramExist == false) {
266         return AVCS_ERR_OK;
267     }
268 
269     bool paramValid = framerate > 0 ? true : false;
270     CHECK_AND_RETURN_RET_LOG(paramValid, AVCS_ERR_CODEC_PARAM_INCORRECT,
271         "Param invalid, %{public}s: %{public}.2f, should be greater than 0",
272         MediaDescriptionKey::MD_KEY_FRAME_RATE.data(), framerate);     // Invalid framerate
273 
274     return AVCS_ERR_OK;
275 }
276 
BitrateAndQualityChecker(CapabilityData & capData,Format & format,CodecScenario scenario)277 int32_t BitrateAndQualityChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
278 {
279     (void)scenario;
280     int64_t bitrate;
281     int32_t quality;
282     int32_t bitrateMode;
283     bool bitrateExist = format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, bitrate);
284     bool qualityExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_QUALITY, quality);
285     bool bitrateModeExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, bitrateMode);
286     PrintParam(bitrateExist, MediaDescriptionKey::MD_KEY_BITRATE, bitrate);
287     PrintParam(qualityExist, MediaDescriptionKey::MD_KEY_QUALITY, quality);
288     PrintParam(bitrateModeExist, MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, bitrateMode);
289 
290     CHECK_AND_RETURN_RET_LOG(!(bitrateExist && qualityExist), AVCS_ERR_CODEC_PARAM_INCORRECT,
291         "Param invalid, bitrate and quality mutually include");  // bitrate and quality mutually include
292 
293     if (bitrateExist) {
294         bool bitrateValid = capData.bitrate.InRange(bitrate);
295         CHECK_AND_RETURN_RET_LOG(bitrateValid, AVCS_ERR_CODEC_PARAM_INCORRECT,
296             "Param invalid, %{public}s: %{public}d, range: %{public}d-%{public}d",
297             MediaDescriptionKey::MD_KEY_BITRATE.data(), static_cast<int32_t>(bitrate),
298             capData.bitrate.minVal, capData.bitrate.maxVal);
299     }
300     if (qualityExist) {
301         bool qualityValid = capData.encodeQuality.InRange(quality);
302         CHECK_AND_RETURN_RET_LOG(qualityValid, AVCS_ERR_CODEC_PARAM_INCORRECT,
303             "Param invalid, %{public}s: %{public}d, range: %{public}d-%{public}d",
304             MediaDescriptionKey::MD_KEY_QUALITY.data(), quality,
305             capData.encodeQuality.minVal, capData.encodeQuality.maxVal);
306     }
307     if (bitrateModeExist) {
308         bool bitrateModeValid = IsSupported(capData.bitrateMode, bitrateMode);
309         CHECK_AND_RETURN_RET_LOG(bitrateModeValid, AVCS_ERR_CODEC_PARAM_INCORRECT,
310             "Param invalid, %{public}s: %{public}d",
311             MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE.data(), bitrateMode);     // Invalid bitrate mode
312         CHECK_AND_RETURN_RET_LOG(!(bitrateExist && bitrateMode == VideoEncodeBitrateMode::CQ),
313             AVCS_ERR_CODEC_PARAM_INCORRECT, "Param invalid, in CQ mode but set bitrate!");
314         CHECK_AND_RETURN_RET_LOG(!(qualityExist && bitrateMode != VideoEncodeBitrateMode::CQ),
315             AVCS_ERR_CODEC_PARAM_INCORRECT, "Param invalid, not in CQ mode but set quality!");
316         if (!qualityExist && bitrateMode == VideoEncodeBitrateMode::CQ) {
317             format.PutIntValue(MediaDescriptionKey::MD_KEY_QUALITY, DEFAULT_QUALITY);
318             AVCODEC_LOGW("In CQ mode but not set quality, set default quality: %{public}d", DEFAULT_QUALITY);
319         }
320     } else {
321         if (qualityExist && IsSupported(capData.bitrateMode, static_cast<int32_t>(VideoEncodeBitrateMode::CQ))) {
322             bitrateMode = VideoEncodeBitrateMode::CQ;
323             format.PutIntValue(MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, bitrateMode);
324         }
325     }
326 
327     return AVCS_ERR_OK;
328 }
329 
VideoProfileChecker(CapabilityData & capData,Format & format,CodecScenario scenario)330 int32_t VideoProfileChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
331 {
332     (void)scenario;
333     int32_t profile;
334     bool paramExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_PROFILE, profile);
335     if (paramExist == false) {
336         return AVCS_ERR_OK;
337     }
338     PrintParam(paramExist, MediaDescriptionKey::MD_KEY_PROFILE, profile);
339 
340     bool paramValid = IsSupported(capData.profiles, profile);
341     CHECK_AND_RETURN_RET_LOG(paramValid, AVCS_ERR_CODEC_PARAM_INCORRECT,
342         "Param invalid, %{public}s: %{public}d, please check codec capabilities",
343         MediaDescriptionKey::MD_KEY_PROFILE.data(), profile);     // Invalid profile
344 
345     return AVCS_ERR_OK;
346 }
347 
RotaitonChecker(CapabilityData & capData,Format & format,CodecScenario scenario)348 int32_t RotaitonChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
349 {
350     (void)capData;
351     (void)scenario;
352     int32_t rotation;
353     bool paramExist = format.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotation);
354     if (paramExist == false) {
355         return AVCS_ERR_OK;
356     }
357     PrintParam(paramExist, MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotation);
358 
359     // valid rotation: 0, 90, 180, 270
360     CHECK_AND_RETURN_RET_LOG(rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270,
361         AVCS_ERR_CODEC_PARAM_INCORRECT, "Param invalid, %{public}s: %{public}d, only support {0, 90, 180, 270}",
362         MediaDescriptionKey::MD_KEY_ROTATION_ANGLE.data(), rotation);    //  Invalid rotation
363 
364     return AVCS_ERR_OK;
365 }
366 
PostProcessingChecker(CapabilityData & capData,Format & format,CodecScenario scenario)367 int32_t PostProcessingChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
368 {
369     if (scenario != CodecScenario::CODEC_SCENARIO_DEC_NORMAL) {
370         return AVCS_ERR_OK;
371     }
372     int32_t colorSpace;
373     bool hasColorSpace = format.GetIntValue(MediaDescriptionKey::MD_KEY_VIDEO_DECODER_OUTPUT_COLOR_SPACE, colorSpace);
374     if (!hasColorSpace) {
375         return AVCS_ERR_OK;
376     }
377     CHECK_AND_RETURN_RET_LOG((colorSpace >= 0) &&    // 0: OH_COLORSAPCE_NONE
378                                  (colorSpace <= 31), // 31: OH_COLORSPACE_DISPLAY_BT2020_PQ
379                              AVCS_ERR_INVALID_VAL, "The output color space %{public}d is invaild", colorSpace);
380     CHECK_AND_RETURN_RET_LOG(capData.mimeType == CodecMimeType::VIDEO_HEVC && capData.isVendor,
381                              AVCS_ERR_VIDEO_UNSUPPORT_COLOR_SPACE_CONVERSION,
382                              "colorspace conversion is not available for the codec.");
383 
384     constexpr int32_t colorSpaceBt709Limited = 8; // see OH_COLORSPACE_BT709_LIMITED in native_buffer.h;
385     CHECK_AND_RETURN_RET_LOG(colorSpace == colorSpaceBt709Limited, AVCS_ERR_VIDEO_UNSUPPORT_COLOR_SPACE_CONVERSION,
386                              "The output color space %{public}d is not supported", colorSpace);
387     PrintParam(true, MediaDescriptionKey::MD_KEY_VIDEO_DECODER_OUTPUT_COLOR_SPACE, colorSpace);
388 
389     return AVCS_ERR_OK;
390 }
391 
QPChecker(CapabilityData & capData,Format & format,CodecScenario scenario)392 int32_t QPChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
393 {
394     (void)capData;
395     (void)scenario;
396     constexpr int32_t MAX_QP = 51;
397     int32_t qpMin;
398     int32_t qpMax;
399     bool qpMinExist = format.GetIntValue(Tag::VIDEO_ENCODER_QP_MIN, qpMin);
400     bool qpMaxExist = format.GetIntValue(Tag::VIDEO_ENCODER_QP_MAX, qpMax);
401     if (!qpMinExist && !qpMaxExist) {
402         return AVCS_ERR_OK;
403     }
404     CHECK_AND_RETURN_RET_LOG(!(qpMinExist != qpMaxExist), AVCS_ERR_INVALID_VAL,
405         "Param invalid, QPmin and QPmax are expected to be set in pairs in format");
406     PrintParam(qpMinExist && qpMaxExist, "QP", qpMin, qpMax);
407 
408     CHECK_AND_RETURN_RET_LOG(qpMin >= 0 && qpMin <= qpMax, AVCS_ERR_INVALID_VAL,
409         "Param invalid, QP range: %{public}d-%{public}d", qpMin, qpMax);
410     CHECK_AND_RETURN_RET_LOG(qpMax <= MAX_QP && qpMax >= qpMin, AVCS_ERR_INVALID_VAL,
411         "Param invalid, QP range: %{public}d-%{public}d", qpMin, qpMax);
412 
413     return AVCS_ERR_OK;
414 }
415 
IFrameIntervalChecker(CapabilityData & capData,Format & format,CodecScenario scenario)416 int32_t IFrameIntervalChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
417 {
418     (void)capData;
419     (void)scenario;
420 
421     int32_t iFrameInterval;
422     bool iFrameIntervalExist = format.GetIntValue(Tag::VIDEO_I_FRAME_INTERVAL, iFrameInterval);
423     PrintParam(iFrameIntervalExist, Tag::VIDEO_I_FRAME_INTERVAL, iFrameInterval);
424     if (!iFrameIntervalExist) {
425         format.PutIntValue(Tag::VIDEO_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL);
426     }
427 
428     return AVCS_ERR_OK;
429 }
430 
TemporalGopSizeChecker(CapabilityData & capData,Format & format,CodecScenario scenario)431 int32_t TemporalGopSizeChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
432 {
433     (void)capData;
434     (void)scenario;
435     int32_t gopSize;
436     int32_t temporalGopSize;
437     double frameRate;
438     int32_t iFrameInterval;
439 
440     bool frameRateExist = format.GetDoubleValue(Tag::VIDEO_FRAME_RATE, frameRate);
441     bool iFrameIntervalExist = format.GetIntValue(Tag::VIDEO_I_FRAME_INTERVAL, iFrameInterval);
442     CHECK_AND_RETURN_RET_LOG(!(iFrameIntervalExist && iFrameInterval == 0), AVCS_ERR_INVALID_VAL,
443         "Not support all key frame in temporal scalability");
444 
445     if (!frameRateExist) {
446         frameRate = DEFAULT_FRAMERATE;
447         format.PutDoubleValue(Tag::VIDEO_FRAME_RATE, DEFAULT_FRAMERATE);
448     }
449     if (!iFrameIntervalExist) {
450         iFrameInterval = DEFAULT_I_FRAME_INTERVAL;
451         format.PutIntValue(Tag::VIDEO_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL);
452     }
453     gopSize = iFrameInterval < 0 ? INT32_MAX : static_cast<int32_t>(frameRate * iFrameInterval / 1000); // 1000: ms to s
454     CHECK_AND_RETURN_RET_LOG(gopSize > MIN_TEMPORAL_GOPSIZE, AVCS_ERR_INVALID_VAL,
455         "Unsuppoted gop size, should be greater than %{public}d!", MIN_TEMPORAL_GOPSIZE);
456     format.PutIntValue("video_encoder_gop_size", gopSize);
457 
458     bool temporalGopSizeExist = format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize);
459     if (!temporalGopSizeExist) {
460         return AVCS_ERR_OK;
461     }
462     PrintParam(temporalGopSizeExist, Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize);
463     CHECK_AND_RETURN_RET_LOG(temporalGopSize >= MIN_TEMPORAL_GOPSIZE, AVCS_ERR_INVALID_VAL,
464         "Param invalid, %{public}s: %{public}d, expect greater or equal than %{public}d",
465         Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize, MIN_TEMPORAL_GOPSIZE);
466     CHECK_AND_RETURN_RET_LOG(temporalGopSize < gopSize, AVCS_ERR_INVALID_VAL,
467         "Param invalid, %{public}s: %{public}d, expect less than gop_size: %{public}d",
468         Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize, gopSize);
469 
470     return AVCS_ERR_OK;
471 }
472 
TemporalGopReferenceModeChecker(CapabilityData & capData,Format & format,CodecScenario scenario)473 int32_t TemporalGopReferenceModeChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
474 {
475     (void)capData;
476     (void)scenario;
477     int32_t mode;
478     bool modeExist = format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, mode);
479     if (!modeExist) {
480         return AVCS_ERR_OK;
481     }
482     PrintParam(modeExist, Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, mode);
483 
484     using namespace OHOS::Media::Plugins;
485     if (mode < static_cast<int32_t>(TemporalGopReferenceMode::ADJACENT_REFERENCE) ||
486         mode >= static_cast<int32_t>(TemporalGopReferenceMode::UNKNOWN)) {
487         AVCODEC_LOGE("Param invalid, %{public}s: %{public}d", Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, mode);
488         return AVCS_ERR_INVALID_VAL;
489     }
490     return AVCS_ERR_OK;
491 }
492 
UniformlyScaledReferenceChecker(CapabilityData & capData,Format & format,CodecScenario scenario)493 int32_t UniformlyScaledReferenceChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
494 {
495     (void)capData;
496     (void)scenario;
497     int32_t mode = -1;
498     format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_REFERENCE_MODE, mode);
499     using namespace OHOS::Media::Plugins;
500     if (mode == static_cast<int32_t>(TemporalGopReferenceMode::UNIFORMLY_SCALED_REFERENCE)) {
501         int32_t temporalGopSize;
502         bool temporalGopSizeExist = format.GetIntValue(Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize);
503         if (!temporalGopSizeExist) {
504             return AVCS_ERR_OK;
505         }
506         CHECK_AND_RETURN_RET_LOG(temporalGopSize == MIN_TEMPORAL_GOPSIZE || temporalGopSize == DEFAULT_TEMPORAL_GOPSIZE,
507                                  AVCS_ERR_INVALID_VAL,
508                                  "Current temporal reference mode param invalid, %{public}s: %{public}d, expect 2 or 4",
509                                  Tag::VIDEO_ENCODER_TEMPORAL_GOP_SIZE, temporalGopSize);
510     }
511     return AVCS_ERR_OK;
512 }
513 
ColorPrimariesChecker(CapabilityData & capData,Format & format,CodecScenario scenario)514 int32_t ColorPrimariesChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
515 {
516     (void)capData;
517     (void)scenario;
518     int32_t colorPrimaries;
519     bool colorPrimariesExist = format.GetIntValue(Tag::VIDEO_COLOR_PRIMARIES, colorPrimaries);
520     if (!colorPrimariesExist) {
521         return AVCS_ERR_OK;
522     }
523     PrintParam(colorPrimariesExist, Tag::VIDEO_COLOR_PRIMARIES, colorPrimaries);
524 
525     if (colorPrimaries < static_cast<int32_t>(ColorPrimary::COLOR_PRIMARY_BT709) ||
526         colorPrimaries > static_cast<int32_t>(ColorPrimary::COLOR_PRIMARY_P3D65)) {
527         AVCODEC_LOGE("Param invalid, %{public}s: %{public}d", Tag::VIDEO_COLOR_PRIMARIES, colorPrimaries);
528         return AVCS_ERR_INVALID_VAL;
529     }
530     return AVCS_ERR_OK;
531 }
532 
TransferCharacteristicsChecker(CapabilityData & capData,Format & format,CodecScenario scenario)533 int32_t TransferCharacteristicsChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
534 {
535     (void)capData;
536     (void)scenario;
537     int32_t transferCharacteristics;
538     bool transferCharacteristicsExist = format.GetIntValue(Tag::VIDEO_COLOR_TRC, transferCharacteristics);
539     if (!transferCharacteristicsExist) {
540         return AVCS_ERR_OK;
541     }
542     PrintParam(transferCharacteristicsExist, Tag::VIDEO_COLOR_TRC, transferCharacteristics);
543 
544     if (transferCharacteristics < static_cast<int32_t>(TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709) ||
545         transferCharacteristics > static_cast<int32_t>(TransferCharacteristic::TRANSFER_CHARACTERISTIC_HLG)) {
546         AVCODEC_LOGE("Param invalid, %{public}s: %{public}d", Tag::VIDEO_COLOR_TRC, transferCharacteristics);
547         return AVCS_ERR_INVALID_VAL;
548     }
549     return AVCS_ERR_OK;
550 }
551 
MatrixCoefficientsChecker(CapabilityData & capData,Format & format,CodecScenario scenario)552 int32_t MatrixCoefficientsChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
553 {
554     (void)capData;
555     (void)scenario;
556     int32_t matrixCoefficients;
557     bool matrixCoefficientsExist = format.GetIntValue(Tag::VIDEO_COLOR_MATRIX_COEFF, matrixCoefficients);
558     if (!matrixCoefficientsExist) {
559         return AVCS_ERR_OK;
560     }
561     PrintParam(matrixCoefficientsExist, Tag::VIDEO_COLOR_MATRIX_COEFF, matrixCoefficients);
562 
563     if (matrixCoefficients < static_cast<int32_t>(MatrixCoefficient::MATRIX_COEFFICIENT_IDENTITY) ||
564         matrixCoefficients > static_cast<int32_t>(MatrixCoefficient::MATRIX_COEFFICIENT_ICTCP)) {
565         AVCODEC_LOGE("Param invalid, %{public}s: %{public}d", Tag::VIDEO_COLOR_MATRIX_COEFF, matrixCoefficients);
566         return AVCS_ERR_INVALID_VAL;
567     }
568     return AVCS_ERR_OK;
569 }
570 
LTRFrameCountChecker(CapabilityData & capData,Format & format,CodecScenario scenario)571 int32_t LTRFrameCountChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
572 {
573     int32_t ltrFrameCount;
574     bool ltrFrameCountExist = format.GetIntValue(Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, ltrFrameCount);
575     if (!ltrFrameCountExist) {
576         return AVCS_ERR_OK;
577     }
578     PrintParam(ltrFrameCountExist, Tag::VIDEO_ENCODER_LTR_FRAME_COUNT, ltrFrameCount);
579 
580     CHECK_AND_RETURN_RET_LOG(scenario != CodecScenario::CODEC_SCENARIO_ENC_TEMPORAL_SCALABILITY,
581         AVCS_ERR_UNSUPPORT, "Param invalid, not supported to set LTR frame count in temporal scalability scenario");
582 
583     auto ltrCap =
584         capData.featuresMap.find(static_cast<int32_t>(AVCapabilityFeature::VIDEO_ENCODER_LONG_TERM_REFERENCE));
585     if (ltrCap == capData.featuresMap.end()) {
586         AVCODEC_LOGW("Not support LTR but set LTR frame count");
587         format.RemoveKey(Tag::VIDEO_ENCODER_LTR_FRAME_COUNT);
588         return AVCS_ERR_OK;
589     }
590     int32_t maxLTRFrameCount = 0;
591     bool maxLTRFrameCountExist =
592         ltrCap->second.GetIntValue(Tag::FEATURE_PROPERTY_VIDEO_ENCODER_MAX_LTR_FRAME_COUNT, maxLTRFrameCount);
593     CHECK_AND_RETURN_RET_LOG(maxLTRFrameCountExist, AVCS_ERR_UNKNOWN, "Max LTR frame count not defined");
594 
595     CHECK_AND_RETURN_RET_LOG(ltrFrameCount >= 0 && ltrFrameCount <= maxLTRFrameCount, AVCS_ERR_INVALID_VAL,
596         "Param invalid, LTR frame count range: %{public}d-%{public}d", 0, maxLTRFrameCount);
597 
598     return AVCS_ERR_OK;
599 }
600 
ScalingModeChecker(CapabilityData & capData,Format & format,CodecScenario scenario)601 int32_t ScalingModeChecker(CapabilityData &capData, Format &format, CodecScenario scenario)
602 {
603     (void)capData;
604     (void)scenario;
605     int32_t scalingMode;
606     bool scalingModeExist = format.GetIntValue(Tag::VIDEO_SCALE_TYPE, scalingMode);
607     if (!scalingModeExist) {
608         return AVCS_ERR_OK;
609     }
610     PrintParam(scalingModeExist, Tag::VIDEO_SCALE_TYPE, scalingMode);
611 
612     if (scalingMode < static_cast<int32_t>(OHOS::ScalingMode::SCALING_MODE_SCALE_TO_WINDOW) ||
613         scalingMode > static_cast<int32_t>(OHOS::ScalingMode::SCALING_MODE_SCALE_CROP)) {
614         AVCODEC_LOGE("Param invalid, %{public}s: %{public}d", Tag::VIDEO_SCALE_TYPE, scalingMode);
615         return AVCS_ERR_INVALID_VAL;
616     }
617     return AVCS_ERR_OK;
618 }
619 } // namespace
620 
621 namespace OHOS {
622 namespace MediaAVCodec {
CheckConfigureValid(Media::Format & format,const std::string & codecName,CodecScenario scenario)623 int32_t CodecParamChecker::CheckConfigureValid(Media::Format &format, const std::string &codecName,
624                                                CodecScenario scenario)
625 {
626     AVCODEC_SYNC_TRACE;
627     auto capData = CodecAbilitySingleton::GetInstance().GetCapabilityByName(codecName);
628     CHECK_AND_RETURN_RET_LOG(capData != std::nullopt,
629         AVCS_ERR_INVALID_OPERATION, "Get codec capability from codec list failed");
630 
631     auto checkers = CONFIGURE_CHECKERS_TABLE.find(scenario);
632     CHECK_AND_RETURN_RET_LOG(checkers != CONFIGURE_CHECKERS_TABLE.end(), AVCS_ERR_UNSUPPORT,
633         "This scenario can not find any checkers");
634 
635     int32_t result = AVCS_ERR_OK;
636     for (const auto &checker : checkers->second) {
637         auto ret = checker(capData.value(), format, scenario);
638         if (ret == AVCS_ERR_CODEC_PARAM_INCORRECT) {
639             result = AVCS_ERR_CODEC_PARAM_INCORRECT;
640         }
641         CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK || ret == AVCS_ERR_CODEC_PARAM_INCORRECT,
642             ret, "Param check failed");
643     }
644     return result;
645 }
646 
CheckParameterValid(const Media::Format & format,Media::Format & oldFormat,const std::string & codecName,CodecScenario scenario)647 int32_t CodecParamChecker::CheckParameterValid(const Media::Format &format, Media::Format &oldFormat,
648                                                const std::string &codecName, CodecScenario scenario)
649 {
650     AVCODEC_SYNC_TRACE;
651     auto capData = CodecAbilitySingleton::GetInstance().GetCapabilityByName(codecName);
652     CHECK_AND_RETURN_RET_LOG(capData != std::nullopt,
653         AVCS_ERR_INVALID_OPERATION, "Get codec capability from codec list failed");
654 
655     auto checkers = PARAMETER_CHECKERS_TABLE.find(scenario);
656     CHECK_AND_RETURN_RET_LOG(checkers != PARAMETER_CHECKERS_TABLE.end(), AVCS_ERR_UNSUPPORT,
657         "This scenario can not find any checkers");
658 
659     MergeFormat(format, oldFormat);
660 
661     for (const auto &checker : checkers->second) {
662         auto ret = checker(capData.value(), oldFormat, scenario);
663         CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Param check failed");
664     }
665     return AVCS_ERR_OK;
666 }
667 
CheckCodecScenario(const Media::Format & format,AVCodecType codecType,const std::string & codecName)668 std::optional<CodecScenario> CodecParamChecker::CheckCodecScenario(const Media::Format &format, AVCodecType codecType,
669                                                                    const std::string &codecName)
670 {
671     auto capData = CodecAbilitySingleton::GetInstance().GetCapabilityByName(codecName);
672     CHECK_AND_RETURN_RET_LOG(capData != std::nullopt,
673         std::nullopt, "Get codec capability from codec list failed");
674 
675     CodecScenario scenario = CodecScenario::CODEC_SCENARIO_DEC_NORMAL;
676     if (codecType == AVCODEC_TYPE_VIDEO_ENCODER) {
677         scenario = CodecScenario::CODEC_SCENARIO_ENC_NORMAL;
678     }
679 
680     for (const auto& checker : VIDEO_SCENARIO_CHECKER_LIST) {
681         auto ret = checker(capData.value(), format, codecType);
682         if (ret == std::nullopt) {
683             continue;
684         }
685         scenario = ret.value();
686         break;
687     }
688 
689     PrintCodecScenario(scenario);
690     return scenario;
691 }
692 
MergeFormat(const Media::Format & format,Media::Format & oldFormat)693 void CodecParamChecker::MergeFormat(const Media::Format &format, Media::Format &oldFormat)
694 {
695     for (const auto& key : FORMAT_MERGE_LIST) {
696         if (!format.ContainKey(key)) {
697             continue;
698         }
699         auto keyType = format.GetValueType(key);
700         switch (keyType) {
701             case FORMAT_TYPE_INT32: {
702                 int32_t value;
703                 format.GetIntValue(key, value);
704                 oldFormat.PutIntValue(key, value);
705                 break;
706             }
707             case FORMAT_TYPE_INT64: {
708                 int64_t value;
709                 format.GetLongValue(key, value);
710                 oldFormat.PutLongValue(key, value);
711                 break;
712             }
713             case FORMAT_TYPE_FLOAT: {
714                 float value;
715                 format.GetFloatValue(key, value);
716                 oldFormat.PutFloatValue(key, value);
717                 break;
718             }
719             case FORMAT_TYPE_DOUBLE: {
720                 double value;
721                 format.GetDoubleValue(key, value);
722                 oldFormat.PutDoubleValue(key, value);
723                 break;
724             }
725             case FORMAT_TYPE_STRING: {
726                 std::string value;
727                 format.GetStringValue(key, value);
728                 oldFormat.PutStringValue(key, value);
729                 break;
730             }
731             default:
732                 break;
733         }
734     }
735 }
736 } // namespace MediaAVCodec
737 } // namespace OHOS