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