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 #define LOG_TAG "GCH_RealtimeZslRequestProcessor"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 #include "realtime_zsl_request_processor.h"
21
22 #include <log/log.h>
23 #include <utils/Trace.h>
24
25 #include <cstdint>
26 #include <shared_mutex>
27
28 #include "hal_types.h"
29 #include "hal_utils.h"
30 #include "system/graphics-base-v1.0.h"
31 #include "utils/Errors.h"
32 #include "vendor_tag_defs.h"
33
34 namespace android {
35 namespace google_camera_hal {
36
37 namespace {
38 // The width and height will be selected according to the following priority.
39 // 1. select the JPEG size if it is in the supported output YUV list
40 // 2. select the smallest output YUV size that
41 // 1) has width/height ratio between the width/height ratio of JPEG and the
42 // max available output size
43 // 2) is larger than JPEG size
SelectWidthAndHeight(uint32_t jpeg_width,uint32_t jpeg_height,CameraDeviceSessionHwl & device_session_hwl,uint32_t & selected_width,uint32_t & selected_height)44 status_t SelectWidthAndHeight(uint32_t jpeg_width, uint32_t jpeg_height,
45 CameraDeviceSessionHwl& device_session_hwl,
46 uint32_t& selected_width,
47 uint32_t& selected_height) {
48 std::unique_ptr<HalCameraMetadata> characteristics;
49 status_t res = device_session_hwl.GetCameraCharacteristics(&characteristics);
50 if (res != OK) {
51 ALOGE("%s: GetCameraCharacteristics failed.", __FUNCTION__);
52 return BAD_VALUE;
53 }
54
55 camera_metadata_ro_entry entry;
56 res = characteristics->Get(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
57 &entry);
58 if (res != OK) {
59 ALOGE("%s: Not able to get ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS",
60 __FUNCTION__);
61 return BAD_VALUE;
62 }
63 int available_size = entry.count / 4;
64
65 uint32_t max_width = 0, max_height = 0;
66 for (int i = 0; i < available_size; ++i) {
67 if (entry.data.i32[4 * i] ==
68 android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888 &&
69 entry.data.i32[4 * i + 3] == static_cast<int32_t>(StreamType::kOutput)) {
70 uint32_t width = static_cast<uint32_t>(entry.data.i32[1 + 4 * i]);
71 uint32_t height = static_cast<uint32_t>(entry.data.i32[2 + 4 * i]);
72
73 // The request JPEG size is a supported output YUV size. It is our top
74 // choice, return directly if found.
75 if (jpeg_width == width && jpeg_height == height) {
76 selected_height = jpeg_height;
77 selected_width = jpeg_width;
78 return OK;
79 }
80 max_width = std::max(max_width, width);
81 max_height = std::max(max_height, height);
82 }
83 }
84
85 bool selected = false;
86 for (int i = 0; i < available_size; i++) {
87 if (entry.data.i32[4 * i] ==
88 android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888 &&
89 entry.data.i32[4 * i + 3] == static_cast<int32_t>(StreamType::kOutput)) {
90 uint32_t width = static_cast<uint32_t>(entry.data.i32[1 + 4 * i]);
91 uint32_t height = static_cast<uint32_t>(entry.data.i32[2 + 4 * i]);
92 if (width < jpeg_width || height < jpeg_height) {
93 // YUV size is smaller than JPEG size
94 continue;
95 }
96 if (selected && width > selected_width) {
97 // Already found a smaller YUV size that fulfill the request
98 continue;
99 }
100
101 // Select the smallest supported YUV size with width/height ratio between
102 // JPEG and the max available output size. It is our second choice.
103 if ((jpeg_height * width - jpeg_width * height) *
104 (height * max_width - width * max_height) >=
105 0) {
106 selected = true;
107 selected_height = height;
108 selected_width = width;
109 }
110 }
111 }
112 if (!selected) {
113 // Select the largest supported YUV size. That is our last choice.
114 selected_height = max_height;
115 selected_width = max_width;
116 }
117 return OK;
118 }
119 } // namespace
120
Create(CameraDeviceSessionHwl * device_session_hwl,android_pixel_format_t pixel_format)121 std::unique_ptr<RealtimeZslRequestProcessor> RealtimeZslRequestProcessor::Create(
122 CameraDeviceSessionHwl* device_session_hwl,
123 android_pixel_format_t pixel_format) {
124 ATRACE_CALL();
125 if (device_session_hwl == nullptr) {
126 ALOGE("%s: device_session_hwl is nullptr", __FUNCTION__);
127 return nullptr;
128 }
129
130 auto request_processor = std::unique_ptr<RealtimeZslRequestProcessor>(
131 new RealtimeZslRequestProcessor(pixel_format, device_session_hwl));
132 if (request_processor == nullptr) {
133 ALOGE("%s: Creating RealtimeZslRequestProcessor failed.", __FUNCTION__);
134 return nullptr;
135 }
136
137 status_t res = request_processor->Initialize(device_session_hwl);
138 if (res != OK) {
139 ALOGE("%s: Initializing RealtimeZslRequestProcessor failed: %s (%d).",
140 __FUNCTION__, strerror(-res), res);
141 return nullptr;
142 }
143
144 return request_processor;
145 }
146
Initialize(CameraDeviceSessionHwl * device_session_hwl)147 status_t RealtimeZslRequestProcessor::Initialize(
148 CameraDeviceSessionHwl* device_session_hwl) {
149 ATRACE_CALL();
150 std::unique_ptr<HalCameraMetadata> characteristics;
151 status_t res = device_session_hwl->GetCameraCharacteristics(&characteristics);
152 if (res != OK) {
153 ALOGE("%s: GetCameraCharacteristics failed.", __FUNCTION__);
154 return BAD_VALUE;
155 }
156
157 camera_metadata_ro_entry entry;
158 res = characteristics->Get(
159 ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &entry);
160 if (res == OK) {
161 active_array_width_ = entry.data.i32[2];
162 active_array_height_ = entry.data.i32[3];
163 ALOGI("%s Active size (%d x %d).", __FUNCTION__, active_array_width_,
164 active_array_height_);
165 } else {
166 ALOGE("%s Get active size failed: %s (%d).", __FUNCTION__, strerror(-res),
167 res);
168 return res;
169 }
170 if (pixel_format_ == android_pixel_format_t::HAL_PIXEL_FORMAT_RAW10) {
171 res = characteristics->Get(VendorTagIds::kHdrUsageMode, &entry);
172 if (res == OK) {
173 hdr_mode_ = static_cast<HdrMode>(entry.data.u8[0]);
174 }
175 }
176
177 return OK;
178 }
179
ConfigureStreams(InternalStreamManager * internal_stream_manager,const StreamConfiguration & stream_config,StreamConfiguration * process_block_stream_config)180 status_t RealtimeZslRequestProcessor::ConfigureStreams(
181 InternalStreamManager* internal_stream_manager,
182 const StreamConfiguration& stream_config,
183 StreamConfiguration* process_block_stream_config) {
184 ATRACE_CALL();
185 if (process_block_stream_config == nullptr ||
186 internal_stream_manager == nullptr) {
187 ALOGE(
188 "%s: process_block_stream_config (%p) is nullptr or "
189 "internal_stream_manager (%p) is nullptr",
190 __FUNCTION__, process_block_stream_config, internal_stream_manager);
191 return BAD_VALUE;
192 }
193
194 // For YUV ZSL, we will use the JPEG size for ZSL buffer size. We already
195 // checked the size is supported in capture session.
196 if (pixel_format_ == android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888) {
197 for (const auto& stream : stream_config.streams) {
198 if (utils::IsSoftwareDenoiseEligibleSnapshotStream(stream)) {
199 if (SelectWidthAndHeight(stream.width, stream.height,
200 *device_session_hwl_, active_array_width_,
201 active_array_height_) != OK) {
202 ALOGE("%s: failed to select ZSL YUV buffer width and height",
203 __FUNCTION__);
204 return BAD_VALUE;
205 }
206 ALOGI("%s, Snapshot size is (%d x %d), selected size is (%d x %d)",
207 __FUNCTION__, stream.width, stream.height, active_array_width_,
208 active_array_height_);
209 break;
210 }
211 }
212 }
213
214 // Register internal stream
215 Stream stream_to_add;
216 stream_to_add.stream_type = StreamType::kOutput;
217 stream_to_add.width = active_array_width_;
218 stream_to_add.height = active_array_height_;
219 stream_to_add.format = pixel_format_;
220 stream_to_add.usage = 0;
221 stream_to_add.rotation = StreamRotation::kRotation0;
222 stream_to_add.data_space = HAL_DATASPACE_ARBITRARY;
223 // For YUV ZSL buffer, if the stream configuration constains physical stream,
224 // we will add the new stream as physical stream. As we support physical
225 // streams only or logical streams only combination. We can check the stream
226 // type of the first stream in the list.
227 if (pixel_format_ == android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888 &&
228 stream_config.streams[0].is_physical_camera_stream) {
229 stream_to_add.is_physical_camera_stream = true;
230 stream_to_add.physical_camera_id =
231 stream_config.streams[0].physical_camera_id;
232 }
233
234 status_t result = internal_stream_manager->RegisterNewInternalStream(
235 stream_to_add, &stream_id_);
236 if (result != OK) {
237 ALOGE("%s: RegisterNewInternalStream failed.", __FUNCTION__);
238 return UNKNOWN_ERROR;
239 }
240
241 internal_stream_manager_ = internal_stream_manager;
242 // Set id back to stream and then HWL can get correct HAL stream ID
243 stream_to_add.id = stream_id_;
244
245 process_block_stream_config->streams = stream_config.streams;
246 // Add internal stream
247 process_block_stream_config->streams.push_back(stream_to_add);
248 process_block_stream_config->operation_mode = stream_config.operation_mode;
249 process_block_stream_config->session_params =
250 HalCameraMetadata::Clone(stream_config.session_params.get());
251 process_block_stream_config->stream_config_counter =
252 stream_config.stream_config_counter;
253 process_block_stream_config->log_id = stream_config.log_id;
254
255 return OK;
256 }
257
SetProcessBlock(std::unique_ptr<ProcessBlock> process_block)258 status_t RealtimeZslRequestProcessor::SetProcessBlock(
259 std::unique_ptr<ProcessBlock> process_block) {
260 ATRACE_CALL();
261 if (process_block == nullptr) {
262 ALOGE("%s: process_block is nullptr", __FUNCTION__);
263 return BAD_VALUE;
264 }
265
266 std::lock_guard lock(process_block_lock_);
267 if (process_block_ != nullptr) {
268 ALOGE("%s: Already configured.", __FUNCTION__);
269 return ALREADY_EXISTS;
270 }
271
272 process_block_ = std::move(process_block);
273 return OK;
274 }
275
ProcessRequest(const CaptureRequest & request)276 status_t RealtimeZslRequestProcessor::ProcessRequest(
277 const CaptureRequest& request) {
278 ATRACE_CALL();
279 std::shared_lock lock(process_block_lock_);
280 if (process_block_ == nullptr) {
281 ALOGE("%s: Not configured yet.", __FUNCTION__);
282 return NO_INIT;
283 }
284
285 if (is_hdrplus_zsl_enabled_ && request.settings != nullptr) {
286 camera_metadata_ro_entry entry = {};
287 status_t res =
288 request.settings->Get(VendorTagIds::kThermalThrottling, &entry);
289 if (res != OK || entry.count != 1) {
290 ALOGW("%s: Getting thermal throttling entry failed: %s(%d)", __FUNCTION__,
291 strerror(-res), res);
292 } else if (entry.data.u8[0] == true) {
293 // Disable HDR+ ZSL once thermal throttles.
294 is_hdrplus_zsl_enabled_ = false;
295 ALOGI("%s: HDR+ ZSL disabled due to thermal throttling", __FUNCTION__);
296 }
297 }
298
299 // Update if preview intent has been requested.
300 camera_metadata_ro_entry entry;
301 if (!preview_intent_seen_ && request.settings != nullptr &&
302 request.settings->Get(ANDROID_CONTROL_CAPTURE_INTENT, &entry) == OK) {
303 if (entry.count == 1 &&
304 *entry.data.u8 == ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW) {
305 preview_intent_seen_ = true;
306 ALOGI("%s: First request with preview intent. ZSL starts.", __FUNCTION__);
307 }
308 }
309
310 CaptureRequest block_request;
311
312 block_request.frame_number = request.frame_number;
313 block_request.settings = HalCameraMetadata::Clone(request.settings.get());
314 block_request.input_buffers = request.input_buffers;
315 block_request.output_buffers = request.output_buffers;
316
317 for (auto& metadata : request.input_buffer_metadata) {
318 block_request.input_buffer_metadata.push_back(
319 HalCameraMetadata::Clone(metadata.get()));
320 }
321
322 for (auto& [camera_id, physical_metadata] : request.physical_camera_settings) {
323 block_request.physical_camera_settings[camera_id] =
324 HalCameraMetadata::Clone(physical_metadata.get());
325 }
326
327 if (is_hdrplus_zsl_enabled_ ||
328 pixel_format_ == android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888) {
329 // Get one bffer from internal stream manager
330 StreamBuffer buffer = {};
331 status_t result;
332 if (preview_intent_seen_) {
333 result = internal_stream_manager_->GetStreamBuffer(stream_id_, &buffer);
334 if (result != OK) {
335 ALOGE("%s: frame:%d GetStreamBuffer failed.", __FUNCTION__,
336 request.frame_number);
337 return UNKNOWN_ERROR;
338 }
339 }
340
341 // Add output to capture request
342 if (preview_intent_seen_) {
343 block_request.output_buffers.push_back(buffer);
344 }
345
346 if (block_request.settings != nullptr && is_hdrplus_zsl_enabled_) {
347 bool enable_hybrid_ae =
348 (hdr_mode_ == HdrMode::kNonHdrplusMode ? false : true);
349 result = hal_utils::ModifyRealtimeRequestForHdrplus(
350 block_request.settings.get(), enable_hybrid_ae);
351 if (result != OK) {
352 ALOGE("%s: ModifyRealtimeRequestForHdrplus (%d) fail", __FUNCTION__,
353 request.frame_number);
354 return UNKNOWN_ERROR;
355 }
356
357 if (hdr_mode_ != HdrMode::kHdrplusMode) {
358 uint8_t processing_mode =
359 static_cast<uint8_t>(ProcessingMode::kIntermediateProcessing);
360 block_request.settings->Set(VendorTagIds::kProcessingMode,
361 &processing_mode,
362 /*data_count=*/1);
363 }
364 }
365 }
366
367 std::vector<ProcessBlockRequest> block_requests(1);
368 block_requests[0].request = std::move(block_request);
369 return process_block_->ProcessRequests(block_requests, request);
370 }
371
Flush()372 status_t RealtimeZslRequestProcessor::Flush() {
373 ATRACE_CALL();
374 std::shared_lock lock(process_block_lock_);
375 if (process_block_ == nullptr) {
376 return OK;
377 }
378
379 return process_block_->Flush();
380 }
381
382 } // namespace google_camera_hal
383 } // namespace android