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
254 return OK;
255 }
256
SetProcessBlock(std::unique_ptr<ProcessBlock> process_block)257 status_t RealtimeZslRequestProcessor::SetProcessBlock(
258 std::unique_ptr<ProcessBlock> process_block) {
259 ATRACE_CALL();
260 if (process_block == nullptr) {
261 ALOGE("%s: process_block is nullptr", __FUNCTION__);
262 return BAD_VALUE;
263 }
264
265 std::lock_guard lock(process_block_lock_);
266 if (process_block_ != nullptr) {
267 ALOGE("%s: Already configured.", __FUNCTION__);
268 return ALREADY_EXISTS;
269 }
270
271 process_block_ = std::move(process_block);
272 return OK;
273 }
274
ProcessRequest(const CaptureRequest & request)275 status_t RealtimeZslRequestProcessor::ProcessRequest(
276 const CaptureRequest& request) {
277 ATRACE_CALL();
278 std::shared_lock lock(process_block_lock_);
279 if (process_block_ == nullptr) {
280 ALOGE("%s: Not configured yet.", __FUNCTION__);
281 return NO_INIT;
282 }
283
284 if (is_hdrplus_zsl_enabled_ && request.settings != nullptr) {
285 camera_metadata_ro_entry entry = {};
286 status_t res =
287 request.settings->Get(VendorTagIds::kThermalThrottling, &entry);
288 if (res != OK || entry.count != 1) {
289 ALOGW("%s: Getting thermal throttling entry failed: %s(%d)", __FUNCTION__,
290 strerror(-res), res);
291 } else if (entry.data.u8[0] == true) {
292 // Disable HDR+ ZSL once thermal throttles.
293 is_hdrplus_zsl_enabled_ = false;
294 ALOGI("%s: HDR+ ZSL disabled due to thermal throttling", __FUNCTION__);
295 }
296 }
297
298 // Update if preview intent has been requested.
299 camera_metadata_ro_entry entry;
300 if (!preview_intent_seen_ && request.settings != nullptr &&
301 request.settings->Get(ANDROID_CONTROL_CAPTURE_INTENT, &entry) == OK) {
302 if (entry.count == 1 &&
303 *entry.data.u8 == ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW) {
304 preview_intent_seen_ = true;
305 ALOGI("%s: First request with preview intent. ZSL starts.", __FUNCTION__);
306 }
307 }
308
309 CaptureRequest block_request;
310
311 block_request.frame_number = request.frame_number;
312 block_request.settings = HalCameraMetadata::Clone(request.settings.get());
313 block_request.input_buffers = request.input_buffers;
314 block_request.output_buffers = request.output_buffers;
315
316 for (auto& metadata : request.input_buffer_metadata) {
317 block_request.input_buffer_metadata.push_back(
318 HalCameraMetadata::Clone(metadata.get()));
319 }
320
321 for (auto& [camera_id, physical_metadata] : request.physical_camera_settings) {
322 block_request.physical_camera_settings[camera_id] =
323 HalCameraMetadata::Clone(physical_metadata.get());
324 }
325
326 if (is_hdrplus_zsl_enabled_ ||
327 pixel_format_ == android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888) {
328 // Get one bffer from internal stream manager
329 StreamBuffer buffer = {};
330 status_t result;
331 if (preview_intent_seen_) {
332 result = internal_stream_manager_->GetStreamBuffer(stream_id_, &buffer);
333 if (result != OK) {
334 ALOGE("%s: frame:%d GetStreamBuffer failed.", __FUNCTION__,
335 request.frame_number);
336 return UNKNOWN_ERROR;
337 }
338 }
339
340 // Add output to capture request
341 if (preview_intent_seen_) {
342 block_request.output_buffers.push_back(buffer);
343 }
344
345 if (block_request.settings != nullptr && is_hdrplus_zsl_enabled_) {
346 bool enable_hybrid_ae =
347 (hdr_mode_ == HdrMode::kNonHdrplusMode ? false : true);
348 result = hal_utils::ModifyRealtimeRequestForHdrplus(
349 block_request.settings.get(), enable_hybrid_ae);
350 if (result != OK) {
351 ALOGE("%s: ModifyRealtimeRequestForHdrplus (%d) fail", __FUNCTION__,
352 request.frame_number);
353 return UNKNOWN_ERROR;
354 }
355
356 if (hdr_mode_ != HdrMode::kHdrplusMode) {
357 uint8_t processing_mode =
358 static_cast<uint8_t>(ProcessingMode::kIntermediateProcessing);
359 block_request.settings->Set(VendorTagIds::kProcessingMode,
360 &processing_mode,
361 /*data_count=*/1);
362 }
363 }
364 }
365
366 std::vector<ProcessBlockRequest> block_requests(1);
367 block_requests[0].request = std::move(block_request);
368 return process_block_->ProcessRequests(block_requests, request);
369 }
370
Flush()371 status_t RealtimeZslRequestProcessor::Flush() {
372 ATRACE_CALL();
373 std::shared_lock lock(process_block_lock_);
374 if (process_block_ == nullptr) {
375 return OK;
376 }
377
378 return process_block_->Flush();
379 }
380
381 } // namespace google_camera_hal
382 } // namespace android