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