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