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