* Copyright (c) 2024-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hcamera_preconfig.h"
#include <cstdint>
#include <memory>
#include <queue>
#include <string>
#include <utility>
#include "ability/camera_ability_parse_util.h"
#include "camera_stream_info_parse.h"
#include "camera_device_ability_items.h"
#include "camera_metadata_info.h"
#include "hcamera_host_manager.h"
#include "metadata_utils.h"
#include "v1_3/types.h"
#include "v1_5/types.h"
namespace OHOS {
namespace CameraStandard {
namespace {
static constexpr float RATIO_VALUE_1_1 = 1.0f;
static constexpr float RATIO_VALUE_4_3 = 4.0f / 3;
static constexpr float RATIO_VALUE_16_9 = 16.0f / 9;
enum PreconfigType {
PRECONFIG_TYPE_720P,
PRECONFIG_TYPE_1080P,
PRECONFIG_TYPE_4K,
PRECONFIG_TYPE_HIGH_QUALITY,
PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020,
};
enum PreconfigRatio {
RATIO_1_1,
RATIO_4_3,
RATIO_16_9,
};
std::map<PreconfigType, std::string> preconfigTypeMap = {
{PRECONFIG_TYPE_720P, "PRECONFIG_720P"}, {PRECONFIG_TYPE_1080P, "PRECONFIG_1080P"},
{PRECONFIG_TYPE_4K, "PRECONFIG_4K"}, {PRECONFIG_TYPE_HIGH_QUALITY, "PRECONFIG_HIGH_QUALITY"},
{PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020, "PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020"}
};
std::map<PreconfigRatio, std::string> preconfigRatioMap = {
{RATIO_1_1, "ratio 1:1"}, {RATIO_4_3, "ratio 4:3"}, {RATIO_16_9, "ratio 16:9"}
};
struct CameraInfo {
std::string cameraId;
std::shared_ptr<OHOS::Camera::CameraMetadata> ability;
};
template<typename T>
std::shared_ptr<T> GetMaxSizeDetailInfo(std::vector<T>& detailInfos, float targetRatioValue, camera_format_t format)
{
CHECK_RETURN_RET(targetRatioValue <= 0, nullptr);
std::shared_ptr<T> maxSizeProfile = nullptr;
for (auto& detailInfo : detailInfos) {
CHECK_CONTINUE(detailInfo.width == 0 || detailInfo.height == 0 || detailInfo.format != format);
float ratio = ((float)detailInfo.width) / detailInfo.height;
if (abs(ratio - targetRatioValue) / targetRatioValue > 0.05f) {
continue;
}
bool isNewSizeProfile = maxSizeProfile == nullptr || detailInfo.width > maxSizeProfile->width;
if (isNewSizeProfile) {
maxSizeProfile = std::make_shared<T>(detailInfo);
}
}
return maxSizeProfile;
}
struct PreconfigProfile {
std::string format;
int32_t width;
int32_t height;
int32_t fpsMin;
int32_t fpsMax;
int32_t fpsPrefer;
bool followSensorMax = false;
PreconfigRatio followSensorMaxRatio = RATIO_4_3;
std::string toString()
{
return "Format:" + format + "\tSize:" + std::to_string(width) + "x" + std::to_string(height) +
"\tFps:" + std::to_string(fpsMin) + "-" + std::to_string(fpsMax) +
",prefer:" + std::to_string(fpsPrefer);
}
float GetRatioValue(PreconfigRatio preconfigRatio)
{
float ratioValue = RATIO_VALUE_4_3;
switch (preconfigRatio) {
case RATIO_1_1:
ratioValue = RATIO_VALUE_1_1;
break;
case RATIO_4_3:
ratioValue = RATIO_VALUE_4_3;
break;
case RATIO_16_9:
ratioValue = RATIO_VALUE_16_9;
break;
default:
break;
}
return ratioValue;
}
std::shared_ptr<ProfileDetailInfo> FindMaxDetailInfoFromProfileLevel(
CameraInfo& cameraInfo, HDI::Camera::V1_3::OperationMode modeName)
{
camera_metadata_item_t item;
int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
cameraInfo.ability->get(), OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL, &item);
CHECK_RETURN_RET(ret != CAM_META_SUCCESS || item.count == 0, nullptr);
std::vector<SpecInfo> specInfos;
ProfileLevelInfo modeInfo = {};
CameraAbilityParseUtil::GetModeInfo(modeName, item, modeInfo);
specInfos.insert(specInfos.end(), modeInfo.specInfos.begin(), modeInfo.specInfos.end());
for (SpecInfo& specInfo : specInfos) {
for (StreamInfo& streamInfo : specInfo.streamInfos) {
CHECK_CONTINUE(streamInfo.streamType != HDI::Camera::V1_3::StreamType::STREAM_TYPE_STILL_CAPTURE);
float ratioValue = GetRatioValue(followSensorMaxRatio);
return GetMaxSizeDetailInfo(streamInfo.detailInfos, ratioValue, OHOS_CAMERA_FORMAT_JPEG);
}
}
return nullptr;
}
std::shared_ptr<DetailInfo> FindMaxDetailInfoFromExtendConfig(
CameraInfo& cameraInfo, HDI::Camera::V1_3::OperationMode modeName)
{
camera_metadata_item_t item;
int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
cameraInfo.ability->get(), OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS, &item);
CHECK_RETURN_RET(ret != CAM_META_SUCCESS || item.count == 0, nullptr);
ExtendInfo extendInfo = {};
std::shared_ptr<CameraStreamInfoParse> modeStreamParse = std::make_shared<CameraStreamInfoParse>();
modeStreamParse->getModeInfo(item.data.i32, item.count, extendInfo);
for (auto& modeInfo : extendInfo.modeInfo) {
CHECK_CONTINUE(modeInfo.modeName != modeName);
for (auto& streamInfo : modeInfo.streamInfo) {
CHECK_CONTINUE(streamInfo.streamType != HDI::Camera::V1_3::StreamType::STREAM_TYPE_STILL_CAPTURE);
float ratioValue = GetRatioValue(followSensorMaxRatio);
return GetMaxSizeDetailInfo(streamInfo.detailInfo, ratioValue, OHOS_CAMERA_FORMAT_JPEG);
}
}
return nullptr;
}
std::string toString(std::vector<CameraInfo>& cameraInfos, HDI::Camera::V1_3::OperationMode modeName)
{
CHECK_RETURN_RET(!followSensorMax, toString());
std::string maxSizeInfo = "";
for (auto& cameraInfo : cameraInfos) {
camera_metadata_item_t item;
int ret = OHOS::Camera::CameraMetadata::FindCameraMetadataItem(
cameraInfo.ability->get(), OHOS_ABILITY_CAMERA_TYPE, &item);
CHECK_RETURN_RET(ret != CAM_META_SUCCESS || item.count == 0, "device camera type info error");
camera_type_enum_t cameraType = static_cast<camera_type_enum_t>(item.data.u8[0]);
CHECK_CONTINUE(cameraType != OHOS_CAMERA_TYPE_UNSPECIFIED);
auto maxDetail = FindMaxDetailInfoFromProfileLevel(cameraInfo, modeName);
if (maxDetail) {
maxSizeInfo += std::to_string(maxDetail->width) + "x" + std::to_string(maxDetail->height) + "(" +
cameraInfo.cameraId + ") ";
continue;
}
auto maxDetailInfo = FindMaxDetailInfoFromExtendConfig(cameraInfo, modeName);
CHECK_CONTINUE(maxDetailInfo == nullptr);
maxSizeInfo += std::to_string(maxDetailInfo->width) + "x" + std::to_string(maxDetailInfo->height) + "(" +
cameraInfo.cameraId + ") ";
}
return "Format:" + format + "\tSize:" + maxSizeInfo + "\tFps:" + std::to_string(fpsMin) + "-" +
std::to_string(fpsMax) + ",prefer:" + std::to_string(fpsPrefer);
}
};
struct PhotoSessionPreconfig {
std::string colorSpace;
PreconfigProfile previewProfile;
PreconfigProfile photoProfile;
};
struct VideoSessionPreconfig {
std::string colorSpace;
PreconfigProfile previewProfile;
PreconfigProfile photoProfile;
PreconfigProfile videoProfile;
};
PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio1v1(PreconfigType preconfigType)
{
PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 720, 720, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 720, 720, 0, 0, 0 };
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1080, 1080, 0, 0, 0 };
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2160, 2160, 0, 0, 0 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_1_1 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020:
sessionPreconfig.colorSpace = "BT2020_HLG";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1440, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_1_1 };
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio4v3(PreconfigType preconfigType)
{
PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 960, 720, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 960, 720, 0, 0, 0 };
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1440, 1080, 0, 0, 0 };
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2880, 2160, 0, 0, 0 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_4_3 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020:
sessionPreconfig.colorSpace = "BT2020_HLG";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1920, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_4_3 };
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
PhotoSessionPreconfig GeneratePhotoSessionPreconfigRatio16v9(PreconfigType preconfigType)
{
PhotoSessionPreconfig sessionPreconfig { .colorSpace = "P3" };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1280, 720, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1280, 720, 0, 0, 0 };
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 1920, 1080, 0, 0, 0 };
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 3840, 2160, 0, 0, 0 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 2560, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_16_9 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020:
sessionPreconfig.colorSpace = "BT2020_HLG";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 2560, 1440, 12, 30, 30 };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 0, 0, 0, 0, 0, true, RATIO_16_9 };
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
VideoSessionPreconfig GenerateVideoSessionPreconfigRatio1v1(PreconfigType preconfigType)
{
VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 2304, 2304, 0, 0, 0 };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 720, 720, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1080, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 2160, 2160, 24, 30, 30 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1080, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 2160, 2160, 24, 30, 30 };
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
VideoSessionPreconfig GenerateVideoSessionPreconfigRatio4v3(PreconfigType preconfigType)
{
VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 3072, 2304, 0, 0, 0 };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 960, 720, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1440, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 2880, 2160, 24, 30, 30 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1440, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 2880, 2160, 24, 30, 30 };
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
VideoSessionPreconfig GenerateVideoSessionPreconfigRatio16v9(PreconfigType preconfigType)
{
VideoSessionPreconfig sessionPreconfig { .colorSpace = "BT709" };
sessionPreconfig.photoProfile = { "CAMERA_FORMAT_JPEG", 4096, 2304, 0, 0, 0 };
switch (preconfigType) {
case PRECONFIG_TYPE_720P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1280, 720, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_1080P:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = sessionPreconfig.previewProfile;
break;
case PRECONFIG_TYPE_4K:
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YUV_420_SP", 1920, 1080, 24, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YUV_420_SP", 3840, 2160, 24, 30, 30 };
break;
case PRECONFIG_TYPE_HIGH_QUALITY:
sessionPreconfig.colorSpace = "BT2020_HLG_LIMIT";
sessionPreconfig.previewProfile = { "CAMERA_FORMAT_YCRCB_P010", 1920, 1080, 12, 30, 30 };
sessionPreconfig.videoProfile = { "CAMERA_FORMAT_YCRCB_P010", 3840, 2160, 24, 30, 30 };
sessionPreconfig.photoProfile.followSensorMax = true;
sessionPreconfig.photoProfile.followSensorMaxRatio = RATIO_16_9;
break;
default:
return sessionPreconfig;
}
return sessionPreconfig;
};
}
void DumpPreconfigInfo(CameraInfoDumper& infoDumper, sptr<HCameraHostManager>& hostManager)
{
std::vector<std::string> cameraIds;
std::vector<CameraInfo> cameraInfos;
hostManager->GetCameras(cameraIds);
for (auto& cameraId : cameraIds) {
CameraInfo cameraInfo { .cameraId = cameraId };
hostManager->GetCameraAbility(cameraId, cameraInfo.ability);
cameraInfos.emplace_back(cameraInfo);
}
for (const auto& typePair : preconfigTypeMap) {
for (const auto& ratioPair : preconfigRatioMap) {
PhotoSessionPreconfig photoPreconfig;
VideoSessionPreconfig videoPreconfig;
switch (ratioPair.first) {
case RATIO_1_1:
photoPreconfig = GeneratePhotoSessionPreconfigRatio1v1(typePair.first);
videoPreconfig = GenerateVideoSessionPreconfigRatio1v1(typePair.first);
break;
case RATIO_4_3:
photoPreconfig = GeneratePhotoSessionPreconfigRatio4v3(typePair.first);
videoPreconfig = GenerateVideoSessionPreconfigRatio4v3(typePair.first);
break;
case RATIO_16_9:
photoPreconfig = GeneratePhotoSessionPreconfigRatio16v9(typePair.first);
videoPreconfig = GenerateVideoSessionPreconfigRatio16v9(typePair.first);
break;
default:
break;
}
infoDumper.Title(typePair.second + " " + ratioPair.second + " :");
infoDumper.Push();
infoDumper.Title("PhotoSession:");
infoDumper.Msg("Colorspace:" + photoPreconfig.colorSpace);
infoDumper.Msg("[Preview]\t" + photoPreconfig.previewProfile.toString());
infoDumper.Msg("[Photo]\t" + photoPreconfig.photoProfile.toString(cameraInfos, HDI::Camera::V1_3::CAPTURE));
infoDumper.Title("VideoSession:");
if (typePair.first != PreconfigType::PRECONFIG_TYPE_HIGH_QUALITY_PHOTOSESSION_BT2020) {
infoDumper.Msg("Colorspace:" + videoPreconfig.colorSpace);
infoDumper.Msg("[Preview]\t" + videoPreconfig.previewProfile.toString());
infoDumper.Msg("[Video]\t" + videoPreconfig.videoProfile.toString());
infoDumper.Msg("[Photo]\t" +
videoPreconfig.photoProfile.toString(cameraInfos, HDI::Camera::V1_3::VIDEO));
} else {
infoDumper.Msg("Not Supported");
}
infoDumper.Pop();
}
}
}
}
}