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_TAG "EmulatedLogicalState"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20
21 #include "EmulatedLogicalRequestState.h"
22
23 #include <log/log.h>
24
25 #include "vendor_tag_defs.h"
26
27 namespace android {
28
EmulatedLogicalRequestState(uint32_t camera_id)29 EmulatedLogicalRequestState::EmulatedLogicalRequestState(uint32_t camera_id)
30 : logical_camera_id_(camera_id),
31 logical_request_state_(std::make_unique<EmulatedRequestState>(camera_id)) {
32 }
33
~EmulatedLogicalRequestState()34 EmulatedLogicalRequestState::~EmulatedLogicalRequestState() {
35 }
36
Initialize(std::unique_ptr<HalCameraMetadata> static_meta,PhysicalDeviceMapPtr physical_devices)37 status_t EmulatedLogicalRequestState::Initialize(
38 std::unique_ptr<HalCameraMetadata> static_meta,
39 PhysicalDeviceMapPtr physical_devices) {
40 if ((physical_devices.get() != nullptr) && (!physical_devices->empty())) {
41 zoom_ratio_physical_camera_info_ = GetZoomRatioPhysicalCameraInfo(
42 static_meta.get(), physical_devices.get());
43
44 physical_device_map_ = std::move(physical_devices);
45
46 static const float ZOOM_RATIO_THRESHOLD = 0.001f;
47 for (const auto& one_zoom_range : zoom_ratio_physical_camera_info_) {
48 ALOGV("%s: cameraId %d, focalLength %f, zoomRatioRange [%f, %f]",
49 __FUNCTION__, one_zoom_range.physical_camera_id,
50 one_zoom_range.focal_length, one_zoom_range.min_zoom_ratio,
51 one_zoom_range.max_zoom_ratio);
52 if (std::abs(one_zoom_range.min_zoom_ratio - 1.0f) < ZOOM_RATIO_THRESHOLD) {
53 current_physical_camera_ = one_zoom_range.physical_camera_id;
54 }
55 }
56
57 if (zoom_ratio_physical_camera_info_.size() > 1) {
58 is_logical_device_ = true;
59 for (const auto& it : *physical_device_map_) {
60 std::unique_ptr<EmulatedRequestState> physical_request_state =
61 std::make_unique<EmulatedRequestState>(it.first);
62 auto ret = physical_request_state->Initialize(
63 HalCameraMetadata::Clone(it.second.second.get()));
64 if (ret != OK) {
65 ALOGE("%s: Physical device: %u request state initialization failed!",
66 __FUNCTION__, it.first);
67 return ret;
68 }
69 physical_request_states_.emplace(it.first,
70 std::move(physical_request_state));
71 }
72 }
73 }
74
75 return logical_request_state_->Initialize(std::move(static_meta));
76 }
77
GetDefaultRequest(RequestTemplate type,std::unique_ptr<HalCameraMetadata> * default_settings)78 status_t EmulatedLogicalRequestState::GetDefaultRequest(
79 RequestTemplate type,
80 std::unique_ptr<HalCameraMetadata>* default_settings /*out*/) {
81 return logical_request_state_->GetDefaultRequest(type, default_settings);
82 };
83
UpdateActivePhysicalId(HalCameraMetadata * result_metadata,uint32_t device_id)84 void EmulatedLogicalRequestState::UpdateActivePhysicalId(
85 HalCameraMetadata* result_metadata, uint32_t device_id) {
86 if (result_metadata == nullptr) {
87 return;
88 }
89
90 auto device_id_str = std::to_string(device_id);
91 std::vector<uint8_t> result;
92 result.reserve(device_id_str.size() + 1);
93 result.insert(result.end(), device_id_str.begin(), device_id_str.end());
94 result.push_back('\0');
95
96 result_metadata->Set(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID,
97 result.data(), result.size());
98 }
99
100 std::unique_ptr<HwlPipelineResult>
InitializeLogicalResult(uint32_t pipeline_id,uint32_t frame_number)101 EmulatedLogicalRequestState::InitializeLogicalResult(uint32_t pipeline_id,
102 uint32_t frame_number) {
103 auto ret = logical_request_state_->InitializeResult(pipeline_id, frame_number);
104 if (is_logical_device_) {
105 if ((physical_camera_output_ids_.get() != nullptr) &&
106 (!physical_camera_output_ids_->empty())) {
107 ret->physical_camera_results.reserve(physical_camera_output_ids_->size());
108 for (const auto& it : *physical_camera_output_ids_) {
109 ret->physical_camera_results[it] =
110 std::move(physical_request_states_[it]
111 ->InitializeResult(pipeline_id, frame_number)
112 ->result_metadata);
113
114 UpdateActivePhysicalId(ret->physical_camera_results[it].get(), it);
115 }
116 }
117
118 UpdateActivePhysicalId(ret->result_metadata.get(), current_physical_camera_);
119 }
120
121 return ret;
122 }
123
InitializeLogicalSettings(std::unique_ptr<HalCameraMetadata> request_settings,std::unique_ptr<std::set<uint32_t>> physical_camera_output_ids,uint32_t override_frame_number,EmulatedSensor::LogicalCameraSettings * logical_settings)124 status_t EmulatedLogicalRequestState::InitializeLogicalSettings(
125 std::unique_ptr<HalCameraMetadata> request_settings,
126 std::unique_ptr<std::set<uint32_t>> physical_camera_output_ids,
127 uint32_t override_frame_number,
128 EmulatedSensor::LogicalCameraSettings* logical_settings /*out*/) {
129 if (logical_settings == nullptr) {
130 return BAD_VALUE;
131 }
132
133 // All logical and physical devices can potentially receive individual client
134 // requests (Currently this is not the case due to HWL API limitations).
135 // The emulated sensor can adapt its characteristics and apply most of them
136 // independently however the frame duration needs to be the same across all
137 // settings.
138 // Track the maximum frame duration and override this value at the end for all
139 // logical settings.
140 nsecs_t max_frame_duration = 0;
141 if (is_logical_device_) {
142 std::swap(physical_camera_output_ids_, physical_camera_output_ids);
143
144 for (const auto& physical_request_state : physical_request_states_) {
145 // All physical devices will receive requests and will keep
146 // updating their respective request state.
147 // However only physical devices referenced by client need to propagate
148 // and apply their settings.
149 EmulatedSensor::SensorSettings physical_sensor_settings;
150 auto ret = physical_request_state.second->InitializeSensorSettings(
151 HalCameraMetadata::Clone(request_settings.get()),
152 override_frame_number, &physical_sensor_settings);
153 if (ret != OK) {
154 ALOGE(
155 "%s: Initialization of physical sensor settings for device id: %u "
156 "failed!",
157 __FUNCTION__, physical_request_state.first);
158 return ret;
159 }
160
161 if (physical_camera_output_ids_->find(physical_request_state.first) !=
162 physical_camera_output_ids_->end()) {
163 logical_settings->emplace(physical_request_state.first,
164 physical_sensor_settings);
165 if (max_frame_duration < physical_sensor_settings.exposure_time) {
166 max_frame_duration = physical_sensor_settings.exposure_time;
167 }
168 }
169 }
170 }
171
172 EmulatedSensor::SensorSettings sensor_settings;
173 auto ret = logical_request_state_->InitializeSensorSettings(
174 std::move(request_settings), override_frame_number, &sensor_settings);
175 logical_settings->emplace(logical_camera_id_, sensor_settings);
176 if (max_frame_duration < sensor_settings.exposure_time) {
177 max_frame_duration = sensor_settings.exposure_time;
178 }
179
180 for (auto it : *logical_settings) {
181 it.second.frame_duration = max_frame_duration;
182 }
183
184 return ret;
185 }
186
187 std::unique_ptr<HalCameraMetadata>
AdaptLogicalCharacteristics(std::unique_ptr<HalCameraMetadata> logical_chars,PhysicalDeviceMapPtr physical_devices)188 EmulatedLogicalRequestState::AdaptLogicalCharacteristics(
189 std::unique_ptr<HalCameraMetadata> logical_chars,
190 PhysicalDeviceMapPtr physical_devices) {
191 if ((logical_chars.get() == nullptr) || (physical_devices.get() == nullptr)) {
192 return nullptr;
193 }
194
195 // Update 'android.logicalMultiCamera.physicalIds' according to the newly
196 // assigned physical ids.
197 // Additionally if possible try to emulate a logical camera device backed by
198 // physical devices with different focal lengths. Usually real logical
199 // cameras like that will have device specific logic to switch between
200 // physical sensors. Unfortunately we cannot infer this behavior using only
201 // static camera characteristics. Use a simplistic approach of inferring
202 // physical camera based on zoom ratio.
203 std::vector<ZoomRatioPhysicalCameraInfo> zoom_ratio_physical_camera_info =
204 GetZoomRatioPhysicalCameraInfo(logical_chars.get(),
205 physical_devices.get());
206
207 std::vector<uint8_t> physical_ids;
208 for (const auto& physical_device : *physical_devices) {
209 auto physical_id = std::to_string(physical_device.first);
210 physical_ids.insert(physical_ids.end(), physical_id.begin(),
211 physical_id.end());
212 physical_ids.push_back('\0');
213 }
214
215 if (zoom_ratio_physical_camera_info.size() > 1) {
216 float zoom_range[2];
217 zoom_range[0] = zoom_ratio_physical_camera_info[0].min_zoom_ratio;
218 zoom_range[1] =
219 zoom_ratio_physical_camera_info[zoom_ratio_physical_camera_info.size() - 1]
220 .max_zoom_ratio;
221 logical_chars->Set(ANDROID_CONTROL_ZOOM_RATIO_RANGE, zoom_range, 2);
222
223 logical_chars->Set(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
224 &zoom_range[1], 1);
225
226 logical_chars->Set(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
227 physical_ids.data(), physical_ids.size());
228
229 // Possibly needs to be removed at some later point:
230 int32_t default_physical_id = physical_devices->begin()->first;
231 logical_chars->Set(google_camera_hal::kLogicalCamDefaultPhysicalId,
232 &default_physical_id, 1);
233
234 camera_metadata_ro_entry entry;
235 logical_chars->Get(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
236 std::set<int32_t> keys(entry.data.i32, entry.data.i32 + entry.count);
237 keys.emplace(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID);
238 std::vector<int32_t> keys_buffer(keys.begin(), keys.end());
239 logical_chars->Set(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
240 keys_buffer.data(), keys_buffer.size());
241
242 keys.clear();
243 keys_buffer.clear();
244 logical_chars->Get(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
245 keys.insert(entry.data.i32, entry.data.i32 + entry.count);
246 // Due to API limitations we currently don't support individual physical requests
247 logical_chars->Erase(ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
248 keys.erase(ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
249 keys.emplace(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
250 keys_buffer.insert(keys_buffer.end(), keys.begin(), keys.end());
251 logical_chars->Set(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
252 keys_buffer.data(), keys_buffer.size());
253 } else {
254 ALOGW(
255 "%s: The logical camera doesn't support combined zoom ratio ranges. "
256 "Emulation "
257 "could be"
258 " very limited in this case!",
259 __FUNCTION__);
260 }
261
262 return logical_chars;
263 }
264
UpdateRequestForDynamicStreams(HwlPipelineRequest * request,const std::vector<EmulatedPipeline> & pipelines,const DynamicStreamIdMapType & dynamic_stream_id_map,bool use_default_physical_camera)265 status_t EmulatedLogicalRequestState::UpdateRequestForDynamicStreams(
266 HwlPipelineRequest* request, const std::vector<EmulatedPipeline>& pipelines,
267 const DynamicStreamIdMapType& dynamic_stream_id_map,
268 bool use_default_physical_camera) {
269 if (request == nullptr) {
270 ALOGE("%s: Request must not be null!", __FUNCTION__);
271 return BAD_VALUE;
272 }
273
274 uint32_t pipeline_id = request->pipeline_id;
275 if (pipeline_id >= pipelines.size()) {
276 ALOGE("%s: Invalid pipeline id %d", __FUNCTION__, pipeline_id);
277 return BAD_VALUE;
278 }
279
280 // Only logical camera support dynamic size streams.
281 if (!is_logical_device_) return OK;
282
283 if (request->settings != nullptr) {
284 camera_metadata_ro_entry entry;
285 auto stat = request->settings->Get(ANDROID_CONTROL_ZOOM_RATIO, &entry);
286 if (stat != OK || entry.count != 1) {
287 ALOGW("%s: Zoom ratio absent from request, re-using older value!",
288 __FUNCTION__);
289 return BAD_VALUE;
290 }
291 if (!use_default_physical_camera) {
292 float zoom_ratio = entry.data.f[0];
293 for (const auto& one_range : zoom_ratio_physical_camera_info_) {
294 if (zoom_ratio >= one_range.min_zoom_ratio &&
295 zoom_ratio <= one_range.max_zoom_ratio) {
296 current_physical_camera_ = one_range.physical_camera_id;
297 break;
298 }
299 }
300 }
301 }
302
303 const auto& current_pipeline = pipelines[pipeline_id];
304 for (auto& output_buffer : request->output_buffers) {
305 auto& current_stream = current_pipeline.streams.at(output_buffer.stream_id);
306 if (current_stream.group_id == -1) continue;
307
308 const auto& stream_ids_for_camera =
309 dynamic_stream_id_map.find(current_physical_camera_);
310 if (stream_ids_for_camera == dynamic_stream_id_map.end()) {
311 ALOGW(
312 "%s: Failed to find physical camera id %d in dynamic stream id map!",
313 __FUNCTION__, current_physical_camera_);
314 continue;
315 }
316 const auto& stream_id =
317 stream_ids_for_camera->second.find(current_stream.group_id);
318 if (stream_id == stream_ids_for_camera->second.end()) {
319 ALOGW(
320 "%s: Failed to find group id %d in dynamic stream id map for camera "
321 "%d",
322 __FUNCTION__, current_stream.group_id, current_physical_camera_);
323 continue;
324 }
325
326 output_buffer.stream_id = stream_id->second;
327 }
328 return OK;
329 }
330
331 std::vector<ZoomRatioPhysicalCameraInfo>
GetZoomRatioPhysicalCameraInfo(const HalCameraMetadata * logical_chars,const PhysicalDeviceMap * physical_devices)332 EmulatedLogicalRequestState::GetZoomRatioPhysicalCameraInfo(
333 const HalCameraMetadata* logical_chars,
334 const PhysicalDeviceMap* physical_devices) {
335 std::vector<ZoomRatioPhysicalCameraInfo> zoom_ratio_physical_camera_info;
336 if ((logical_chars == nullptr) || (physical_devices == nullptr)) {
337 return zoom_ratio_physical_camera_info;
338 }
339
340 // Get the logical camera's focal length and sensor size
341 camera_metadata_ro_entry_t entry;
342 auto ret =
343 logical_chars->Get(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
344 if ((ret != OK) || (entry.count == 0)) {
345 return zoom_ratio_physical_camera_info;
346 }
347 float logical_focal_length = entry.data.f[0];
348 ret = logical_chars->Get(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, &entry);
349 if ((ret != OK) || (entry.count == 0)) {
350 return zoom_ratio_physical_camera_info;
351 }
352 float logical_sensor_width = entry.data.f[0];
353
354 // Derive the zoom ratio boundary values for each physical camera id, based on
355 // focal lengths and camera sensor physical size.
356 for (const auto& physical_device : *physical_devices) {
357 ret = physical_device.second.second->Get(
358 ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
359 if ((ret == OK) && (entry.count > 0)) {
360 float focal_length = entry.data.f[0];
361 ret = physical_device.second.second->Get(
362 ANDROID_SENSOR_INFO_PHYSICAL_SIZE, &entry);
363 if ((ret == OK) && (entry.count > 0)) {
364 float sensor_width = entry.data.f[0];
365 ret = physical_device.second.second->Get(
366 ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
367 if ((ret == OK) && (entry.count > 0)) {
368 float max_digital_zoom = entry.data.f[0];
369 // focal length of ultrawide lens
370 float min_zoom_ratio = focal_length * logical_sensor_width /
371 (logical_focal_length * sensor_width);
372 float max_zoom_ratio = max_digital_zoom * min_zoom_ratio;
373 zoom_ratio_physical_camera_info.push_back(
374 {focal_length, min_zoom_ratio, max_zoom_ratio,
375 physical_device.first});
376 }
377 }
378 }
379 }
380
381 // Sort the mapping by ascending focal length
382 std::sort(zoom_ratio_physical_camera_info.begin(),
383 zoom_ratio_physical_camera_info.end(),
384 [](const ZoomRatioPhysicalCameraInfo& a,
385 const ZoomRatioPhysicalCameraInfo& b) {
386 return a.focal_length < b.focal_length;
387 });
388
389 // Modify the zoom ratio range for each focal length so that they don't
390 // overlap
391 for (size_t i = 0; i < zoom_ratio_physical_camera_info.size() - 1; i++) {
392 auto& current = zoom_ratio_physical_camera_info[i];
393 auto& next = zoom_ratio_physical_camera_info[i + 1];
394 if (current.max_zoom_ratio > next.min_zoom_ratio) {
395 current.max_zoom_ratio = next.min_zoom_ratio;
396 }
397 }
398
399 return zoom_ratio_physical_camera_info;
400 }
401
402 } // namespace android
403