1 /*
2  * Copyright (c) 2023-2023 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 "session/video_session.h"
17 
18 #include "camera_error_code.h"
19 #include "camera_log.h"
20 #include "camera_util.h"
21 #include "input/camera_input.h"
22 #include "input/camera_manager.h"
23 #include "output/camera_output_capability.h"
24 
25 namespace OHOS {
26 namespace CameraStandard {
27 namespace {
GeneratePreconfigProfiles1_1(PreconfigType preconfigType)28 std::shared_ptr<PreconfigProfiles> GeneratePreconfigProfiles1_1(PreconfigType preconfigType)
29 {
30     std::shared_ptr<PreconfigProfiles> configs = std::make_shared<PreconfigProfiles>(ColorSpace::BT709);
31     configs->photoProfile = { CameraFormat::CAMERA_FORMAT_JPEG, { .width = 0, .height = 0 } };
32     configs->photoProfile.sizeRatio_ = RATIO_1_1;
33     configs->photoProfile.sizeFollowSensorMax_ = true;
34     switch (preconfigType) {
35         case PRECONFIG_720P:
36             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 720, .height = 720 } };
37             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
38 
39             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
40                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
41             break;
42         case PRECONFIG_1080P:
43             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1080, .height = 1080 } };
44             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
45 
46             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
47                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
48             break;
49         case PRECONFIG_4K:
50             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1080, .height = 1080 } };
51             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
52 
53             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 2160, .height = 2160 },
54                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
55             break;
56         case PRECONFIG_HIGH_QUALITY:
57             configs->colorSpace = ColorSpace::BT2020_HLG_LIMIT;
58             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 1080, .height = 1080 } };
59             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
60 
61             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 2160, .height = 2160 },
62                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
63             break;
64         default:
65             MEDIA_ERR_LOG(
66                 "VideoSession::GeneratePreconfigProfiles1_1 not support this config:%{public}d", preconfigType);
67             return nullptr;
68     }
69     return configs;
70 }
71 
GeneratePreconfigProfiles4_3(PreconfigType preconfigType)72 std::shared_ptr<PreconfigProfiles> GeneratePreconfigProfiles4_3(PreconfigType preconfigType)
73 {
74     std::shared_ptr<PreconfigProfiles> configs = std::make_shared<PreconfigProfiles>(ColorSpace::BT709);
75     configs->photoProfile = { CameraFormat::CAMERA_FORMAT_JPEG, { .width = 0, .height = 0 } };
76     configs->photoProfile.sizeRatio_ = RATIO_4_3;
77     configs->photoProfile.sizeFollowSensorMax_ = true;
78     switch (preconfigType) {
79         case PRECONFIG_720P:
80             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 960, .height = 720 } };
81             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
82 
83             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
84                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
85             break;
86         case PRECONFIG_1080P:
87             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1440, .height = 1080 } };
88             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
89 
90             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
91                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
92             break;
93         case PRECONFIG_4K:
94             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1440, .height = 1080 } };
95             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
96 
97             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 2880, .height = 2160 },
98                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
99             break;
100         case PRECONFIG_HIGH_QUALITY:
101             configs->colorSpace = ColorSpace::BT2020_HLG_LIMIT;
102             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 1440, .height = 1080 } };
103             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
104 
105             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 2880, .height = 2160 },
106                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
107             break;
108         default:
109             MEDIA_ERR_LOG(
110                 "VideoSession::GeneratePreconfigProfiles4_3 not support this config:%{public}d", preconfigType);
111             return nullptr;
112     }
113     return configs;
114 }
115 
GeneratePreconfigProfiles16_9(PreconfigType preconfigType)116 std::shared_ptr<PreconfigProfiles> GeneratePreconfigProfiles16_9(PreconfigType preconfigType)
117 {
118     std::shared_ptr<PreconfigProfiles> configs = std::make_shared<PreconfigProfiles>(ColorSpace::BT709);
119     configs->photoProfile = { CameraFormat::CAMERA_FORMAT_JPEG, { .width = 0, .height = 0 } };
120     configs->photoProfile.sizeRatio_ = RATIO_16_9;
121     configs->photoProfile.sizeFollowSensorMax_ = true;
122     switch (preconfigType) {
123         case PRECONFIG_720P:
124             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1280, .height = 720 } };
125             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
126 
127             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
128                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
129             break;
130         case PRECONFIG_1080P:
131             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1920, .height = 1080 } };
132             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
133 
134             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, configs->previewProfile.size_,
135                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
136             break;
137         case PRECONFIG_4K:
138             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 1920, .height = 1080 } };
139             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
140 
141             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YUV_420_SP, { .width = 3840, .height = 2160 },
142                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
143             break;
144         case PRECONFIG_HIGH_QUALITY:
145             configs->colorSpace = ColorSpace::BT2020_HLG_LIMIT;
146             configs->previewProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 1920, .height = 1080 } };
147             configs->previewProfile.fps_ = { .fixedFps = 30, .minFps = 24, .maxFps = 30 };
148 
149             configs->videoProfile = { CameraFormat::CAMERA_FORMAT_YCRCB_P010, { .width = 3840, .height = 2160 },
150                 { configs->previewProfile.fps_.minFps, configs->previewProfile.fps_.maxFps } };
151             break;
152         default:
153             MEDIA_ERR_LOG(
154                 "VideoSession::GeneratePreconfigProfiles4_3 not support this config:%{public}d", preconfigType);
155             return nullptr;
156     }
157     return configs;
158 }
159 } // namespace
160 
CanAddOutput(sptr<CaptureOutput> & output)161 bool VideoSession::CanAddOutput(sptr<CaptureOutput>& output)
162 {
163     MEDIA_DEBUG_LOG("Enter Into VideoSession::CanAddOutput");
164     CHECK_ERROR_RETURN_RET_LOG(
165         !IsSessionConfiged() || output == nullptr, false, "VideoSession::CanAddOutput operation is Not allowed!");
166     return CaptureSession::CanAddOutput(output);
167 }
168 
GeneratePreconfigProfiles(PreconfigType preconfigType,ProfileSizeRatio preconfigRatio)169 std::shared_ptr<PreconfigProfiles> VideoSession::GeneratePreconfigProfiles(
170     PreconfigType preconfigType, ProfileSizeRatio preconfigRatio)
171 {
172     switch (preconfigRatio) {
173         case RATIO_1_1:
174             return GeneratePreconfigProfiles1_1(preconfigType);
175         case RATIO_4_3:
176             return GeneratePreconfigProfiles4_3(preconfigType);
177         case UNSPECIFIED:
178         // Fall through
179         case RATIO_16_9:
180             return GeneratePreconfigProfiles16_9(preconfigType);
181         default:
182             MEDIA_ERR_LOG("VideoSession::GeneratePreconfigProfiles unknow profile size ratio.");
183             break;
184     }
185     return nullptr;
186 }
187 
IsPreconfigProfilesLegal(std::shared_ptr<PreconfigProfiles> configs)188 bool VideoSession::IsPreconfigProfilesLegal(std::shared_ptr<PreconfigProfiles> configs)
189 {
190     auto cameraList = CameraManager::GetInstance()->GetSupportedCameras();
191     int32_t supportedCameraNum = 0;
192     for (auto& device : cameraList) {
193         MEDIA_INFO_LOG("VideoSession::IsPreconfigProfilesLegal check camera:%{public}s type:%{public}d",
194             device->GetID().c_str(), device->GetCameraType());
195         if (device->GetCameraType() != CAMERA_TYPE_DEFAULT) {
196             continue;
197         }
198         // Check photo
199         bool isPhotoCanPreconfig = IsPhotoProfileLegal(device, configs->photoProfile);
200         CHECK_ERROR_RETURN_RET_LOG(!isPhotoCanPreconfig, false,
201             "VideoSession::IsPreconfigProfilesLegal check photo profile fail, no matched photo profiles:%{public}d "
202             "%{public}dx%{public}d",
203             configs->photoProfile.format_, configs->photoProfile.size_.width, configs->photoProfile.size_.height);
204 
205         // Check preview
206         bool isPreviewCanPreconfig = IsPreviewProfileLegal(device, configs->previewProfile);
207         CHECK_ERROR_RETURN_RET_LOG(!isPreviewCanPreconfig, false,
208             "VideoSession::IsPreconfigProfilesLegal check preview profile fail, no matched preview profiles:%{public}d "
209             "%{public}dx%{public}d",
210             configs->previewProfile.format_, configs->previewProfile.size_.width, configs->previewProfile.size_.height);
211 
212         // Check video
213         auto isVideoCanPreconfig = IsVideoProfileLegal(device, configs->videoProfile);
214         CHECK_ERROR_RETURN_RET_LOG(!isVideoCanPreconfig, false,
215             "VideoSession::IsPreconfigProfilesLegal check video profile fail, no matched video profiles:%{public}d "
216             "%{public}dx%{public}d",
217             configs->videoProfile.format_, configs->videoProfile.size_.width, configs->videoProfile.size_.height);
218         supportedCameraNum++;
219     }
220     MEDIA_INFO_LOG(
221         "VideoSession::IsPreconfigProfilesLegal check pass, supportedCameraNum is%{public}d", supportedCameraNum);
222     return supportedCameraNum > 0;
223 }
224 
IsPhotoProfileLegal(sptr<CameraDevice> & device,Profile & photoProfile)225 bool VideoSession::IsPhotoProfileLegal(sptr<CameraDevice>& device, Profile& photoProfile)
226 {
227     auto photoProfilesIt = device->modePhotoProfiles_.find(SceneMode::VIDEO);
228     CHECK_ERROR_RETURN_RET_LOG(photoProfilesIt == device->modePhotoProfiles_.end(), false,
229         "VideoSession::CanPreconfig check photo profile fail, empty photo profiles");
230     auto photoProfiles = photoProfilesIt->second;
231     return std::any_of(photoProfiles.begin(), photoProfiles.end(), [&photoProfile](auto& profile) {
232         if (!photoProfile.sizeFollowSensorMax_) {
233             return profile == photoProfile;
234         }
235         return IsProfileSameRatio(profile, photoProfile.sizeRatio_, RATIO_VALUE_16_9);
236     });
237 }
238 
IsPreviewProfileLegal(sptr<CameraDevice> & device,Profile & previewProfile)239 bool VideoSession::IsPreviewProfileLegal(sptr<CameraDevice>& device, Profile& previewProfile)
240 {
241     auto previewProfilesIt = device->modePreviewProfiles_.find(SceneMode::VIDEO);
242     CHECK_ERROR_RETURN_RET_LOG(previewProfilesIt == device->modePreviewProfiles_.end(), false,
243         "VideoSession::CanPreconfig check preview profile fail, empty preview profiles");
244     auto previewProfiles = previewProfilesIt->second;
245     return std::any_of(previewProfiles.begin(), previewProfiles.end(),
246         [&previewProfile](auto& profile) { return profile == previewProfile; });
247 }
248 
IsVideoProfileLegal(sptr<CameraDevice> & device,VideoProfile & videoProfile)249 bool VideoSession::IsVideoProfileLegal(sptr<CameraDevice>& device, VideoProfile& videoProfile)
250 {
251     auto videoProfilesIt = device->modeVideoProfiles_.find(SceneMode::VIDEO);
252     CHECK_ERROR_RETURN_RET_LOG(videoProfilesIt == device->modeVideoProfiles_.end(), false,
253         "VideoSession::CanPreconfig check video profile fail, empty video profiles");
254     auto videoProfiles = videoProfilesIt->second;
255     return std::any_of(videoProfiles.begin(), videoProfiles.end(),
256         [&videoProfile](auto& profile) { return profile.IsContains(videoProfile); });
257 }
258 
CanPreconfig(PreconfigType preconfigType,ProfileSizeRatio preconfigRatio)259 bool VideoSession::CanPreconfig(PreconfigType preconfigType, ProfileSizeRatio preconfigRatio)
260 {
261     MEDIA_INFO_LOG(
262         "VideoSession::CanPreconfig check type:%{public}d, check ratio:%{public}d", preconfigType, preconfigRatio);
263     std::shared_ptr<PreconfigProfiles> configs = GeneratePreconfigProfiles(preconfigType, preconfigRatio);
264     CHECK_ERROR_RETURN_RET_LOG(configs == nullptr, false, "VideoSession::CanPreconfig get configs fail.");
265     return IsPreconfigProfilesLegal(configs);
266 }
267 
Preconfig(PreconfigType preconfigType,ProfileSizeRatio preconfigRatio)268 int32_t VideoSession::Preconfig(PreconfigType preconfigType, ProfileSizeRatio preconfigRatio)
269 {
270     MEDIA_INFO_LOG("VideoSession::Preconfig type:%{public}d ratio:%{public}d", preconfigType, preconfigRatio);
271     std::shared_ptr<PreconfigProfiles> configs = GeneratePreconfigProfiles(preconfigType, preconfigRatio);
272     CHECK_ERROR_RETURN_RET_LOG(configs == nullptr, SERVICE_FATL_ERROR,
273         "VideoSession::Preconfig not support this type:%{public}d ratio:%{public}d", preconfigType, preconfigRatio);
274     CHECK_ERROR_RETURN_RET_LOG(
275         !IsPreconfigProfilesLegal(configs), SERVICE_FATL_ERROR, "VideoSession::Preconfig preconfigProfile is illegal.");
276     SetPreconfigProfiles(configs);
277     MEDIA_INFO_LOG("VideoSession::Preconfig %s", configs->ToString().c_str());
278     return SUCCESS;
279 }
280 
CanSetFrameRateRange(int32_t minFps,int32_t maxFps,CaptureOutput * curOutput)281 bool VideoSession::CanSetFrameRateRange(int32_t minFps, int32_t maxFps, CaptureOutput* curOutput)
282 {
283     return CanSetFrameRateRangeForOutput(minFps, maxFps, curOutput) ? true : false;
284 }
285 } // namespace CameraStandard
286 } // namespace OHOS