1 /*
2 * Copyright (c) 2024-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 "hcamera_preconfig.h"
17
18 #include <cstdint>
19 #include <memory>
20 #include <queue>
21 #include <string>
22 #include <utility>
23
24 #include "ability/camera_ability_parse_util.h"
25 #include "camera_stream_info_parse.h"
26 #include "camera_device_ability_items.h"
27 #include "camera_metadata_info.h"
28 #include "hcamera_host_manager.h"
29 #include "metadata_utils.h"
30 #include "v1_3/types.h"
31
32 namespace OHOS {
33 namespace CameraStandard {
34 namespace {
35
36 static constexpr float RATIO_VALUE_1_1 = 1.0f;
37 static constexpr float RATIO_VALUE_4_3 = 4.0f / 3;
38 static constexpr float RATIO_VALUE_16_9 = 16.0f / 9;
39
40 enum PreconfigType {
41 PRECONFIG_TYPE_720P,
42 PRECONFIG_TYPE_1080P,
43 PRECONFIG_TYPE_4K,
44 PRECONFIG_TYPE_HIGH_QUALITY,
45 };
46
47 enum PreconfigRatio {
48 RATIO_1_1,
49 RATIO_4_3,
50 RATIO_16_9,
51 };
52
53 struct CameraInfo {
54 std::string cameraId;
55 std::shared_ptr<OHOS::Camera::CameraMetadata> ability;
56 };
57
58 template<typename T>
GetMaxSizeDetailInfo(std::vector<T> & detailInfos,float targetRatioValue,camera_format_t format)59 std::shared_ptr<T> GetMaxSizeDetailInfo(std::vector<T>& detailInfos, float targetRatioValue, camera_format_t format)
60 {
61 CHECK_ERROR_RETURN_RET(targetRatioValue <= 0, nullptr);
62 std::shared_ptr<T> maxSizeProfile = nullptr;
63 for (auto& detailInfo : detailInfos) {
64 if (detailInfo.width == 0 || detailInfo.height == 0 || detailInfo.format != format) {
65 continue;
66 }
67 float ratio = ((float)detailInfo.width) / detailInfo.height;
68 if (abs(ratio - targetRatioValue) / targetRatioValue > 0.05f) { // 0.05f is 5% tolerance.
69 continue;
70 }
71 if (maxSizeProfile == nullptr || detailInfo.width > maxSizeProfile->width) {
72 maxSizeProfile = std::make_shared<T>(detailInfo);
73 }
74 }
75 return maxSizeProfile;
76 }
77
78 struct PreconfigProfile {
79 std::string format;
80 int32_t width;
81 int32_t height;
82 int32_t fpsMin;
83 int32_t fpsMax;
84 int32_t fpsPrefer;
85 bool followSensorMax = false;
86 PreconfigRatio followSensorMaxRatio = RATIO_4_3;
87
toStringOHOS::CameraStandard::__anon1ca33ed60110::PreconfigProfile88 std::string toString()
89 {
90 return "Format:" + format + "\tSize:" + std::to_string(width) + "x" + std::to_string(height) +
91 "\tFps:" + std::to_string(fpsMin) + "-" + std::to_string(fpsMax) +
92 ",prefer:" + std::to_string(fpsPrefer);
93 }
94
GetRatioValueOHOS::CameraStandard::__anon1ca33ed60110::PreconfigProfile95 float GetRatioValue(PreconfigRatio preconfigRatio)
96 {
97 float ratioValue = RATIO_VALUE_4_3;
98 switch (preconfigRatio) {
99 case RATIO_1_1:
100 ratioValue = RATIO_VALUE_1_1;
101 break;
102 case RATIO_4_3:
103 ratioValue = RATIO_VALUE_4_3;
104 break;
105 case RATIO_16_9:
106 ratioValue = RATIO_VALUE_16_9;
107 break;
108 default:
109 // Do nothing
110 break;
111 }
112 return ratioValue;
113 }
114
FindMaxDetailInfoFromProfileLevelOHOS::CameraStandard::__anon1ca33ed60110::PreconfigProfile115 std::shared_ptr<ProfileDetailInfo> FindMaxDetailInfoFromProfileLevel(
116 CameraInfo& cameraInfo, HDI::Camera::V1_3::OperationMode modeName)
117 {
118 camera_metadata_item_t item;
119 int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
120 cameraInfo.ability->get(), OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL, &item);
121 CHECK_ERROR_RETURN_RET(ret != CAM_META_SUCCESS || item.count == 0, nullptr);
122 std::vector<SpecInfo> specInfos;
123 ProfileLevelInfo modeInfo = {};
124 CameraAbilityParseUtil::GetModeInfo(modeName, item, modeInfo);
125 specInfos.insert(specInfos.end(), modeInfo.specInfos.begin(), modeInfo.specInfos.end());
126 for (SpecInfo& specInfo : specInfos) {
127 for (StreamInfo& streamInfo : specInfo.streamInfos) {
128 if (streamInfo.streamType != HDI::Camera::V1_3::StreamType::STREAM_TYPE_STILL_CAPTURE) {
129 continue;
130 }
131 float ratioValue = GetRatioValue(followSensorMaxRatio);
132 return GetMaxSizeDetailInfo(streamInfo.detailInfos, ratioValue, OHOS_CAMERA_FORMAT_JPEG);
133 }
134 }
135 return nullptr;
136 }
137
FindMaxDetailInfoFromExtendConfigOHOS::CameraStandard::__anon1ca33ed60110::PreconfigProfile138 std::shared_ptr<DetailInfo> FindMaxDetailInfoFromExtendConfig(
139 CameraInfo& cameraInfo, HDI::Camera::V1_3::OperationMode modeName)
140 {
141 camera_metadata_item_t item;
142 int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
143 cameraInfo.ability->get(), OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS, &item);
144 CHECK_ERROR_RETURN_RET(ret != CAM_META_SUCCESS || item.count == 0, nullptr);
145 ExtendInfo extendInfo = {};
146 std::shared_ptr<CameraStreamInfoParse> modeStreamParse = std::make_shared<CameraStreamInfoParse>();
147 modeStreamParse->getModeInfo(item.data.i32, item.count, extendInfo); // 解析tag中带的数据信息意义
148 for (auto& modeInfo : extendInfo.modeInfo) {
149 if (modeInfo.modeName != modeName) {
150 continue;
151 }
152 for (auto& streamInfo : modeInfo.streamInfo) {
153 if (streamInfo.streamType != HDI::Camera::V1_3::StreamType::STREAM_TYPE_STILL_CAPTURE) {
154 continue;
155 }
156 float ratioValue = GetRatioValue(followSensorMaxRatio);
157 return GetMaxSizeDetailInfo(streamInfo.detailInfo, ratioValue, OHOS_CAMERA_FORMAT_JPEG);
158 }
159 }
160 return nullptr;
161 }
162
toStringOHOS::CameraStandard::__anon1ca33ed60110::PreconfigProfile163 std::string toString(std::vector<CameraInfo>& cameraInfos, HDI::Camera::V1_3::OperationMode modeName)
164 {
165 if (!followSensorMax) {
166 return toString();
167 }
168 std::string maxSizeInfo = "";
169 for (auto& cameraInfo : cameraInfos) {
170 camera_metadata_item_t item;
171 int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
172 cameraInfo.ability->get(), OHOS_ABILITY_CAMERA_TYPE, &item);
173 if (ret != CAM_META_SUCCESS || item.count == 0) {
174 return "device camera type info error";
175 }
176 camera_type_enum_t cameraType = static_cast<camera_type_enum_t>(item.data.u8[0]);
177 if (cameraType != OHOS_CAMERA_TYPE_UNSPECIFIED) {
178 continue;
179 }
180 auto maxDetail = FindMaxDetailInfoFromProfileLevel(cameraInfo, modeName);
181 if (maxDetail) {
182 maxSizeInfo += std::to_string(maxDetail->width) + "x" + std::to_string(maxDetail->height) + "(" +
183 cameraInfo.cameraId + ") ";
184 continue;
185 }
186 auto maxDetailInfo = FindMaxDetailInfoFromExtendConfig(cameraInfo, modeName);
187 if (maxDetailInfo == nullptr) {
188 continue;
189 }
190 maxSizeInfo += std::to_string(maxDetailInfo->width) + "x" + std::to_string(maxDetailInfo->height) + "(" +
191 cameraInfo.cameraId + ") ";
192 }
193 return "Format:" + format + "\tSize:" + maxSizeInfo + "\tFps:" + std::to_string(fpsMin) + "-" +
194 std::to_string(fpsMax) + ",prefer:" + std::to_string(fpsPrefer);
195 }
196 };
197
198 struct PhotoSessionPreconfig {
199 std::string colorSpace;
200 PreconfigProfile previewProfile;
201 PreconfigProfile photoProfile;
202 };
203
204 struct VideoSessionPreconfig {
205 std::string colorSpace;
206 PreconfigProfile previewProfile;
207 PreconfigProfile photoProfile;
208 PreconfigProfile videoProfile;
209 };
210
GeneratePhotoSessionPreconfigRatio1v1(PreconfigType preconfigType)211 PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio1v1(PreconfigType preconfigType)
212 {
213 PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
214 switch (preconfigType) {
215 case PRECONFIG_TYPE_720P:
216 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 720, 720, 12, 30, 30 };
217 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 720, 720, 0, 0, 0 };
218 break;
219 case PRECONFIG_TYPE_1080P:
220 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 12, 30, 30 };
221 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1080, 1080, 0, 0, 0 };
222 break;
223 case PRECONFIG_TYPE_4K:
224 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 12, 30, 30 };
225 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2160, 2160, 0, 0, 0 };
226 break;
227 case PRECONFIG_TYPE_HIGH_QUALITY:
228 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1440, 12, 30, 30 };
229 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_1_1 };
230 break;
231 default:
232 return sessionPreconfig;
233 }
234 return sessionPreconfig;
235 };
236
GeneratePhotoSessionPreconfigRatio4v3(PreconfigType preconfigType)237 PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio4v3(PreconfigType preconfigType)
238 {
239 PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
240 switch (preconfigType) {
241 case PRECONFIG_TYPE_720P:
242 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 960, 720, 12, 30, 30 };
243 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 960, 720, 0, 0, 0 };
244 break;
245 case PRECONFIG_TYPE_1080P:
246 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 12, 30, 30 };
247 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1440, 1080, 0, 0, 0 };
248 break;
249 case PRECONFIG_TYPE_4K:
250 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 12, 30, 30 };
251 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2880, 2160, 0, 0, 0 };
252 break;
253 case PRECONFIG_TYPE_HIGH_QUALITY:
254 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1440, 12, 30, 30 };
255 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_4_3 };
256 break;
257 default:
258 return sessionPreconfig;
259 }
260 return sessionPreconfig;
261 };
262
GeneratePhotoSessionPreconfigRatio16v9(PreconfigType preconfigType)263 PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio16v9(PreconfigType preconfigType)
264 {
265 PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
266 switch (preconfigType) {
267 case PRECONFIG_TYPE_720P:
268 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1280, 720, 12, 30, 30 };
269 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1280, 720, 0, 0, 0 };
270 break;
271 case PRECONFIG_TYPE_1080P:
272 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 12, 30, 30 };
273 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1920, 1080, 0, 0, 0 };
274 break;
275 case PRECONFIG_TYPE_4K:
276 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 12, 30, 30 };
277 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 3840, 2160, 0, 0, 0 };
278 break;
279 case PRECONFIG_TYPE_HIGH_QUALITY:
280 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 2560, 1440, 12, 30, 30 };
281 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_16_9 };
282 break;
283 default:
284 return sessionPreconfig;
285 }
286 return sessionPreconfig;
287 };
288
GenerateVideoSessionPreconfigRatio1v1(PreconfigType preconfigType)289 VideoSessionPreconfig GenerateVideoSessionPreconfigRatio1v1(PreconfigType preconfigType)
290 {
291 VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
292 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2304, 2304, 0, 0, 0 };
293 switch (preconfigType) {
294 case PRECONFIG_TYPE_720P:
295 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 720, 720, 24, 30, 30 };
296 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
297 break;
298 case PRECONFIG_TYPE_1080P:
299 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 24, 30, 30 };
300 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
301 break;
302 case PRECONFIG_TYPE_4K:
303 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 24, 30, 30 };
304 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 2160, 2160, 24, 30, 30 };
305 break;
306 case PRECONFIG_TYPE_HIGH_QUALITY:
307 sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
308 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1080, 1080, 24, 30, 30 };
309 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 2160, 2160, 24, 30, 30 };
310 break;
311 default:
312 return sessionPreconfig;
313 }
314 return sessionPreconfig;
315 };
316
GenerateVideoSessionPreconfigRatio4v3(PreconfigType preconfigType)317 VideoSessionPreconfig GenerateVideoSessionPreconfigRatio4v3(PreconfigType preconfigType)
318 {
319 VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
320 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 3072, 2304, 0, 0, 0 };
321 switch (preconfigType) {
322 case PRECONFIG_TYPE_720P:
323 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 960, 720, 24, 30, 30 };
324 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
325 break;
326 case PRECONFIG_TYPE_1080P:
327 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 24, 30, 30 };
328 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
329 break;
330 case PRECONFIG_TYPE_4K:
331 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 24, 30, 30 };
332 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 2880, 2160, 24, 30, 30 };
333 break;
334 case PRECONFIG_TYPE_HIGH_QUALITY:
335 sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
336 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1440, 1080, 24, 30, 30 };
337 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 2880, 2160, 24, 30, 30 };
338 break;
339 default:
340 return sessionPreconfig;
341 }
342 return sessionPreconfig;
343 };
344
GenerateVideoSessionPreconfigRatio16v9(PreconfigType preconfigType)345 VideoSessionPreconfig GenerateVideoSessionPreconfigRatio16v9(PreconfigType preconfigType)
346 {
347 VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
348 sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 4096, 2304, 0, 0, 0 };
349 switch (preconfigType) {
350 case PRECONFIG_TYPE_720P:
351 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1280, 720, 24, 30, 30 };
352 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
353 break;
354 case PRECONFIG_TYPE_1080P:
355 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 24, 30, 30 };
356 sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
357 break;
358 case PRECONFIG_TYPE_4K:
359 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 24, 30, 30 };
360 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 3840, 2160, 24, 30, 30 };
361 break;
362 case PRECONFIG_TYPE_HIGH_QUALITY:
363 sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
364 sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1920, 1080, 12, 30, 30 };
365 sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 3840, 2160, 24, 30, 30 };
366 sessionPreconfig.photoProfile.followSensorMax = true;
367 sessionPreconfig.photoProfile.followSensorMaxRatio = RATIO_16_9;
368 break;
369 default:
370 return sessionPreconfig;
371 }
372 return sessionPreconfig;
373 };
374 } // namespace
375
DumpPreconfigInfo(CameraInfoDumper & infoDumper,sptr<HCameraHostManager> & hostManager)376 void DumpPreconfigInfo(CameraInfoDumper& infoDumper, sptr<HCameraHostManager>& hostManager)
377 {
378 std::map<PreconfigType, std::string> preconfigTypeMap = { { PRECONFIG_TYPE_720P, "PRECONFIG_720P" },
379 { PRECONFIG_TYPE_1080P, "PRECONFIG_1080P" }, { PRECONFIG_TYPE_4K, "PRECONFIG_4K" },
380 { PRECONFIG_TYPE_HIGH_QUALITY, "PRECONFIG_HIGH_QUALITY" } };
381 std::map<PreconfigRatio, std::string> preconfigRatioMap = { { RATIO_1_1, "ratio 1:1" }, { RATIO_4_3, "ratio 4:3" },
382 { RATIO_16_9, "ratio 16:9" } };
383 std::vector<std::string> cameraIds;
384 std::vector<CameraInfo> cameraInfos;
385 hostManager->GetCameras(cameraIds);
386 for (auto& cameraId : cameraIds) {
387 CameraInfo cameraInfo { .cameraId = cameraId };
388 hostManager->GetCameraAbility(cameraId, cameraInfo.ability);
389 cameraInfos.emplace_back(cameraInfo);
390 }
391 for (const auto& typePair : preconfigTypeMap) {
392 for (const auto& ratioPair : preconfigRatioMap) {
393 PhotoSessionPreconfig photoPreconfig;
394 VideoSessionPreconfig videoPreconfig;
395 switch (ratioPair.first) {
396 case RATIO_1_1:
397 photoPreconfig = GeneratePhotoSessionPreconfigRatio1v1(typePair.first);
398 videoPreconfig = GenerateVideoSessionPreconfigRatio1v1(typePair.first);
399 break;
400 case RATIO_4_3:
401 photoPreconfig = GeneratePhotoSessionPreconfigRatio4v3(typePair.first);
402 videoPreconfig = GenerateVideoSessionPreconfigRatio4v3(typePair.first);
403 break;
404 case RATIO_16_9:
405 photoPreconfig = GeneratePhotoSessionPreconfigRatio16v9(typePair.first);
406 videoPreconfig = GenerateVideoSessionPreconfigRatio16v9(typePair.first);
407 break;
408 default:
409 // Do nothing.
410 break;
411 }
412 infoDumper.Title(typePair.second + " " + ratioPair.second + " :");
413 infoDumper.Push();
414 infoDumper.Title("PhotoSession:");
415 infoDumper.Msg("Colorspace:" + photoPreconfig.colorSpace);
416 infoDumper.Msg("[Preview]\t" + photoPreconfig.previewProfile.toString());
417 infoDumper.Msg("[Photo]\t" + photoPreconfig.photoProfile.toString(cameraInfos, HDI::Camera::V1_3::CAPTURE));
418 infoDumper.Title("VideoSession:");
419 infoDumper.Msg("Colorspace:" + videoPreconfig.colorSpace);
420 infoDumper.Msg("[Preview]\t" + videoPreconfig.previewProfile.toString());
421 infoDumper.Msg("[Video]\t" + videoPreconfig.videoProfile.toString());
422 infoDumper.Msg("[Photo]\t" + videoPreconfig.photoProfile.toString(cameraInfos, HDI::Camera::V1_3::VIDEO));
423 infoDumper.Pop();
424 }
425 }
426 }
427 } // namespace CameraStandard
428 } // namespace OHOS
429