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