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_DualIrCaptureSession"
19 #define ATRACE_TAG ATRACE_TAG_CAMERA
20 #include "dual_ir_capture_session.h"
21 
22 #include <log/log.h>
23 #include <utils/Trace.h>
24 
25 #include <set>
26 #include <vector>
27 
28 #include "dual_ir_request_processor.h"
29 #include "dual_ir_result_request_processor.h"
30 #include "hal_utils.h"
31 #include "multicam_realtime_process_block.h"
32 
33 namespace android {
34 namespace google_camera_hal {
35 
IsStreamConfigurationSupported(CameraDeviceSessionHwl * device_session_hwl,const StreamConfiguration & stream_config)36 bool DualIrCaptureSession::IsStreamConfigurationSupported(
37     CameraDeviceSessionHwl* device_session_hwl,
38     const StreamConfiguration& stream_config) {
39   ATRACE_CALL();
40   if (device_session_hwl == nullptr) {
41     ALOGE("%s: device_session_hwl is nullptr", __FUNCTION__);
42     return false;
43   }
44 
45   std::vector<uint32_t> physical_camera_ids =
46       device_session_hwl->GetPhysicalCameraIds();
47   if (physical_camera_ids.size() != 2) {
48     ALOGD("%s: Only support two IR cameras but there are %zu cameras.",
49           __FUNCTION__, physical_camera_ids.size());
50     return false;
51   }
52 
53   // Check the two physical cameras are IR cameras.
54   for (auto id : physical_camera_ids) {
55     std::unique_ptr<HalCameraMetadata> characteristics;
56     status_t res = device_session_hwl->GetPhysicalCameraCharacteristics(
57         id, &characteristics);
58     if (res != OK) {
59       ALOGE("%s: Cannot get physical camera characteristics for camera %u",
60             __FUNCTION__, id);
61       return false;
62     }
63 
64     // TODO(b/129088371): Work around b/129088371 because current IR camera's
65     // CFA is MONO instead of NIR.
66     if (!hal_utils::IsIrCamera(characteristics.get()) &&
67         !hal_utils::IsMonoCamera(characteristics.get())) {
68       ALOGD("%s: camera %u is not an IR or MONO camera", __FUNCTION__, id);
69       return false;
70     }
71   }
72 
73   uint32_t physical_stream_number = 0;
74   uint32_t logical_stream_number = 0;
75   for (auto& stream : stream_config.streams) {
76     if (stream.is_physical_camera_stream) {
77       physical_stream_number++;
78     } else {
79       logical_stream_number++;
80     }
81   }
82   if (logical_stream_number > 0 && physical_stream_number > 0) {
83     ALOGD("%s: can't support mixed logical and physical stream", __FUNCTION__);
84     return false;
85   }
86 
87   ALOGD("%s: DualIrCaptureSession supports the stream config", __FUNCTION__);
88   return true;
89 }
90 
Create(CameraDeviceSessionHwl * device_session_hwl,const StreamConfiguration & stream_config,ProcessCaptureResultFunc process_capture_result,ProcessBatchCaptureResultFunc,NotifyFunc notify,HwlSessionCallback,std::vector<HalStream> * hal_configured_streams,CameraBufferAllocatorHwl *)91 std::unique_ptr<CaptureSession> DualIrCaptureSession::Create(
92     CameraDeviceSessionHwl* device_session_hwl,
93     const StreamConfiguration& stream_config,
94     ProcessCaptureResultFunc process_capture_result,
95     ProcessBatchCaptureResultFunc /*process_batch_capture_result*/,
96     NotifyFunc notify, HwlSessionCallback /*session_callback*/,
97     std::vector<HalStream>* hal_configured_streams,
98     CameraBufferAllocatorHwl* /*camera_allocator_hwl*/) {
99   ATRACE_CALL();
100   if (!IsStreamConfigurationSupported(device_session_hwl, stream_config)) {
101     ALOGE("%s: stream configuration is not supported.", __FUNCTION__);
102     return nullptr;
103   }
104 
105   // TODO(b/129707250): Assume the first physical camera is the lead until
106   // it's available in the static metadata.
107   std::vector<uint32_t> physical_camera_ids =
108       device_session_hwl->GetPhysicalCameraIds();
109   uint32_t lead_camera_id = physical_camera_ids[0];
110 
111   // If stream configuration only contains follower physical streams, set
112   // follower as lead.
113   bool has_lead_camera_config = false;
114   for (auto& stream : stream_config.streams) {
115     if (!stream.is_physical_camera_stream ||
116         (stream.is_physical_camera_stream &&
117          stream.physical_camera_id == physical_camera_ids[0])) {
118       has_lead_camera_config = true;
119       break;
120     }
121   }
122   if (!has_lead_camera_config) {
123     lead_camera_id = physical_camera_ids[1];
124   }
125 
126   auto session = std::unique_ptr<DualIrCaptureSession>(
127       new DualIrCaptureSession(lead_camera_id));
128   if (session == nullptr) {
129     ALOGE("%s: Creating DualIrCaptureSession failed.", __FUNCTION__);
130     return nullptr;
131   }
132 
133   status_t res = session->Initialize(device_session_hwl, stream_config,
134                                      process_capture_result, notify,
135                                      hal_configured_streams);
136   if (res != OK) {
137     ALOGE("%s: Initializing DualIrCaptureSession failed: %s (%d).",
138           __FUNCTION__, strerror(-res), res);
139     return nullptr;
140   }
141 
142   ALOGI("%s: Created a DualIrCaptureSession", __FUNCTION__);
143   return session;
144 }
145 
DualIrCaptureSession(uint32_t lead_camera_id)146 DualIrCaptureSession::DualIrCaptureSession(uint32_t lead_camera_id)
147     : kLeadCameraId(lead_camera_id) {
148 }
149 
~DualIrCaptureSession()150 DualIrCaptureSession::~DualIrCaptureSession() {
151   ATRACE_CALL();
152   if (device_session_hwl_ != nullptr) {
153     device_session_hwl_->DestroyPipelines();
154   }
155 }
156 
AreAllStreamsConfigured(const StreamConfiguration & stream_config,const StreamConfiguration & process_block_stream_config) const157 bool DualIrCaptureSession::AreAllStreamsConfigured(
158     const StreamConfiguration& stream_config,
159     const StreamConfiguration& process_block_stream_config) const {
160   ATRACE_CALL();
161   // Check all streams are configured.
162   if (stream_config.streams.size() !=
163       process_block_stream_config.streams.size()) {
164     ALOGE("%s: stream_config has %zu streams but only configured %zu streams",
165           __FUNCTION__, stream_config.streams.size(),
166           process_block_stream_config.streams.size());
167     return false;
168   }
169 
170   for (auto& stream : stream_config.streams) {
171     bool found = false;
172     for (auto& configured_stream : process_block_stream_config.streams) {
173       if (stream.id == configured_stream.id) {
174         found = true;
175         break;
176       }
177     }
178 
179     if (!found) {
180       ALOGE("%s: Cannot find stream %u in configured streams.", __FUNCTION__,
181             stream.id);
182       return false;
183     }
184   }
185 
186   return true;
187 }
188 
ConfigureStreams(RequestProcessor * request_processor,ProcessBlock * process_block,const StreamConfiguration & overall_config,const StreamConfiguration & stream_config,StreamConfiguration * process_block_stream_config)189 status_t DualIrCaptureSession::ConfigureStreams(
190     RequestProcessor* request_processor, ProcessBlock* process_block,
191     const StreamConfiguration& overall_config,
192     const StreamConfiguration& stream_config,
193     StreamConfiguration* process_block_stream_config) {
194   ATRACE_CALL();
195   if (request_processor == nullptr || process_block == nullptr) {
196     ALOGE("%s: request_processor(%p) or process_block(%p) is nullptr",
197           __FUNCTION__, request_processor, process_block);
198     return BAD_VALUE;
199   }
200 
201   status_t res = request_processor->ConfigureStreams(
202       internal_stream_manager_.get(), stream_config,
203       process_block_stream_config);
204   if (res != OK) {
205     ALOGE("%s: Configuring stream for RequestProcessor failed: %s(%d)",
206           __FUNCTION__, strerror(-res), res);
207     return res;
208   }
209 
210   res = process_block->ConfigureStreams(*process_block_stream_config,
211                                         overall_config);
212   if (res != OK) {
213     ALOGE("%s: Configuring streams for ProcessBlock failed: %s(%d)",
214           __FUNCTION__, strerror(-res), res);
215     return res;
216   }
217 
218   return OK;
219 }
220 
ConnectProcessChain(RequestProcessor * request_processor,std::unique_ptr<ProcessBlock> process_block,std::unique_ptr<ResultProcessor> result_processor)221 status_t DualIrCaptureSession::ConnectProcessChain(
222     RequestProcessor* request_processor,
223     std::unique_ptr<ProcessBlock> process_block,
224     std::unique_ptr<ResultProcessor> result_processor) {
225   ATRACE_CALL();
226   if (request_processor == nullptr) {
227     ALOGE("%s: request_processor is nullptr", __FUNCTION__);
228     return BAD_VALUE;
229   }
230 
231   status_t res = process_block->SetResultProcessor(std::move(result_processor));
232   if (res != OK) {
233     ALOGE("%s: Setting result process in process block failed.", __FUNCTION__);
234     return res;
235   }
236 
237   res = request_processor->SetProcessBlock(std::move(process_block));
238   if (res != OK) {
239     ALOGE("%s: Setting process block for request processor failed: %s(%d)",
240           __FUNCTION__, strerror(-res), res);
241     return res;
242   }
243 
244   return OK;
245 }
246 
PurgeHalConfiguredStream(const StreamConfiguration & stream_config,std::vector<HalStream> * hal_configured_streams)247 status_t DualIrCaptureSession::PurgeHalConfiguredStream(
248     const StreamConfiguration& stream_config,
249     std::vector<HalStream>* hal_configured_streams) {
250   if (hal_configured_streams == nullptr) {
251     ALOGE("%s: HAL configured stream list is null.", __FUNCTION__);
252     return BAD_VALUE;
253   }
254 
255   std::set<int32_t> framework_stream_id_set;
256   for (auto& stream : stream_config.streams) {
257     framework_stream_id_set.insert(stream.id);
258   }
259 
260   std::vector<HalStream> configured_streams;
261   for (auto& hal_stream : *hal_configured_streams) {
262     if (framework_stream_id_set.find(hal_stream.id) !=
263         framework_stream_id_set.end()) {
264       configured_streams.push_back(hal_stream);
265     }
266   }
267   *hal_configured_streams = configured_streams;
268   return OK;
269 }
270 
MakeDepthChainSegmentStreamConfig(const StreamConfiguration &,StreamConfiguration * rt_process_block_stream_config,StreamConfiguration * depth_chain_segment_stream_config)271 status_t DualIrCaptureSession::MakeDepthChainSegmentStreamConfig(
272     const StreamConfiguration& /*stream_config*/,
273     StreamConfiguration* rt_process_block_stream_config,
274     StreamConfiguration* depth_chain_segment_stream_config) {
275   if (depth_chain_segment_stream_config == nullptr ||
276       rt_process_block_stream_config == nullptr) {
277     ALOGE(
278         "%s: depth_chain_segment_stream_config is nullptr or "
279         "rt_process_block_stream_config is nullptr.",
280         __FUNCTION__);
281     return BAD_VALUE;
282   }
283   // TODO(b/131618554):
284   // Actually implement this function to form a depth chain segment stream
285   // config from the overall stream config and the streams mutli-camera realtime
286   // process block configured.
287   // This function signature may need to be changed.
288 
289   return OK;
290 }
291 
SetupRealtimeSegment(const StreamConfiguration & stream_config,StreamConfiguration * process_block_stream_config,std::unique_ptr<MultiCameraRtProcessBlock> * rt_process_block,std::unique_ptr<DualIrResultRequestProcessor> * rt_result_request_processor)292 status_t DualIrCaptureSession::SetupRealtimeSegment(
293     const StreamConfiguration& stream_config,
294     StreamConfiguration* process_block_stream_config,
295     std::unique_ptr<MultiCameraRtProcessBlock>* rt_process_block,
296     std::unique_ptr<DualIrResultRequestProcessor>* rt_result_request_processor) {
297   request_processor_ =
298       DualIrRequestProcessor::Create(device_session_hwl_, kLeadCameraId);
299   if (request_processor_ == nullptr) {
300     ALOGE("%s: Creating DualIrRtRequestProcessor failed.", __FUNCTION__);
301     return UNKNOWN_ERROR;
302   }
303 
304   auto process_block = MultiCameraRtProcessBlock::Create(device_session_hwl_);
305   if (process_block == nullptr) {
306     ALOGE("%s: Creating MultiCameraRtProcessBlock failed.", __FUNCTION__);
307     return UNKNOWN_ERROR;
308   }
309 
310   auto result_request_processor = DualIrResultRequestProcessor::Create(
311       device_session_hwl_, stream_config, kLeadCameraId);
312   if (result_request_processor == nullptr) {
313     ALOGE("%s: Creating DualIrResultRequestProcessor failed.", __FUNCTION__);
314     return UNKNOWN_ERROR;
315   }
316 
317   status_t res = ConfigureStreams(request_processor_.get(), process_block.get(),
318                                   stream_config, stream_config,
319                                   process_block_stream_config);
320   if (res != OK) {
321     ALOGE("%s: Configuring streams failed: %s(%d).", __FUNCTION__,
322           strerror(-res), res);
323     return res;
324   }
325 
326   *rt_process_block = std::move(process_block);
327   *rt_result_request_processor = std::move(result_request_processor);
328   return OK;
329 }
330 
SetupDepthSegment(const StreamConfiguration & stream_config,StreamConfiguration * process_block_stream_config,DualIrResultRequestProcessor * rt_result_request_processor,std::unique_ptr<DepthProcessBlock> * depth_process_block,std::unique_ptr<DualIrDepthResultProcessor> * depth_result_processor)331 status_t DualIrCaptureSession::SetupDepthSegment(
332     const StreamConfiguration& stream_config,
333     StreamConfiguration* process_block_stream_config,
334     DualIrResultRequestProcessor* rt_result_request_processor,
335     std::unique_ptr<DepthProcessBlock>* depth_process_block,
336     std::unique_ptr<DualIrDepthResultProcessor>* depth_result_processor) {
337   DepthProcessBlock::DepthProcessBlockCreateData data = {};
338   auto process_block =
339       DepthProcessBlock::Create(device_session_hwl_, nullptr, data);
340   if (process_block == nullptr) {
341     ALOGE("%s: Creating DepthProcessBlock failed.", __FUNCTION__);
342     return UNKNOWN_ERROR;
343   }
344 
345   auto result_processor =
346       DualIrDepthResultProcessor::Create(internal_stream_manager_.get());
347   if (result_processor == nullptr) {
348     ALOGE("%s: Creating DualIrDepthResultProcessor failed.", __FUNCTION__);
349     return UNKNOWN_ERROR;
350   }
351 
352   StreamConfiguration depth_pb_stream_config;
353   StreamConfiguration depth_chain_segment_stream_config;
354   status_t res = MakeDepthChainSegmentStreamConfig(
355       stream_config, process_block_stream_config,
356       &depth_chain_segment_stream_config);
357   if (res != OK) {
358     ALOGE("%s: Failed to make depth chain segment stream configuration: %s(%d)",
359           __FUNCTION__, strerror(-res), res);
360     return res;
361   }
362 
363   res = ConfigureStreams(rt_result_request_processor, process_block.get(),
364                          stream_config, depth_chain_segment_stream_config,
365                          &depth_pb_stream_config);
366   if (res != OK) {
367     ALOGE("%s: Failed to configure streams for the depth segment.",
368           __FUNCTION__);
369     return res;
370   }
371 
372   // Append the streams configured by depth process block. So
373   // process_block_stream_config contains all streams configured by both
374   // realtime and depth process blocks
375   process_block_stream_config->streams.insert(
376       process_block_stream_config->streams.end(),
377       depth_pb_stream_config.streams.begin(),
378       depth_pb_stream_config.streams.end());
379 
380   *depth_process_block = std::move(process_block);
381   *depth_result_processor = std::move(result_processor);
382 
383   return OK;
384 }
385 
BuildPipelines(const StreamConfiguration & stream_config,std::vector<HalStream> * hal_configured_streams,MultiCameraRtProcessBlock * rt_process_block,DepthProcessBlock * depth_process_block)386 status_t DualIrCaptureSession::BuildPipelines(
387     const StreamConfiguration& stream_config,
388     std::vector<HalStream>* hal_configured_streams,
389     MultiCameraRtProcessBlock* rt_process_block,
390     DepthProcessBlock* depth_process_block) {
391   status_t res = device_session_hwl_->BuildPipelines();
392   if (res != OK) {
393     ALOGE("%s: Building pipelines failed: %s(%d)", __FUNCTION__, strerror(-res),
394           res);
395     return res;
396   }
397 
398   res = rt_process_block->GetConfiguredHalStreams(hal_configured_streams);
399   if (res != OK) {
400     ALOGE("%s: Getting HAL streams failed: %s(%d)", __FUNCTION__,
401           strerror(-res), res);
402     return res;
403   }
404 
405   if (has_depth_stream_) {
406     std::vector<HalStream> depth_pb_configured_streams;
407     res = depth_process_block->GetConfiguredHalStreams(
408         &depth_pb_configured_streams);
409     if (res != OK) {
410       ALOGE("%s: Failed to get configured hal streams from DepthProcessBlock",
411             __FUNCTION__);
412       return UNKNOWN_ERROR;
413     }
414     // Depth Process Block can only configure one depth stream so far
415     if (depth_pb_configured_streams.size() != 1) {
416       ALOGE("%s: DepthProcessBlock configured more than one stream.",
417             __FUNCTION__);
418       return UNKNOWN_ERROR;
419     }
420     hal_configured_streams->push_back(depth_pb_configured_streams[0]);
421   }
422 
423   res = PurgeHalConfiguredStream(stream_config, hal_configured_streams);
424   if (res != OK) {
425     ALOGE("%s: Removing internal streams from configured stream failed: %s(%d)",
426           __FUNCTION__, strerror(-res), res);
427     return res;
428   }
429 
430   return OK;
431 }
432 
CreateProcessChain(const StreamConfiguration & stream_config,ProcessCaptureResultFunc process_capture_result,NotifyFunc notify,std::vector<HalStream> * hal_configured_streams)433 status_t DualIrCaptureSession::CreateProcessChain(
434     const StreamConfiguration& stream_config,
435     ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
436     std::vector<HalStream>* hal_configured_streams) {
437   ATRACE_CALL();
438 
439   // process_block_stream_config is used to collect all streams configured by
440   // both realtime and the depth process blocks. This is used to verify if all
441   // framework streams have been configured.
442   StreamConfiguration process_block_stream_config;
443 
444   std::unique_ptr<MultiCameraRtProcessBlock> rt_process_block;
445   std::unique_ptr<DualIrResultRequestProcessor> rt_result_request_processor;
446   status_t res =
447       SetupRealtimeSegment(stream_config, &process_block_stream_config,
448                            &rt_process_block, &rt_result_request_processor);
449   if (res != OK) {
450     ALOGE("%s: Failed to setup the realtime segment of the process chain.",
451           __FUNCTION__);
452     return res;
453   }
454 
455   // Create process block and result processor for Depth Process Chain Segment
456   std::unique_ptr<DepthProcessBlock> depth_process_block;
457   std::unique_ptr<DualIrDepthResultProcessor> depth_result_processor;
458   if (has_depth_stream_) {
459     status_t res =
460         SetupDepthSegment(stream_config, &process_block_stream_config,
461                           rt_result_request_processor.get(),
462                           &depth_process_block, &depth_result_processor);
463     if (res != OK) {
464       ALOGE("%s: Failed to setup the depth segment of the process chain.",
465             __FUNCTION__);
466       return res;
467     }
468   }
469 
470   if (!AreAllStreamsConfigured(stream_config, process_block_stream_config)) {
471     ALOGE("%s: Not all streams are configured!", __FUNCTION__);
472     return INVALID_OPERATION;
473   }
474 
475   res = BuildPipelines(stream_config, hal_configured_streams,
476                        rt_process_block.get(), depth_process_block.get());
477   if (res != OK) {
478     ALOGE("%s: Failed to build pipelines.", __FUNCTION__);
479     return res;
480   }
481 
482   // Only connect the depth segment of the realtime process chain when depth
483   // stream is configured
484   if (has_depth_stream_) {
485     depth_result_processor->SetResultCallback(
486         process_capture_result, notify,
487         /*process_batch_capture_result=*/nullptr);
488     res = ConnectProcessChain(rt_result_request_processor.get(),
489                               std::move(depth_process_block),
490                               std::move(depth_result_processor));
491     if (res != OK) {
492       ALOGE("%s: Connecting depth segment of realtime chain failed: %s(%d)",
493             __FUNCTION__, strerror(-res), res);
494       return res;
495     }
496   }
497 
498   rt_result_request_processor->SetResultCallback(
499       process_capture_result, notify, /*process_batch_capture_result=*/nullptr);
500   res =
501       ConnectProcessChain(request_processor_.get(), std::move(rt_process_block),
502                           std::move(rt_result_request_processor));
503   if (res != OK) {
504     ALOGE("%s: Connecting process chain failed: %s(%d)", __FUNCTION__,
505           strerror(-res), res);
506     return res;
507   }
508 
509   return OK;
510 }
511 
Initialize(CameraDeviceSessionHwl * device_session_hwl,const StreamConfiguration & stream_config,ProcessCaptureResultFunc process_capture_result,NotifyFunc notify,std::vector<HalStream> * hal_configured_streams)512 status_t DualIrCaptureSession::Initialize(
513     CameraDeviceSessionHwl* device_session_hwl,
514     const StreamConfiguration& stream_config,
515     ProcessCaptureResultFunc process_capture_result, NotifyFunc notify,
516     std::vector<HalStream>* hal_configured_streams) {
517   ATRACE_CALL();
518   device_session_hwl_ = device_session_hwl;
519 
520   internal_stream_manager_ = InternalStreamManager::Create();
521   if (internal_stream_manager_ == nullptr) {
522     ALOGE("%s: Cannot create internal stream manager.", __FUNCTION__);
523     return UNKNOWN_ERROR;
524   }
525 
526   for (auto& stream : stream_config.streams) {
527     if (utils::IsDepthStream(stream)) {
528       ALOGI("%s: Depth stream found in the stream config.", __FUNCTION__);
529       has_depth_stream_ = true;
530     }
531   }
532 
533   status_t res = CreateProcessChain(stream_config, process_capture_result,
534                                     notify, hal_configured_streams);
535   if (res != OK) {
536     ALOGE("%s: Creating the process  chain failed: %s(%d)", __FUNCTION__,
537           strerror(-res), res);
538     return res;
539   }
540 
541   return OK;
542 }
543 
ProcessRequest(const CaptureRequest & request)544 status_t DualIrCaptureSession::ProcessRequest(const CaptureRequest& request) {
545   ATRACE_CALL();
546   return request_processor_->ProcessRequest(request);
547 }
548 
Flush()549 status_t DualIrCaptureSession::Flush() {
550   ATRACE_CALL();
551   return request_processor_->Flush();
552 }
553 
554 }  // namespace google_camera_hal
555 }  // namespace android
556