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_MultiCameraRtProcessBlock"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 #include <log/log.h>
21 #include <utils/Trace.h>
22 
23 #include <unordered_set>
24 
25 #include "hal_utils.h"
26 #include "multicam_realtime_process_block.h"
27 #include "result_processor.h"
28 
29 namespace android {
30 namespace google_camera_hal {
31 
Create(CameraDeviceSessionHwl * device_session_hwl)32 std::unique_ptr<MultiCameraRtProcessBlock> MultiCameraRtProcessBlock::Create(
33     CameraDeviceSessionHwl* device_session_hwl) {
34   ATRACE_CALL();
35   if (!IsSupported(device_session_hwl)) {
36     ALOGE("%s: Not supported.", __FUNCTION__);
37     return nullptr;
38   }
39 
40   auto block = std::unique_ptr<MultiCameraRtProcessBlock>(
41       new MultiCameraRtProcessBlock(device_session_hwl));
42   if (block == nullptr) {
43     ALOGE("%s: Creating MultiCameraRtProcessBlock failed.", __FUNCTION__);
44     return nullptr;
45   }
46   block->request_id_manager_ = PipelineRequestIdManager::Create();
47   if (block->request_id_manager_ == nullptr) {
48     ALOGE("%s: Creating PipelineRequestIdManager failed.", __FUNCTION__);
49     return nullptr;
50   }
51   return block;
52 }
53 
IsSupported(CameraDeviceSessionHwl * device_session_hwl)54 bool MultiCameraRtProcessBlock::IsSupported(
55     CameraDeviceSessionHwl* device_session_hwl) {
56   ATRACE_CALL();
57   if (device_session_hwl == nullptr) {
58     ALOGE("%s: device_session_hwl is nullptr", __FUNCTION__);
59     return false;
60   }
61 
62   if (device_session_hwl->GetPhysicalCameraIds().size() <= 1) {
63     ALOGE("%s: Only support multiple physical cameras", __FUNCTION__);
64     return false;
65   }
66 
67   return true;
68 }
69 
MultiCameraRtProcessBlock(CameraDeviceSessionHwl * device_session_hwl)70 MultiCameraRtProcessBlock::MultiCameraRtProcessBlock(
71     CameraDeviceSessionHwl* device_session_hwl)
72     : kCameraId(device_session_hwl->GetCameraId()),
73       device_session_hwl_(device_session_hwl) {
74   hwl_pipeline_callback_.process_pipeline_result = HwlProcessPipelineResultFunc(
75       [this](std::unique_ptr<HwlPipelineResult> result) {
76         NotifyHwlPipelineResult(std::move(result));
77       });
78 
79   hwl_pipeline_callback_.notify = NotifyHwlPipelineMessageFunc(
80       [this](uint32_t pipeline_id, const NotifyMessage& message) {
81         NotifyHwlPipelineMessage(pipeline_id, message);
82       });
83 }
84 
SetResultProcessor(std::unique_ptr<ResultProcessor> result_processor)85 status_t MultiCameraRtProcessBlock::SetResultProcessor(
86     std::unique_ptr<ResultProcessor> result_processor) {
87   ATRACE_CALL();
88   if (result_processor == nullptr) {
89     ALOGE("%s: result_processor is nullptr", __FUNCTION__);
90     return BAD_VALUE;
91   }
92 
93   std::lock_guard<std::mutex> lock(result_processor_mutex_);
94   if (result_processor_ != nullptr) {
95     ALOGE("%s: result_processor_ was already set.", __FUNCTION__);
96     return ALREADY_EXISTS;
97   }
98 
99   result_processor_ = std::move(result_processor);
100   return OK;
101 }
102 
GetCameraStreamConfigurationMap(const StreamConfiguration & stream_config,CameraStreamConfigurationMap * camera_stream_config_map) const103 status_t MultiCameraRtProcessBlock::GetCameraStreamConfigurationMap(
104     const StreamConfiguration& stream_config,
105     CameraStreamConfigurationMap* camera_stream_config_map) const {
106   if (camera_stream_config_map == nullptr) {
107     ALOGE("%s: camera_stream_config_map is nullptr", __FUNCTION__);
108     return BAD_VALUE;
109   }
110 
111   // Create one stream configuration for each camera.
112   camera_stream_config_map->clear();
113   for (auto& stream : stream_config.streams) {
114     if (!stream.is_physical_camera_stream) {
115       ALOGE("%s: Only physical streams are supported.", __FUNCTION__);
116       return BAD_VALUE;
117     }
118 
119     (*camera_stream_config_map)[stream.physical_camera_id].streams.push_back(
120         stream);
121   }
122 
123   // Copy the rest of the stream configuration fields
124   for (auto& [camera_id, config] : *camera_stream_config_map) {
125     config.operation_mode = stream_config.operation_mode;
126     config.session_params =
127         HalCameraMetadata::Clone(stream_config.session_params.get());
128     config.stream_config_counter = stream_config.stream_config_counter;
129   }
130 
131   return OK;
132 }
133 
ConfigureStreams(const StreamConfiguration & stream_config,const StreamConfiguration & overall_config)134 status_t MultiCameraRtProcessBlock::ConfigureStreams(
135     const StreamConfiguration& stream_config,
136     const StreamConfiguration& overall_config) {
137   ATRACE_CALL();
138   std::lock_guard lock(configure_shared_mutex_);
139   if (is_configured_) {
140     ALOGE("%s: Already configured.", __FUNCTION__);
141     return ALREADY_EXISTS;
142   }
143 
144   CameraStreamConfigurationMap camera_stream_configs;
145   status_t res =
146       GetCameraStreamConfigurationMap(stream_config, &camera_stream_configs);
147   if (res != OK) {
148     ALOGE("%s: Failed to get camera stream config map: %s(%d)", __FUNCTION__,
149           strerror(-res), res);
150     return res;
151   }
152 
153   configured_streams_.clear();
154   camera_pipeline_ids_.clear();
155 
156   // Configuration a pipeline for each camera.
157   for (auto& [camera_id, config] : camera_stream_configs) {
158     uint32_t pipeline_id = 0;
159     res = device_session_hwl_->ConfigurePipeline(
160         camera_id, hwl_pipeline_callback_, config, overall_config, &pipeline_id);
161     if (res != OK) {
162       ALOGE("%s: Configuring stream for camera %u failed: %s(%d)", __FUNCTION__,
163             camera_id, strerror(-res), res);
164       return res;
165     }
166     ALOGV("%s: config realtime pipeline camera id %u pipeline_id %u",
167           __FUNCTION__, camera_id, pipeline_id);
168 
169     camera_pipeline_ids_[camera_id] = pipeline_id;
170     for (auto& stream : config.streams) {
171       configured_streams_[stream.id].pipeline_id = pipeline_id;
172       configured_streams_[stream.id].stream = stream;
173     }
174   }
175 
176   is_configured_ = true;
177   return OK;
178 }
179 
GetConfiguredHalStreams(std::vector<HalStream> * hal_streams) const180 status_t MultiCameraRtProcessBlock::GetConfiguredHalStreams(
181     std::vector<HalStream>* hal_streams) const {
182   ATRACE_CALL();
183   std::lock_guard lock(configure_shared_mutex_);
184   if (hal_streams == nullptr) {
185     ALOGE("%s: hal_streams is nullptr.", __FUNCTION__);
186     return BAD_VALUE;
187   }
188 
189   if (!is_configured_) {
190     ALOGE("%s: Not configured yet.", __FUNCTION__);
191     return NO_INIT;
192   }
193 
194   hal_streams->clear();
195   for (auto& [camera_id, pipeline_id] : camera_pipeline_ids_) {
196     std::vector<HalStream> pipeline_hal_stream;
197     status_t res = device_session_hwl_->GetConfiguredHalStream(
198         pipeline_id, &pipeline_hal_stream);
199     if (res != OK) {
200       ALOGE("%s: Getting configured HAL streams for pipeline %u failed: %s(%d)",
201             __FUNCTION__, pipeline_id, strerror(-res), res);
202       return res;
203     }
204 
205     hal_streams->insert(hal_streams->end(), pipeline_hal_stream.begin(),
206                         pipeline_hal_stream.end());
207   }
208 
209   return OK;
210 }
211 
GetBufferPhysicalCameraIdLocked(const StreamBuffer & buffer,uint32_t * camera_id) const212 status_t MultiCameraRtProcessBlock::GetBufferPhysicalCameraIdLocked(
213     const StreamBuffer& buffer, uint32_t* camera_id) const {
214   if (camera_id == nullptr) {
215     ALOGE("%s: camera_id is nullptr", __FUNCTION__);
216     return BAD_VALUE;
217   }
218 
219   int32_t stream_id = buffer.stream_id;
220   auto configured_stream_iter = configured_streams_.find(stream_id);
221   if (configured_stream_iter == configured_streams_.end()) {
222     ALOGE("%s: Stream %d was not configured.", __FUNCTION__, stream_id);
223     return BAD_VALUE;
224   }
225 
226   const ConfiguredStream& configure_stream = configured_stream_iter->second;
227   if (!configure_stream.stream.is_physical_camera_stream) {
228     ALOGE("%s: Stream %d is not a physical stream.", __FUNCTION__, stream_id);
229     return BAD_VALUE;
230   }
231 
232   *camera_id = configure_stream.stream.physical_camera_id;
233   return OK;
234 }
235 
GetOutputBufferPipelineIdLocked(const StreamBuffer & buffer,uint32_t * pipeline_id) const236 status_t MultiCameraRtProcessBlock::GetOutputBufferPipelineIdLocked(
237     const StreamBuffer& buffer, uint32_t* pipeline_id) const {
238   if (pipeline_id == nullptr) {
239     ALOGE("%s: pipeline_id is nullptr", __FUNCTION__);
240     return BAD_VALUE;
241   }
242 
243   uint32_t camera_id;
244   status_t res = GetBufferPhysicalCameraIdLocked(buffer, &camera_id);
245   if (res != OK) {
246     ALOGE("%s: Getting buffer's physical camera ID failed: %s(%d)",
247           __FUNCTION__, strerror(-res), res);
248     return res;
249   }
250 
251   auto camera_pipeline_id_iter = camera_pipeline_ids_.find(camera_id);
252   if (camera_pipeline_id_iter == camera_pipeline_ids_.end()) {
253     ALOGE("%s: Cannot find the pipeline ID for camera %u", __FUNCTION__,
254           camera_id);
255     return BAD_VALUE;
256   }
257 
258   *pipeline_id = camera_pipeline_id_iter->second;
259   return OK;
260 }
261 
AreRequestsValidLocked(const std::vector<ProcessBlockRequest> & block_requests) const262 bool MultiCameraRtProcessBlock::AreRequestsValidLocked(
263     const std::vector<ProcessBlockRequest>& block_requests) const {
264   ATRACE_CALL();
265   if (block_requests.empty()) {
266     ALOGE("%s: requests is empty.", __FUNCTION__);
267     return false;
268   }
269 
270   std::unordered_set<int32_t> request_camera_ids;
271   uint32_t frame_number = block_requests[0].request.frame_number;
272   for (auto& block_request : block_requests) {
273     if (block_request.request.output_buffers.size() == 0) {
274       ALOGE("%s: request %u doesn't contain any output streams.", __FUNCTION__,
275             block_request.request.frame_number);
276       return false;
277     }
278 
279     if (block_request.request.frame_number != frame_number) {
280       ALOGE("%s: Not all frame numbers in requests are the same.", __FUNCTION__);
281       return false;
282     }
283 
284     // Check all output buffers will be captured from the same physical camera.
285     uint32_t physical_camera_id;
286     for (uint32_t i = 0; i < block_request.request.output_buffers.size(); i++) {
287       uint32_t buffer_camera_id;
288       status_t res = GetBufferPhysicalCameraIdLocked(
289           block_request.request.output_buffers[0], &buffer_camera_id);
290       if (res != OK) {
291         ALOGE("%s: Getting buffer's physical camera ID failed: %s(%d)",
292               __FUNCTION__, strerror(-res), res);
293         return false;
294       }
295 
296       if (i == 0) {
297         physical_camera_id = buffer_camera_id;
298       } else if (buffer_camera_id != physical_camera_id) {
299         ALOGE("%s: Buffers should belong to the same camera ID in a request.",
300               __FUNCTION__);
301         return false;
302       }
303     }
304 
305     // Check no two requests will be captured from the same physical camera.
306     if (request_camera_ids.find(physical_camera_id) != request_camera_ids.end()) {
307       ALOGE("%s: No two requests can be captured from the same camera ID (%u).",
308             __FUNCTION__, physical_camera_id);
309       return false;
310     }
311 
312     request_camera_ids.insert(physical_camera_id);
313   }
314 
315   return true;
316 }
317 
ForwardPendingRequests(const std::vector<ProcessBlockRequest> & process_block_requests,const CaptureRequest & remaining_session_request)318 status_t MultiCameraRtProcessBlock::ForwardPendingRequests(
319     const std::vector<ProcessBlockRequest>& process_block_requests,
320     const CaptureRequest& remaining_session_request) {
321   std::lock_guard<std::mutex> lock(result_processor_mutex_);
322   if (result_processor_ == nullptr) {
323     ALOGE("%s: result processor was not set.", __FUNCTION__);
324     return NO_INIT;
325   }
326 
327   return result_processor_->AddPendingRequests(process_block_requests,
328                                                remaining_session_request);
329 }
330 
PrepareBlockByCameraId(uint32_t camera_id,uint32_t frame_number)331 status_t MultiCameraRtProcessBlock::PrepareBlockByCameraId(
332     uint32_t camera_id, uint32_t frame_number) {
333   return device_session_hwl_->PreparePipeline(camera_pipeline_ids_[camera_id],
334                                               frame_number);
335 }
336 
ProcessRequests(const std::vector<ProcessBlockRequest> & process_block_requests,const CaptureRequest & remaining_session_request)337 status_t MultiCameraRtProcessBlock::ProcessRequests(
338     const std::vector<ProcessBlockRequest>& process_block_requests,
339     const CaptureRequest& remaining_session_request) {
340   ATRACE_CALL();
341   std::shared_lock lock(configure_shared_mutex_);
342   if (configured_streams_.empty()) {
343     ALOGE("%s: block is not configured.", __FUNCTION__);
344     return NO_INIT;
345   }
346 
347   if (!AreRequestsValidLocked(process_block_requests)) {
348     ALOGE("%s: Requests are not supported.", __FUNCTION__);
349     return BAD_VALUE;
350   }
351 
352   status_t res =
353       ForwardPendingRequests(process_block_requests, remaining_session_request);
354   if (res != OK) {
355     ALOGE("%s: Forwarding pending requests failed: %s(%d)", __FUNCTION__,
356           strerror(-res), res);
357     return res;
358   }
359 
360   // Get pipeline ID for each request.
361   std::vector<uint32_t> pipeline_ids;
362   for (auto& block_request : process_block_requests) {
363     uint32_t pipeline_id;
364 
365     // Get the camera ID of the request's first output buffer. All output
366     // buffers should belong to the same pipeline ID, which is checked in
367     // AreRequestsSupportedLocked.
368     res = GetOutputBufferPipelineIdLocked(
369         block_request.request.output_buffers[0], &pipeline_id);
370     if (res != OK) {
371       ALOGE("%s: Getting buffer's pipeline ID failed: %s(%d)", __FUNCTION__,
372             strerror(-res), res);
373       return res;
374     }
375 
376     res = request_id_manager_->SetPipelineRequestId(
377         block_request.request_id, block_request.request.frame_number,
378         pipeline_id);
379     if (res != OK) {
380       ALOGE("%s: Adding pipeline request id info failed: %s(%d)", __FUNCTION__,
381             strerror(-res), res);
382       return res;
383     }
384 
385     pipeline_ids.push_back(pipeline_id);
386     ALOGV("%s: frame_number %u pipeline_id %u request_id %u", __FUNCTION__,
387           block_request.request.frame_number, pipeline_id,
388           block_request.request_id);
389   }
390 
391   std::vector<HwlPipelineRequest> hwl_requests;
392   res = hal_utils::CreateHwlPipelineRequests(&hwl_requests, pipeline_ids,
393                                              process_block_requests);
394   if (res != OK) {
395     ALOGE("%s: Creating HWL pipeline requests failed: %s(%d)", __FUNCTION__,
396           strerror(-res), res);
397     return res;
398   }
399 
400   return device_session_hwl_->SubmitRequests(
401       process_block_requests[0].request.frame_number, hwl_requests);
402 }
403 
Flush()404 status_t MultiCameraRtProcessBlock::Flush() {
405   ATRACE_CALL();
406   std::shared_lock lock(configure_shared_mutex_);
407   if (configured_streams_.empty()) {
408     return OK;
409   }
410 
411   status_t res = device_session_hwl_->Flush();
412   if (res != OK) {
413     ALOGE("%s: Flushing hwl device session failed.", __FUNCTION__);
414     return res;
415   }
416 
417   if (result_processor_ == nullptr) {
418     ALOGW("%s: result processor is nullptr.", __FUNCTION__);
419     return res;
420   }
421 
422   return result_processor_->FlushPendingRequests();
423 }
424 
NotifyHwlPipelineResult(std::unique_ptr<HwlPipelineResult> hwl_result)425 void MultiCameraRtProcessBlock::NotifyHwlPipelineResult(
426     std::unique_ptr<HwlPipelineResult> hwl_result) {
427   ATRACE_CALL();
428   std::lock_guard<std::mutex> lock(result_processor_mutex_);
429   if (result_processor_ == nullptr) {
430     ALOGE("%s: result processor is nullptr. Dropping a result", __FUNCTION__);
431     return;
432   }
433 
434   uint32_t frame_number = hwl_result->frame_number;
435   uint32_t pipeline_id = hwl_result->pipeline_id;
436   if (hwl_result->result_metadata == nullptr &&
437       hwl_result->input_buffers.empty() && hwl_result->output_buffers.empty()) {
438     ALOGV("%s: Skip empty result. pipeline_id %u frame_number %u", __FUNCTION__,
439           pipeline_id, frame_number);
440     return;
441   }
442   auto capture_result = hal_utils::ConvertToCaptureResult(std::move(hwl_result));
443   if (capture_result == nullptr) {
444     ALOGE("%s: Converting to capture result failed.", __FUNCTION__);
445     return;
446   }
447 
448   ALOGV(
449       "%s: pipeline id %u frame_number %u output_buffer size %zu input_buffers "
450       "size %zu metadata %p ",
451       __FUNCTION__, pipeline_id, frame_number,
452       capture_result->output_buffers.size(),
453       capture_result->input_buffers.size(),
454       capture_result->result_metadata.get());
455 
456   uint32_t request_id = 0;
457   status_t res = request_id_manager_->GetPipelineRequestId(
458       pipeline_id, frame_number, &request_id);
459   if (res != OK) {
460     ALOGE("%s: Get request Id and remove pending failed. res %d", __FUNCTION__,
461           res);
462     return;
463   }
464 
465   ProcessBlockResult block_result = {.request_id = request_id,
466                                      .result = std::move(capture_result)};
467   result_processor_->ProcessResult(std::move(block_result));
468 }
469 
NotifyHwlPipelineMessage(uint32_t pipeline_id,const NotifyMessage & message)470 void MultiCameraRtProcessBlock::NotifyHwlPipelineMessage(
471     uint32_t pipeline_id, const NotifyMessage& message) {
472   ATRACE_CALL();
473   std::lock_guard<std::mutex> lock(result_processor_mutex_);
474   if (result_processor_ == nullptr) {
475     ALOGE("%s: result processor is nullptr. Dropping a message", __FUNCTION__);
476     return;
477   }
478   uint32_t frame_number = message.type == MessageType::kShutter
479                               ? message.message.shutter.frame_number
480                               : message.message.error.frame_number;
481   ALOGV("%s: pipeline id %u frame_number %u type %d", __FUNCTION__, pipeline_id,
482         frame_number, message.type);
483   uint32_t request_id = 0;
484   status_t res = request_id_manager_->GetPipelineRequestId(
485       pipeline_id, frame_number, &request_id);
486   if (res != OK) {
487     ALOGE("%s: Get request Id and remove pending failed. res %d", __FUNCTION__,
488           res);
489     return;
490   }
491   ProcessBlockNotifyMessage block_message = {.request_id = request_id,
492                                              .message = message};
493   result_processor_->Notify(std::move(block_message));
494 }
495 
496 }  // namespace google_camera_hal
497 }  // namespace android
498