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