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   if (pixel_format != android_pixel_format_t::HAL_PIXEL_FORMAT_YCBCR_420_888) {
130     ALOGE("%s: only YCBCR_420_888 is supported for YUV ZSL", __FUNCTION__);
131     return nullptr;
132   }
133 
134   auto request_processor = std::unique_ptr<RealtimeZslRequestProcessor>(
135       new RealtimeZslRequestProcessor(device_session_hwl));
136   if (request_processor == nullptr) {
137     ALOGE("%s: Creating RealtimeZslRequestProcessor failed.", __FUNCTION__);
138     return nullptr;
139   }
140 
141   status_t res = request_processor->Initialize(device_session_hwl);
142   if (res != OK) {
143     ALOGE("%s: Initializing RealtimeZslRequestProcessor failed: %s (%d).",
144           __FUNCTION__, strerror(-res), res);
145     return nullptr;
146   }
147 
148   return request_processor;
149 }
150 
Initialize(CameraDeviceSessionHwl * device_session_hwl)151 status_t RealtimeZslRequestProcessor::Initialize(
152     CameraDeviceSessionHwl* device_session_hwl) {
153   ATRACE_CALL();
154   std::unique_ptr<HalCameraMetadata> characteristics;
155   status_t res = device_session_hwl->GetCameraCharacteristics(&characteristics);
156   if (res != OK) {
157     ALOGE("%s: GetCameraCharacteristics failed.", __FUNCTION__);
158     return BAD_VALUE;
159   }
160 
161   camera_metadata_ro_entry entry;
162   res = characteristics->Get(
163       ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &entry);
164   if (res == OK) {
165     active_array_width_ = entry.data.i32[2];
166     active_array_height_ = entry.data.i32[3];
167     ALOGI("%s Active size (%d x %d).", __FUNCTION__, active_array_width_,
168           active_array_height_);
169   } else {
170     ALOGE("%s Get active size failed: %s (%d).", __FUNCTION__, strerror(-res),
171           res);
172     return res;
173   }
174 
175   return OK;
176 }
177 
ConfigureStreams(InternalStreamManager * internal_stream_manager,const StreamConfiguration & stream_config,StreamConfiguration * process_block_stream_config)178 status_t RealtimeZslRequestProcessor::ConfigureStreams(
179     InternalStreamManager* internal_stream_manager,
180     const StreamConfiguration& stream_config,
181     StreamConfiguration* process_block_stream_config) {
182   ATRACE_CALL();
183   if (process_block_stream_config == nullptr ||
184       internal_stream_manager == nullptr) {
185     ALOGE(
186         "%s: process_block_stream_config (%p) is nullptr or "
187         "internal_stream_manager (%p) is nullptr",
188         __FUNCTION__, process_block_stream_config, internal_stream_manager);
189     return BAD_VALUE;
190   }
191 
192   // For YUV ZSL, we will use the JPEG size for ZSL buffer size. We already
193   // checked the size is supported in capture session.
194   for (const auto& stream : stream_config.streams) {
195     if (utils::IsSoftwareDenoiseEligibleSnapshotStream(stream)) {
196       if (SelectWidthAndHeight(stream.width, stream.height,
197                                *device_session_hwl_, active_array_width_,
198                                active_array_height_) != OK) {
199         ALOGE("%s: failed to select ZSL YUV buffer width and height",
200               __FUNCTION__);
201         return BAD_VALUE;
202       }
203       ALOGI("%s, Snapshot size is (%d x %d), selected size is (%d x %d)",
204             __FUNCTION__, stream.width, stream.height, active_array_width_,
205             active_array_height_);
206       break;
207     }
208   }
209 
210   // Register internal stream
211   Stream stream_to_add;
212   stream_to_add.stream_type = StreamType::kOutput;
213   stream_to_add.width = active_array_width_;
214   stream_to_add.height = active_array_height_;
215   stream_to_add.format = HAL_PIXEL_FORMAT_YCBCR_420_888;
216   stream_to_add.usage = 0;
217   stream_to_add.rotation = StreamRotation::kRotation0;
218   stream_to_add.data_space = HAL_DATASPACE_ARBITRARY;
219   // For YUV ZSL buffer, if the stream configuration constains physical stream,
220   // we will add the new stream as physical stream. As we support physical
221   // streams only or logical streams only combination. We can check the stream
222   // type of the first stream in the list.
223   if (stream_config.streams[0].is_physical_camera_stream) {
224     stream_to_add.is_physical_camera_stream = true;
225     stream_to_add.physical_camera_id =
226         stream_config.streams[0].physical_camera_id;
227   }
228 
229   status_t result = internal_stream_manager->RegisterNewInternalStream(
230       stream_to_add, &stream_id_);
231   if (result != OK) {
232     ALOGE("%s: RegisterNewInternalStream failed.", __FUNCTION__);
233     return UNKNOWN_ERROR;
234   }
235 
236   internal_stream_manager_ = internal_stream_manager;
237   // Set id back to stream and then HWL can get correct HAL stream ID
238   stream_to_add.id = stream_id_;
239 
240   process_block_stream_config->streams = stream_config.streams;
241   // Add internal stream
242   process_block_stream_config->streams.push_back(stream_to_add);
243   process_block_stream_config->operation_mode = stream_config.operation_mode;
244   process_block_stream_config->session_params =
245       HalCameraMetadata::Clone(stream_config.session_params.get());
246   process_block_stream_config->stream_config_counter =
247       stream_config.stream_config_counter;
248   process_block_stream_config->log_id = stream_config.log_id;
249 
250   return OK;
251 }
252 
SetProcessBlock(std::unique_ptr<ProcessBlock> process_block)253 status_t RealtimeZslRequestProcessor::SetProcessBlock(
254     std::unique_ptr<ProcessBlock> process_block) {
255   ATRACE_CALL();
256   if (process_block == nullptr) {
257     ALOGE("%s: process_block is nullptr", __FUNCTION__);
258     return BAD_VALUE;
259   }
260 
261   std::lock_guard lock(process_block_lock_);
262   if (process_block_ != nullptr) {
263     ALOGE("%s: Already configured.", __FUNCTION__);
264     return ALREADY_EXISTS;
265   }
266 
267   process_block_ = std::move(process_block);
268   return OK;
269 }
270 
ProcessRequest(const CaptureRequest & request)271 status_t RealtimeZslRequestProcessor::ProcessRequest(
272     const CaptureRequest& request) {
273   ATRACE_CALL();
274   std::shared_lock lock(process_block_lock_);
275   if (process_block_ == nullptr) {
276     ALOGE("%s: Not configured yet.", __FUNCTION__);
277     return NO_INIT;
278   }
279 
280   // Update if preview intent has been requested.
281   camera_metadata_ro_entry entry;
282   if (!preview_intent_seen_ && request.settings != nullptr &&
283       request.settings->Get(ANDROID_CONTROL_CAPTURE_INTENT, &entry) == OK) {
284     if (entry.count == 1 &&
285         *entry.data.u8 == ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW) {
286       preview_intent_seen_ = true;
287       ALOGI("%s: First request with preview intent. ZSL starts.", __FUNCTION__);
288     }
289   }
290 
291   CaptureRequest block_request;
292 
293   block_request.frame_number = request.frame_number;
294   block_request.settings = HalCameraMetadata::Clone(request.settings.get());
295   block_request.input_buffers = request.input_buffers;
296   block_request.output_buffers = request.output_buffers;
297 
298   for (auto& metadata : request.input_buffer_metadata) {
299     block_request.input_buffer_metadata.push_back(
300         HalCameraMetadata::Clone(metadata.get()));
301   }
302 
303   for (auto& [camera_id, physical_metadata] : request.physical_camera_settings) {
304     block_request.physical_camera_settings[camera_id] =
305         HalCameraMetadata::Clone(physical_metadata.get());
306   }
307 
308   // Get one buffer from internal stream manager
309   StreamBuffer buffer = {};
310   status_t result;
311   if (preview_intent_seen_) {
312     result = internal_stream_manager_->GetStreamBuffer(stream_id_, &buffer);
313     if (result != OK) {
314       ALOGE("%s: frame:%d GetStreamBuffer failed.", __FUNCTION__,
315             request.frame_number);
316       return UNKNOWN_ERROR;
317     }
318   }
319 
320   // Add output to capture request
321   if (preview_intent_seen_) {
322     block_request.output_buffers.push_back(buffer);
323   }
324 
325   std::vector<ProcessBlockRequest> block_requests(1);
326   block_requests[0].request = std::move(block_request);
327   return process_block_->ProcessRequests(block_requests, request);
328 }
329 
Flush()330 status_t RealtimeZslRequestProcessor::Flush() {
331   ATRACE_CALL();
332   std::shared_lock lock(process_block_lock_);
333   if (process_block_ == nullptr) {
334     return OK;
335   }
336 
337   return process_block_->Flush();
338 }
339 
RepeatingRequestEnd(int32_t frame_number,const std::vector<int32_t> & stream_ids)340 void RealtimeZslRequestProcessor::RepeatingRequestEnd(
341     int32_t frame_number, const std::vector<int32_t>& stream_ids) {
342   ATRACE_CALL();
343   std::shared_lock lock(process_block_lock_);
344   if (process_block_ != nullptr) {
345     process_block_->RepeatingRequestEnd(frame_number, stream_ids);
346   }
347 }
348 
349 }  // namespace google_camera_hal
350 }  // namespace android
351