1 /*
2 * Copyright (C) 2019 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_NDEBUG 0
18 #include <cstdint>
19 #define LOG_TAG "GCH_Utils"
20
21 #include <cutils/properties.h>
22 #include <dirent.h>
23 #include <dlfcn.h>
24 #include <hardware/gralloc.h>
25 #include <sys/stat.h>
26
27 #include "utils.h"
28 #include "vendor_tag_defs.h"
29
30 namespace android {
31 namespace google_camera_hal {
32 namespace utils {
33
34 constexpr char kRealtimeThreadSetProp[] =
35 "persist.vendor.camera.realtimethread";
36
37 constexpr uint32_t kMinSupportedSoftwareDenoiseDimension = 1000;
38
IsDepthStream(const Stream & stream)39 bool IsDepthStream(const Stream& stream) {
40 if (stream.stream_type == StreamType::kOutput &&
41 stream.data_space == HAL_DATASPACE_DEPTH &&
42 stream.format == HAL_PIXEL_FORMAT_Y16) {
43 return true;
44 }
45
46 return false;
47 }
48
IsPreviewStream(const Stream & stream)49 bool IsPreviewStream(const Stream& stream) {
50 if (stream.stream_type == StreamType::kOutput &&
51 stream.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
52 ((stream.usage & GRALLOC_USAGE_HW_COMPOSER) == GRALLOC_USAGE_HW_COMPOSER ||
53 (stream.usage & GRALLOC_USAGE_HW_TEXTURE) == GRALLOC_USAGE_HW_TEXTURE)) {
54 return true;
55 }
56
57 return false;
58 }
59
IsJPEGSnapshotStream(const Stream & stream)60 bool IsJPEGSnapshotStream(const Stream& stream) {
61 if (stream.stream_type == StreamType::kOutput &&
62 stream.format == HAL_PIXEL_FORMAT_BLOB &&
63 (stream.data_space == HAL_DATASPACE_JFIF ||
64 stream.data_space == HAL_DATASPACE_V0_JFIF)) {
65 return true;
66 }
67
68 return false;
69 }
70
IsOutputZslStream(const Stream & stream)71 bool IsOutputZslStream(const Stream& stream) {
72 if (stream.stream_type == StreamType::kOutput &&
73 (stream.usage & GRALLOC_USAGE_HW_CAMERA_ZSL) ==
74 GRALLOC_USAGE_HW_CAMERA_ZSL) {
75 return true;
76 }
77
78 return false;
79 }
80
IsVideoStream(const Stream & stream)81 bool IsVideoStream(const Stream& stream) {
82 if (stream.stream_type == StreamType::kOutput &&
83 (stream.usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0) {
84 return true;
85 }
86
87 return false;
88 }
89
IsRawStream(const Stream & stream)90 bool IsRawStream(const Stream& stream) {
91 if (stream.stream_type == StreamType::kOutput &&
92 (stream.format == HAL_PIXEL_FORMAT_RAW10 ||
93 stream.format == HAL_PIXEL_FORMAT_RAW16 ||
94 stream.format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
95 return true;
96 }
97
98 return false;
99 }
100
IsInputRawStream(const Stream & stream)101 bool IsInputRawStream(const Stream& stream) {
102 if (stream.stream_type == StreamType::kInput &&
103 (stream.format == HAL_PIXEL_FORMAT_RAW10 ||
104 stream.format == HAL_PIXEL_FORMAT_RAW16 ||
105 stream.format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
106 return true;
107 }
108
109 return false;
110 }
111
IsArbitraryDataSpaceRawStream(const Stream & stream)112 bool IsArbitraryDataSpaceRawStream(const Stream& stream) {
113 return IsRawStream(stream) && (stream.data_space == HAL_DATASPACE_ARBITRARY);
114 }
115
IsYUVSnapshotStream(const Stream & stream)116 bool IsYUVSnapshotStream(const Stream& stream) {
117 if (stream.stream_type == StreamType::kOutput &&
118 stream.format == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
119 !IsVideoStream(stream) && !IsPreviewStream(stream)) {
120 return true;
121 }
122
123 return false;
124 }
125
IsSoftwareDenoiseEligibleSnapshotStream(const Stream & stream)126 bool IsSoftwareDenoiseEligibleSnapshotStream(const Stream& stream) {
127 if (utils::IsYUVSnapshotStream(stream) ||
128 utils::IsJPEGSnapshotStream(stream)) {
129 return stream.width >= kMinSupportedSoftwareDenoiseDimension ||
130 stream.height >= kMinSupportedSoftwareDenoiseDimension;
131 }
132 return false;
133 }
134
GetSensorPhysicalSize(const HalCameraMetadata * characteristics,float * width,float * height)135 status_t GetSensorPhysicalSize(const HalCameraMetadata* characteristics,
136 float* width, float* height) {
137 if (characteristics == nullptr || width == nullptr || height == nullptr) {
138 ALOGE("%s: characteristics or width/height is nullptr", __FUNCTION__);
139 return BAD_VALUE;
140 }
141
142 camera_metadata_ro_entry entry;
143 status_t res = characteristics->Get(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, &entry);
144 if (res != OK || entry.count != 2) {
145 ALOGE(
146 "%s: Getting ANDROID_SENSOR_INFO_PHYSICAL_SIZE failed: %s(%d) count: "
147 "%zu",
148 __FUNCTION__, strerror(-res), res, entry.count);
149 return res;
150 }
151
152 *width = entry.data.f[0];
153 *height = entry.data.f[1];
154 return OK;
155 }
156
HasCapability(const HalCameraMetadata * metadata,uint8_t capability)157 bool HasCapability(const HalCameraMetadata* metadata, uint8_t capability) {
158 if (metadata == nullptr) {
159 return false;
160 }
161
162 camera_metadata_ro_entry_t entry;
163 auto ret = metadata->Get(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
164 if (ret != OK) {
165 return false;
166 }
167 for (size_t i = 0; i < entry.count; i++) {
168 if (entry.data.u8[i] == capability) {
169 return true;
170 }
171 }
172 return false;
173 }
174
GetSensorActiveArraySize(const HalCameraMetadata * characteristics,Rect * active_array,bool maximum_resolution)175 status_t GetSensorActiveArraySize(const HalCameraMetadata* characteristics,
176 Rect* active_array, bool maximum_resolution) {
177 if (characteristics == nullptr || active_array == nullptr) {
178 ALOGE("%s: characteristics or active_array is nullptr", __FUNCTION__);
179 return BAD_VALUE;
180 }
181 uint32_t active_array_tag =
182 maximum_resolution
183 ? ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
184 : ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE;
185 camera_metadata_ro_entry entry;
186 status_t res = characteristics->Get(active_array_tag, &entry);
187 if (res != OK || entry.count != 4) {
188 ALOGE(
189 "%s: Getting ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE failed: %s(%d) "
190 "count: %zu max resolution ? %s",
191 __FUNCTION__, strerror(-res), res, entry.count,
192 maximum_resolution ? "true" : "false");
193 return res;
194 }
195
196 active_array->left = entry.data.i32[0];
197 active_array->top = entry.data.i32[1];
198 active_array->right = entry.data.i32[0] + entry.data.i32[2] - 1;
199 active_array->bottom = entry.data.i32[1] + entry.data.i32[3] - 1;
200
201 return OK;
202 }
203
GetZoomRatioRange(const HalCameraMetadata * characteristics,ZoomRatioRange * zoom_ratio_range)204 status_t GetZoomRatioRange(const HalCameraMetadata* characteristics,
205 ZoomRatioRange* zoom_ratio_range) {
206 if (characteristics == nullptr || zoom_ratio_range == nullptr) {
207 ALOGE("%s: characteristics or zoom_ratio_range is nullptr", __FUNCTION__);
208 return BAD_VALUE;
209 }
210
211 camera_metadata_ro_entry entry;
212 status_t res = characteristics->Get(ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
213 if (res != OK || entry.count != 2) {
214 ALOGE(
215 "%s: Getting ANDROID_CONTROL_ZOOM_RATIO_RANGE failed: %s(%d) "
216 "count: %zu",
217 __FUNCTION__, strerror(-res), res, entry.count);
218 return res;
219 }
220
221 zoom_ratio_range->min = entry.data.f[0];
222 zoom_ratio_range->max = entry.data.f[1];
223
224 return OK;
225 }
226
GetSensorPixelArraySize(const HalCameraMetadata * characteristics,Dimension * pixel_array)227 status_t GetSensorPixelArraySize(const HalCameraMetadata* characteristics,
228 Dimension* pixel_array) {
229 if (characteristics == nullptr || pixel_array == nullptr) {
230 ALOGE("%s: characteristics or pixel_array is nullptr", __FUNCTION__);
231 return BAD_VALUE;
232 }
233
234 camera_metadata_ro_entry entry;
235 status_t res =
236 characteristics->Get(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, &entry);
237 if (res != OK || entry.count != 2) {
238 ALOGE(
239 "%s: Getting ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE failed: %s(%d) "
240 "count: %zu",
241 __FUNCTION__, strerror(-res), res, entry.count);
242 return res;
243 }
244
245 pixel_array->width = entry.data.i32[0];
246 pixel_array->height = entry.data.i32[1];
247
248 return OK;
249 }
250
GetFocalLength(const HalCameraMetadata * characteristics,float * focal_length)251 status_t GetFocalLength(const HalCameraMetadata* characteristics,
252 float* focal_length) {
253 if (characteristics == nullptr || focal_length == nullptr) {
254 ALOGE("%s: characteristics or focal_length is nullptr", __FUNCTION__);
255 return BAD_VALUE;
256 }
257
258 camera_metadata_ro_entry entry;
259 status_t res =
260 characteristics->Get(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
261 if (res != OK || entry.count != 1) {
262 ALOGE(
263 "%s: Getting ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS failed: %s(%d) "
264 "count: %zu",
265 __FUNCTION__, strerror(-res), res, entry.count);
266 return res;
267 }
268
269 *focal_length = entry.data.f[0];
270
271 return OK;
272 }
273
IsLiveSnapshotConfigured(const StreamConfiguration & stream_config)274 bool IsLiveSnapshotConfigured(const StreamConfiguration& stream_config) {
275 bool has_video_stream = false;
276 bool has_jpeg_stream = false;
277 for (auto stream : stream_config.streams) {
278 if (utils::IsVideoStream(stream)) {
279 has_video_stream = true;
280 } else if (utils::IsJPEGSnapshotStream(stream)) {
281 has_jpeg_stream = true;
282 }
283 }
284
285 return (has_video_stream & has_jpeg_stream);
286 }
287
IsHighSpeedModeFpsCompatible(StreamConfigurationMode mode,const HalCameraMetadata * old_session,const HalCameraMetadata * new_session)288 bool IsHighSpeedModeFpsCompatible(StreamConfigurationMode mode,
289 const HalCameraMetadata* old_session,
290 const HalCameraMetadata* new_session) {
291 if (mode != StreamConfigurationMode::kConstrainedHighSpeed) {
292 return false;
293 }
294
295 camera_metadata_ro_entry_t ae_target_fps_entry;
296 int32_t old_max_fps = 0;
297 int32_t new_max_fps = 0;
298
299 if (old_session->Get(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
300 &ae_target_fps_entry) == OK) {
301 old_max_fps = ae_target_fps_entry.data.i32[1];
302 }
303 if (new_session->Get(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
304 &ae_target_fps_entry) == OK) {
305 new_max_fps = ae_target_fps_entry.data.i32[1];
306 }
307
308 ALOGI("%s: HFR: old max fps: %d, new max fps: %d", __FUNCTION__, old_max_fps,
309 new_max_fps);
310
311 if (new_max_fps == old_max_fps) {
312 return true;
313 }
314
315 return false;
316 }
317
IsSessionParameterCompatible(const HalCameraMetadata * old_session,const HalCameraMetadata * new_session)318 bool IsSessionParameterCompatible(const HalCameraMetadata* old_session,
319 const HalCameraMetadata* new_session) {
320 auto old_session_count = old_session->GetEntryCount();
321 auto new_session_count = new_session->GetEntryCount();
322 if (old_session_count == 0 || new_session_count == 0) {
323 ALOGI("No session paramerter, old:%zu, new:%zu", old_session_count,
324 new_session_count);
325 if (new_session_count != 0) {
326 camera_metadata_ro_entry_t entry;
327 if (new_session->Get(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry) == OK) {
328 int32_t max_fps = entry.data.i32[1];
329 if (max_fps > 30) {
330 ALOGI("new session paramerter max fps:%d", max_fps);
331 return false;
332 }
333 }
334 }
335 return true;
336 }
337
338 if (old_session_count != new_session_count) {
339 ALOGI(
340 "Entry count has changed from %zu "
341 "to %zu",
342 old_session_count, new_session_count);
343 return false;
344 }
345
346 for (size_t entry_index = 0; entry_index < new_session_count; entry_index++) {
347 camera_metadata_ro_entry_t new_entry;
348 // Get the medata from new session first
349 if (new_session->GetByIndex(&new_entry, entry_index) != OK) {
350 ALOGW("Unable to get new session entry for index %zu", entry_index);
351 return false;
352 }
353
354 // Get the same tag from old session
355 camera_metadata_ro_entry_t old_entry;
356 if (old_session->Get(new_entry.tag, &old_entry) != OK) {
357 ALOGW("Unable to get old session tag 0x%x", new_entry.tag);
358 return false;
359 }
360
361 if (new_entry.count != old_entry.count) {
362 ALOGI(
363 "New entry count %zu doesn't "
364 "match old entry count %zu",
365 new_entry.count, old_entry.count);
366 return false;
367 }
368
369 if (new_entry.tag == ANDROID_CONTROL_AE_TARGET_FPS_RANGE) {
370 // Stream reconfiguration is not needed in case the upper
371 // framerate range remains unchanged. Any other modification
372 // to the session parameters must trigger new stream
373 // configuration.
374 int32_t old_min_fps = old_entry.data.i32[0];
375 int32_t old_max_fps = old_entry.data.i32[1];
376 int32_t new_min_fps = new_entry.data.i32[0];
377 int32_t new_max_fps = new_entry.data.i32[1];
378 // Do not reconfigure session if max FPS hasn't changed or in
379 // the special case that AE FPS is throttling [60, 60] to [30, 30] or
380 // restored from [30, 30] to [60, 60] from GCA side when session parameter
381 // kVideo60to30FPSThermalThrottle is enabled.
382 uint8_t video_60_to_30fps_thermal_throttle = 0;
383 camera_metadata_ro_entry_t video_60_to_30fps_throttle_entry;
384 if (new_session->Get(kVideo60to30FPSThermalThrottle,
385 &video_60_to_30fps_throttle_entry) == OK) {
386 video_60_to_30fps_thermal_throttle =
387 video_60_to_30fps_throttle_entry.data.u8[0];
388 }
389
390 bool ignore_fps_range_diff = false;
391 if (video_60_to_30fps_thermal_throttle) {
392 if (((old_min_fps == 60) && (old_max_fps == 60) &&
393 (new_min_fps == 30) && (new_max_fps == 30)) ||
394 ((old_min_fps == 30) && (old_max_fps == 30) &&
395 (new_min_fps == 60) && (new_max_fps == 60))) {
396 ignore_fps_range_diff = true;
397 }
398 }
399
400 if (old_max_fps == new_max_fps || ignore_fps_range_diff) {
401 ALOGI(
402 "%s: Ignore fps (%d, %d) to (%d, %d). "
403 "video_60_to_30fps_thermal_throttle: %u",
404 __FUNCTION__, old_min_fps, old_max_fps, new_min_fps, new_max_fps,
405 video_60_to_30fps_thermal_throttle);
406 continue;
407 }
408
409 return false;
410 } else {
411 // Same type and count, compare values
412 size_t type_size = camera_metadata_type_size[old_entry.type];
413 size_t entry_size = type_size * old_entry.count;
414 int32_t cmp = memcmp(new_entry.data.u8, old_entry.data.u8, entry_size);
415 if (cmp != 0) {
416 ALOGI("Session parameter value has changed");
417 return false;
418 }
419 }
420 }
421
422 return true;
423 }
424
ConvertZoomRatio(const float zoom_ratio,const Dimension & active_array_dimension,int32_t * left,int32_t * top,int32_t * width,int32_t * height)425 void ConvertZoomRatio(const float zoom_ratio,
426 const Dimension& active_array_dimension, int32_t* left,
427 int32_t* top, int32_t* width, int32_t* height) {
428 if (left == nullptr || top == nullptr || width == nullptr ||
429 height == nullptr) {
430 ALOGE("%s, invalid params", __FUNCTION__);
431 return;
432 }
433
434 assert(zoom_ratio != 0);
435 *left = std::round(*left / zoom_ratio + 0.5f * active_array_dimension.width *
436 (1.0f - 1.0f / zoom_ratio));
437 *top = std::round(*top / zoom_ratio + 0.5f * active_array_dimension.height *
438 (1.0f - 1.0f / zoom_ratio));
439 *width = std::round(*width / zoom_ratio);
440 *height = std::round(*height / zoom_ratio);
441
442 if (zoom_ratio >= 1.0f) {
443 utils::ClampBoundary(active_array_dimension, left, top, width, height);
444 }
445 }
446
SupportRealtimeThread()447 bool SupportRealtimeThread() {
448 static bool support_real_time = false;
449 static bool first_time = false;
450 if (first_time == false) {
451 first_time = true;
452 support_real_time = property_get_bool(kRealtimeThreadSetProp, false);
453 }
454
455 return support_real_time;
456 }
457
SetRealtimeThread(pthread_t thread)458 status_t SetRealtimeThread(pthread_t thread) {
459 struct sched_param param = {
460 .sched_priority = 1,
461 };
462 int32_t res =
463 pthread_setschedparam(thread, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m);
464 if (res != 0) {
465 ALOGE("%s: Couldn't set SCHED_FIFO", __FUNCTION__);
466 return BAD_VALUE;
467 }
468
469 return OK;
470 }
471
UpdateThreadSched(pthread_t thread,int32_t policy,struct sched_param * param)472 status_t UpdateThreadSched(pthread_t thread, int32_t policy,
473 struct sched_param* param) {
474 if (param == nullptr) {
475 ALOGE("%s: sched_param is nullptr", __FUNCTION__);
476 return BAD_VALUE;
477 }
478 int32_t res = pthread_setschedparam(thread, policy, param);
479 if (res != 0) {
480 ALOGE("%s: Couldn't set schedparam", __FUNCTION__);
481 return BAD_VALUE;
482 }
483
484 return OK;
485 }
486
487 // Returns an array of regular files under dir_path.
FindLibraryPaths(const char * dir_path)488 std::vector<std::string> FindLibraryPaths(const char* dir_path) {
489 std::vector<std::string> libs;
490
491 errno = 0;
492 DIR* dir = opendir(dir_path);
493 if (!dir) {
494 ALOGD("%s: Unable to open directory %s (%s)", __FUNCTION__, dir_path,
495 strerror(errno));
496 return libs;
497 }
498
499 struct dirent* entry = nullptr;
500 while ((entry = readdir(dir)) != nullptr) {
501 std::string lib_path(dir_path);
502 lib_path += entry->d_name;
503 struct stat st;
504 if (stat(lib_path.c_str(), &st) == 0) {
505 if (S_ISREG(st.st_mode)) {
506 libs.push_back(lib_path);
507 }
508 }
509 }
510
511 return libs;
512 }
513
IsStreamUseCaseSupported(const StreamConfiguration & stream_config,const std::set<int64_t> & stream_use_cases,bool log_if_not_supported)514 bool IsStreamUseCaseSupported(const StreamConfiguration& stream_config,
515 const std::set<int64_t>& stream_use_cases,
516 bool log_if_not_supported) {
517 for (const auto& stream : stream_config.streams) {
518 if (stream_use_cases.find(stream.use_case) == stream_use_cases.end()) {
519 if (log_if_not_supported) {
520 ALOGE("Stream use case %d not in set of supported use cases",
521 stream.use_case);
522 }
523 return false;
524 }
525 }
526 return true;
527 }
528
GetStreamUseCases(const HalCameraMetadata * static_metadata,std::set<int64_t> * stream_use_cases)529 status_t GetStreamUseCases(const HalCameraMetadata* static_metadata,
530 std::set<int64_t>* stream_use_cases) {
531 if (static_metadata == nullptr || stream_use_cases == nullptr) {
532 return BAD_VALUE;
533 }
534
535 camera_metadata_ro_entry entry;
536 status_t ret =
537 static_metadata->Get(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
538 if (ret != OK) {
539 ALOGV("%s: No available stream use cases!", __FUNCTION__);
540 stream_use_cases->insert(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
541 return OK;
542 }
543 stream_use_cases->insert(entry.data.i64, entry.data.i64 + entry.count);
544
545 return OK;
546 }
547
IsSecuredStream(const Stream & stream)548 bool IsSecuredStream(const Stream& stream) {
549 return (stream.usage & GRALLOC_USAGE_PROTECTED) != 0u;
550 }
551
IsStreamUseCasesVideoCall(const Stream & stream)552 bool IsStreamUseCasesVideoCall(const Stream& stream) {
553 return (stream.use_case ==
554 ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL)
555 ? true
556 : false;
557 }
558
IsHdrStream(const Stream & stream)559 bool IsHdrStream(const Stream& stream) {
560 return stream.dynamic_profile !=
561 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
562 }
563
564 } // namespace utils
565 } // namespace google_camera_hal
566 } // namespace android
567