1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "SharedSessionConfigUtils"
18
19 #include "SharedSessionConfigUtils.h"
20
21 #include <inttypes.h>
22 #include <sstream>
23 #include <utils/Log.h>
24
25 namespace android {
26
toString(ErrorCode errorCode)27 const char* SharedSessionConfigUtils::toString(ErrorCode errorCode) {
28 switch (errorCode) {
29 case ErrorCode::STATUS_OK:
30 return "STATUS_OK";
31 case ErrorCode::ERROR_READ_CONFIG_FILE:
32 return "ERROR_READ_CONFIG_FILE";
33 case ErrorCode::ERROR_CONFIG_FILE_FORMAT:
34 return "ERROR_CONFIG_FILE_FORMAT";
35 case ErrorCode::ERROR_CONFIG_READER_UNINITIALIZED:
36 return "ERROR_CONFIG_READER_UNINITIALIZED";
37 case ErrorCode::ERROR_BAD_PARAMETER:
38 return "ERROR_BAD_PARAMETER";
39 default:
40 ALOGE("%s: Called toString on an unknown ErrorCode. This should never happen",
41 __FUNCTION__);
42 return "";
43 }
44 }
45
getColorSpaceFromStr(const char * colorSpaceStr,int32_t * colorSpace)46 ErrorCode SharedSessionConfigUtils::getColorSpaceFromStr(const char* colorSpaceStr,
47 /* out */ int32_t* colorSpace) {
48 if (colorSpaceStr == nullptr || !strcmp(colorSpaceStr, "")) {
49 *colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED;
50 return ErrorCode::STATUS_OK;
51 }
52
53 int32_t colorSpaceInt = (int32_t) std::strtol(colorSpaceStr, nullptr, 0);
54 if (VALID_COLOR_SPACES.find(colorSpaceInt) == VALID_COLOR_SPACES.end()) {
55 ALOGE("%s: colorSpace %" PRId32 " is invalid: ", __FUNCTION__, colorSpaceInt);
56 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_COLOR_SPACES).c_str());
57 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
58 }
59
60 *colorSpace = colorSpaceInt;
61 return ErrorCode::STATUS_OK;
62 }
63
getSurfaceTypeFromXml(const XMLElement * surfaceTypeXml,int64_t * surfaceType)64 ErrorCode SharedSessionConfigUtils::getSurfaceTypeFromXml(const XMLElement* surfaceTypeXml,
65 /* out */ int64_t* surfaceType) {
66 if (surfaceTypeXml == nullptr || surfaceTypeXml->GetText() == nullptr
67 || !strcmp(surfaceTypeXml->GetText(), "")) {
68 ALOGE("%s: surface type field must be populated", __FUNCTION__);
69 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
70 }
71
72 int64_t surfaceTypeInt = std::strtol(surfaceTypeXml->GetText(), nullptr, 0);
73 if (VALID_SURFACE_TYPES.find(surfaceTypeInt) == VALID_SURFACE_TYPES.end()) {
74 ALOGE("%s: surfaceType %" PRId64 " is invalid: ", __FUNCTION__, surfaceTypeInt);
75 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_SURFACE_TYPES).c_str());
76 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
77 }
78
79 *surfaceType = surfaceTypeInt;
80 return ErrorCode::STATUS_OK;
81 }
82
getWidthFromXml(const XMLElement * widthXml,int64_t * width)83 ErrorCode SharedSessionConfigUtils::getWidthFromXml(const XMLElement* widthXml,
84 /* out */ int64_t* width) {
85 if (widthXml == nullptr || widthXml->GetText() == nullptr
86 || !strcmp(widthXml->GetText(), "")) {
87 ALOGE("%s: width field must be populated", __FUNCTION__);
88 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
89 }
90
91 const char* widthStr = widthXml->GetText();
92 *width = std::strtol(widthStr, nullptr, 0);
93 if (*width <= 0) {
94 ALOGE("%s: width value is invalid", __FUNCTION__);
95 }
96
97 return ErrorCode::STATUS_OK;
98 }
99
getHeightFromXml(const XMLElement * heightXml,int64_t * height)100 ErrorCode SharedSessionConfigUtils::getHeightFromXml(const XMLElement* heightXml,
101 /* out */ int64_t* height) {
102 if (heightXml == nullptr || heightXml->GetText() == nullptr
103 || !strcmp(heightXml->GetText(), "")) {
104 ALOGE("%s: height field must be populated", __FUNCTION__);
105 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
106 }
107
108 const char* heightStr = heightXml->GetText();
109 *height = std::strtol(heightStr, nullptr, 0);
110 if (*height <= 0) {
111 ALOGE("%s: height value is invalid", __FUNCTION__);
112 }
113
114 return ErrorCode::STATUS_OK;
115 }
116
getPhysicalCameraIdFromXml(const XMLElement * physicalCameraIdXml,std::string * physicalCameraId)117 ErrorCode SharedSessionConfigUtils::getPhysicalCameraIdFromXml(
118 const XMLElement* physicalCameraIdXml, /* out */ std::string* physicalCameraId) {
119 *physicalCameraId =
120 (physicalCameraIdXml == nullptr || physicalCameraIdXml->GetText() == nullptr)
121 ? "": physicalCameraIdXml->GetText();
122 return ErrorCode::STATUS_OK;
123 }
124
getStreamUseCaseFromXml(const XMLElement * streamUseCaseXml,int64_t * streamUseCase)125 ErrorCode SharedSessionConfigUtils::getStreamUseCaseFromXml(const XMLElement* streamUseCaseXml,
126 /* out */ int64_t* streamUseCase) {
127 if (streamUseCaseXml == nullptr || streamUseCaseXml->GetText() == nullptr
128 || !strcmp(streamUseCaseXml->GetText(), "")) {
129 *streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
130 return ErrorCode::STATUS_OK;
131 }
132
133 int64_t streamUseCaseInt = std::strtol(streamUseCaseXml->GetText(), nullptr, 0);
134 if (VALID_STREAM_USE_CASES.find(streamUseCaseInt) == VALID_STREAM_USE_CASES.end()) {
135 ALOGE("%s: streamUseCase %" PRId64 " is invalid: ", __FUNCTION__, streamUseCaseInt);
136 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_STREAM_USE_CASES).c_str());
137 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
138 }
139
140 *streamUseCase = streamUseCaseInt;
141 return ErrorCode::STATUS_OK;
142 }
143
getTimestampBaseFromXml(const XMLElement * timestampBaseXml,int64_t * timestampBase)144 ErrorCode SharedSessionConfigUtils::getTimestampBaseFromXml(const XMLElement* timestampBaseXml,
145 /* out */ int64_t* timestampBase) {
146 if (timestampBaseXml == nullptr || timestampBaseXml->GetText() == nullptr
147 || !strcmp(timestampBaseXml->GetText(), "")) {
148 *timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT;
149 return ErrorCode::STATUS_OK;
150 }
151
152 int64_t timestampBaseInt = std::strtol(timestampBaseXml->GetText(), nullptr, 0);
153 if (VALID_TIMESTAMP_BASES.find(timestampBaseInt) == VALID_TIMESTAMP_BASES.end()) {
154 ALOGE("%s: timestampBase %" PRId64 " is invalid: ", __FUNCTION__, timestampBaseInt);
155 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_TIMESTAMP_BASES).c_str());
156 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
157 }
158
159 *timestampBase = timestampBaseInt;
160 return ErrorCode::STATUS_OK;
161 }
162
getMirrorModeFromXml(const XMLElement * mirrorModeXml,int64_t * mirrorMode)163 ErrorCode SharedSessionConfigUtils::getMirrorModeFromXml(const XMLElement* mirrorModeXml,
164 /* out */ int64_t* mirrorMode) {
165 if (mirrorModeXml == nullptr || mirrorModeXml->GetText() == nullptr
166 || !strcmp(mirrorModeXml->GetText(), "")) {
167 *mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO;
168 return ErrorCode::STATUS_OK;
169 }
170
171 int64_t mirrorModeInt = std::strtol(mirrorModeXml->GetText(), nullptr, 0);
172 if (VALID_MIRROR_MODES.find(mirrorModeInt) == VALID_MIRROR_MODES.end()) {
173 ALOGE("%s: mirrorMode %" PRId64 " is invalid: ", __FUNCTION__, mirrorModeInt);
174 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_MIRROR_MODES).c_str());
175 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
176 }
177
178 *mirrorMode = mirrorModeInt;
179 return ErrorCode::STATUS_OK;
180 }
181
getUseReadoutTimestampFromXml(const XMLElement * useReadoutTimestampXml,bool * useReadoutTimestamp)182 ErrorCode SharedSessionConfigUtils::getUseReadoutTimestampFromXml(
183 const XMLElement* useReadoutTimestampXml, /* out */ bool* useReadoutTimestamp) {
184 if (useReadoutTimestampXml != nullptr && useReadoutTimestampXml->GetText() != nullptr
185 && strcmp(useReadoutTimestampXml->GetText(), "")) {
186 const char* useReadoutTimestampStr = useReadoutTimestampXml->GetText();
187 if (!strcmp(useReadoutTimestampStr, "1")) {
188 *useReadoutTimestamp = true;
189 return ErrorCode::STATUS_OK;
190 } else if (strcmp(useReadoutTimestampStr, "0")) {
191 ALOGE("%s: useReadoutTimestamp string %s is invalid: ", __FUNCTION__,
192 useReadoutTimestampStr);
193 ALOGE("%s: Expected one of: {0, 1}", __FUNCTION__);
194 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
195 }
196 }
197
198 *useReadoutTimestamp = false;
199 return ErrorCode::STATUS_OK;
200 }
201
getFormatFromXml(const XMLElement * formatXml,int64_t * format,int64_t surfaceType)202 ErrorCode SharedSessionConfigUtils::getFormatFromXml(const XMLElement* formatXml,
203 /* out */ int64_t* format,
204 int64_t surfaceType) {
205 if (surfaceType != OutputConfiguration::SURFACE_TYPE_IMAGE_READER) {
206 // if surface type is not image reader, format must default to impl defined enum.
207 *format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
208 return ErrorCode::STATUS_OK;
209 }
210
211 if (formatXml == nullptr || formatXml->GetText() == nullptr
212 || !strcmp(formatXml->GetText(), "")) {
213 ALOGE("%s: format field must be populated", __FUNCTION__);
214 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
215 }
216
217 int64_t formatInt = std::strtol(formatXml->GetText(), nullptr, 0);
218 if (VALID_FORMATS.find(formatInt) == VALID_FORMATS.end()) {
219 ALOGE("%s: format %" PRId64 " is invalid: ", __FUNCTION__, formatInt);
220 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_FORMATS).c_str());
221 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
222 }
223
224 *format = formatInt;
225 return ErrorCode::STATUS_OK;
226 }
227
getUsageFromXml(const XMLElement * usageXml,int64_t * usage,int64_t surfaceType)228 ErrorCode SharedSessionConfigUtils::getUsageFromXml(const XMLElement* usageXml,
229 /* out */ int64_t* usage,
230 int64_t surfaceType) {
231 if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE) {
232 // if surface type is SURFACE_TYPE_SURFACE_TEXTURE, usage must default to
233 // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
234 *usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
235 return ErrorCode::STATUS_OK;
236 }
237
238 if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
239 // if surface type is SURFACE_TYPE_SURFACE_VIEW, usage must default to
240 // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY.
241 *usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
242 return ErrorCode::STATUS_OK;
243 }
244
245 if (surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_RECORDER
246 || surfaceType == OutputConfiguration::SURFACE_TYPE_MEDIA_CODEC) {
247 // if surface type is SURFACE_TYPE_MEDIA_RECORDER or SURFACE_TYPE_MEDIA_CODEC, usage must
248 // default to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE
249 *usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
250 return ErrorCode::STATUS_OK;
251 }
252
253 if (usageXml == nullptr || usageXml->GetText() == nullptr
254 || !strcmp(usageXml->GetText(), "")) {
255 *usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER;
256 return ErrorCode::STATUS_OK;
257 }
258
259 const char* usageStr = usageXml->GetText();
260 std::vector<std::string> usageFlags = splitString(usageStr, '|');
261
262 for (std::string usageFlagStr : usageFlags) {
263 int64_t usageFlag = std::strtol(usageFlagStr.c_str(), nullptr, 0);
264 if (VALID_USAGES.find(usageFlag) == VALID_USAGES.end()) {
265 ALOGE("%s: usage %" PRId64 " is invalid: ", __FUNCTION__, usageFlag);
266 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_USAGES).c_str());
267 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
268 }
269
270 *usage |= usageFlag;
271 }
272
273 return ErrorCode::STATUS_OK;
274 }
275
getDataSpaceFromXml(const XMLElement * dataSpaceXml,int64_t * dataSpace)276 ErrorCode SharedSessionConfigUtils::getDataSpaceFromXml(const XMLElement* dataSpaceXml,
277 /* out */ int64_t* dataSpace) {
278 if (dataSpaceXml == nullptr || dataSpaceXml->GetText() == nullptr
279 || !strcmp(dataSpaceXml->GetText(), "")) {
280 *dataSpace = HAL_DATASPACE_UNKNOWN;
281 return ErrorCode::STATUS_OK;
282 }
283
284 int64_t dataSpaceInt = std::strtol(dataSpaceXml->GetText(), nullptr, 0);
285 if (VALID_DATA_SPACES.find(dataSpaceInt) == VALID_DATA_SPACES.end()) {
286 ALOGE("%s: dataSpace %" PRId64 " is invalid: ", __FUNCTION__, dataSpaceInt);
287 ALOGE("%s: Expected one of: %s", __FUNCTION__, setToString(VALID_DATA_SPACES).c_str());
288 return ErrorCode::ERROR_CONFIG_FILE_FORMAT;
289 }
290
291 *dataSpace = dataSpaceInt;
292 return ErrorCode::STATUS_OK;
293 }
294
splitString(std::string inputString,char delimiter)295 std::vector<std::string> SharedSessionConfigUtils::splitString(std::string inputString,
296 char delimiter) {
297 std::vector<std::string> tokens;
298 std::istringstream iss(inputString);
299 std::string token;
300
301 while (std::getline(iss, token, delimiter)) {
302 tokens.push_back(token);
303 }
304
305 return tokens;
306 }
307
setToString(const std::set<int64_t> & s)308 std::string SharedSessionConfigUtils::setToString(const std::set<int64_t>& s) {
309 std::ostringstream oss;
310 oss << "{";
311
312 for (auto it = s.begin(); it != s.end();) {
313 oss << *it;
314
315 if (++it != s.end()) {
316 oss << ", ";
317 }
318 }
319
320 oss << "}";
321 return oss.str();
322 }
323
324 } // namespace android
325