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