| /* |
| * Copyright (C) 2017-2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "CamDevSession@3.4-impl" |
| #include <android/log.h> |
| |
| #include <set> |
| #include <utils/Trace.h> |
| #include <hardware/gralloc.h> |
| #include <hardware/gralloc1.h> |
| #include "CameraDeviceSession.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace camera { |
| namespace device { |
| namespace V3_4 { |
| namespace implementation { |
| |
| CameraDeviceSession::CameraDeviceSession( |
| camera3_device_t* device, |
| const camera_metadata_t* deviceInfo, |
| const sp<V3_2::ICameraDeviceCallback>& callback) : |
| V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) { |
| } |
| |
| CameraDeviceSession::~CameraDeviceSession() { |
| } |
| |
| Return<void> CameraDeviceSession::configureStreams_3_4( |
| const StreamConfiguration& requestedConfiguration, |
| ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { |
| Status status = initStatus(); |
| HalStreamConfiguration outStreams; |
| |
| // hold the inflight lock for entire configureStreams scope since there must not be any |
| // inflight request/results during stream configuration. |
| Mutex::Autolock _l(mInflightLock); |
| if (!mInflightBuffers.empty()) { |
| ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", |
| __FUNCTION__, mInflightBuffers.size()); |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return Void(); |
| } |
| |
| if (!mInflightAETriggerOverrides.empty()) { |
| ALOGE("%s: trying to configureStreams while there are still %zu inflight" |
| " trigger overrides!", __FUNCTION__, |
| mInflightAETriggerOverrides.size()); |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return Void(); |
| } |
| |
| if (!mInflightRawBoostPresent.empty()) { |
| ALOGE("%s: trying to configureStreams while there are still %zu inflight" |
| " boost overrides!", __FUNCTION__, |
| mInflightRawBoostPresent.size()); |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return Void(); |
| } |
| |
| if (status != Status::OK) { |
| _hidl_cb(status, outStreams); |
| return Void(); |
| } |
| |
| const camera_metadata_t *paramBuffer = nullptr; |
| if (0 < requestedConfiguration.sessionParams.size()) { |
| ::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams; |
| V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, ¶mBuffer); |
| } |
| |
| camera3_stream_configuration_t stream_list{}; |
| hidl_vec<camera3_stream_t*> streams; |
| stream_list.session_parameters = paramBuffer; |
| if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) { |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return Void(); |
| } |
| |
| ATRACE_BEGIN("camera3->configure_streams"); |
| status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); |
| ATRACE_END(); |
| |
| // In case Hal returns error most likely it was not able to release |
| // the corresponding resources of the deleted streams. |
| if (ret == OK) { |
| postProcessConfigurationLocked_3_4(requestedConfiguration); |
| } |
| |
| if (ret == -EINVAL) { |
| status = Status::ILLEGAL_ARGUMENT; |
| } else if (ret != OK) { |
| status = Status::INTERNAL_ERROR; |
| } else { |
| V3_4::implementation::convertToHidl(stream_list, &outStreams); |
| mFirstRequest = true; |
| } |
| |
| _hidl_cb(status, outStreams); |
| return Void(); |
| } |
| |
| bool CameraDeviceSession::preProcessConfigurationLocked_3_4( |
| const StreamConfiguration& requestedConfiguration, |
| camera3_stream_configuration_t *stream_list /*out*/, |
| hidl_vec<camera3_stream_t*> *streams /*out*/) { |
| |
| if ((stream_list == nullptr) || (streams == nullptr)) { |
| return false; |
| } |
| |
| stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode; |
| stream_list->num_streams = requestedConfiguration.streams.size(); |
| streams->resize(stream_list->num_streams); |
| stream_list->streams = streams->data(); |
| |
| for (uint32_t i = 0; i < stream_list->num_streams; i++) { |
| int id = requestedConfiguration.streams[i].v3_2.id; |
| |
| if (mStreamMap.count(id) == 0) { |
| Camera3Stream stream; |
| convertFromHidl(requestedConfiguration.streams[i], &stream); |
| mStreamMap[id] = stream; |
| mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId; |
| mStreamMap[id].data_space = mapToLegacyDataspace( |
| mStreamMap[id].data_space); |
| mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str(); |
| mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); |
| } else { |
| // width/height/format must not change, but usage/rotation might need to change |
| if (mStreamMap[id].stream_type != |
| (int) requestedConfiguration.streams[i].v3_2.streamType || |
| mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width || |
| mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height || |
| mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format || |
| mStreamMap[id].data_space != |
| mapToLegacyDataspace( static_cast<android_dataspace_t> ( |
| requestedConfiguration.streams[i].v3_2.dataSpace)) || |
| mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) { |
| ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); |
| return false; |
| } |
| mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation; |
| mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage; |
| } |
| (*streams)[i] = &mStreamMap[id]; |
| } |
| |
| return true; |
| } |
| |
| void CameraDeviceSession::postProcessConfigurationLocked_3_4( |
| const StreamConfiguration& requestedConfiguration) { |
| // delete unused streams, note we do this after adding new streams to ensure new stream |
| // will not have the same address as deleted stream, and HAL has a chance to reference |
| // the to be deleted stream in configure_streams call |
| for(auto it = mStreamMap.begin(); it != mStreamMap.end();) { |
| int id = it->first; |
| bool found = false; |
| for (const auto& stream : requestedConfiguration.streams) { |
| if (id == stream.v3_2.id) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| // Unmap all buffers of deleted stream |
| // in case the configuration call succeeds and HAL |
| // is able to release the corresponding resources too. |
| cleanupBuffersLocked(id); |
| it = mStreamMap.erase(it); |
| } else { |
| ++it; |
| } |
| } |
| |
| // Track video streams |
| mVideoStreamIds.clear(); |
| for (const auto& stream : requestedConfiguration.streams) { |
| if (stream.v3_2.streamType == StreamType::OUTPUT && |
| stream.v3_2.usage & |
| graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) { |
| mVideoStreamIds.push_back(stream.v3_2.id); |
| } |
| } |
| mResultBatcher.setBatchedStreams(mVideoStreamIds); |
| } |
| |
| Return<void> CameraDeviceSession::processCaptureRequest_3_4( |
| const hidl_vec<V3_4::CaptureRequest>& requests, |
| const hidl_vec<V3_2::BufferCache>& cachesToRemove, |
| ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) { |
| updateBufferCaches(cachesToRemove); |
| |
| uint32_t numRequestProcessed = 0; |
| Status s = Status::OK; |
| for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) { |
| s = processOneCaptureRequest_3_4(requests[i]); |
| if (s != Status::OK) { |
| break; |
| } |
| } |
| |
| if (s == Status::OK && requests.size() > 1) { |
| mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size()); |
| } |
| |
| _hidl_cb(s, numRequestProcessed); |
| return Void(); |
| } |
| |
| Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request) { |
| Status status = initStatus(); |
| if (status != Status::OK) { |
| ALOGE("%s: camera init failed or disconnected", __FUNCTION__); |
| return status; |
| } |
| |
| camera3_capture_request_t halRequest; |
| halRequest.frame_number = request.v3_2.frameNumber; |
| |
| bool converted = true; |
| V3_2::CameraMetadata settingsFmq; // settings from FMQ |
| if (request.v3_2.fmqSettingsSize > 0) { |
| // non-blocking read; client must write metadata before calling |
| // processOneCaptureRequest |
| settingsFmq.resize(request.v3_2.fmqSettingsSize); |
| bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.v3_2.fmqSettingsSize); |
| if (read) { |
| converted = V3_2::implementation::convertFromHidl(settingsFmq, &halRequest.settings); |
| } else { |
| ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__); |
| converted = false; |
| } |
| } else { |
| converted = V3_2::implementation::convertFromHidl(request.v3_2.settings, |
| &halRequest.settings); |
| } |
| |
| if (!converted) { |
| ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__); |
| return Status::ILLEGAL_ARGUMENT; |
| } |
| |
| if (mFirstRequest && halRequest.settings == nullptr) { |
| ALOGE("%s: capture request settings must not be null for first request!", |
| __FUNCTION__); |
| return Status::ILLEGAL_ARGUMENT; |
| } |
| |
| hidl_vec<buffer_handle_t*> allBufPtrs; |
| hidl_vec<int> allFences; |
| bool hasInputBuf = (request.v3_2.inputBuffer.streamId != -1 && |
| request.v3_2.inputBuffer.bufferId != 0); |
| size_t numOutputBufs = request.v3_2.outputBuffers.size(); |
| size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); |
| |
| if (numOutputBufs == 0) { |
| ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__); |
| return Status::ILLEGAL_ARGUMENT; |
| } |
| |
| status = importRequest(request.v3_2, allBufPtrs, allFences); |
| if (status != Status::OK) { |
| return status; |
| } |
| |
| hidl_vec<camera3_stream_buffer_t> outHalBufs; |
| outHalBufs.resize(numOutputBufs); |
| bool aeCancelTriggerNeeded = false; |
| ::android::hardware::camera::common::V1_0::helper::CameraMetadata settingsOverride; |
| { |
| Mutex::Autolock _l(mInflightLock); |
| if (hasInputBuf) { |
| auto streamId = request.v3_2.inputBuffer.streamId; |
| auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber); |
| auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; |
| convertFromHidl( |
| allBufPtrs[numOutputBufs], request.v3_2.inputBuffer.status, |
| &mStreamMap[request.v3_2.inputBuffer.streamId], allFences[numOutputBufs], |
| &bufCache); |
| bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str(); |
| halRequest.input_buffer = &bufCache; |
| } else { |
| halRequest.input_buffer = nullptr; |
| } |
| |
| halRequest.num_output_buffers = numOutputBufs; |
| for (size_t i = 0; i < numOutputBufs; i++) { |
| auto streamId = request.v3_2.outputBuffers[i].streamId; |
| auto key = std::make_pair(streamId, request.v3_2.frameNumber); |
| auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; |
| convertFromHidl( |
| allBufPtrs[i], request.v3_2.outputBuffers[i].status, |
| &mStreamMap[streamId], allFences[i], |
| &bufCache); |
| bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str(); |
| outHalBufs[i] = bufCache; |
| } |
| halRequest.output_buffers = outHalBufs.data(); |
| |
| AETriggerCancelOverride triggerOverride; |
| aeCancelTriggerNeeded = handleAePrecaptureCancelRequestLocked( |
| halRequest, &settingsOverride /*out*/, &triggerOverride/*out*/); |
| if (aeCancelTriggerNeeded) { |
| mInflightAETriggerOverrides[halRequest.frame_number] = |
| triggerOverride; |
| halRequest.settings = settingsOverride.getAndLock(); |
| } |
| } |
| |
| std::vector<const char *> physicalCameraIds; |
| std::vector<const camera_metadata_t *> physicalCameraSettings; |
| std::vector<V3_2::CameraMetadata> physicalFmq; |
| size_t settingsCount = request.physicalCameraSettings.size(); |
| if (settingsCount > 0) { |
| physicalCameraIds.reserve(settingsCount); |
| physicalCameraSettings.reserve(settingsCount); |
| physicalFmq.reserve(settingsCount); |
| |
| for (size_t i = 0; i < settingsCount; i++) { |
| uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize; |
| const camera_metadata_t *settings; |
| if (settingsSize > 0) { |
| physicalFmq.push_back(V3_2::CameraMetadata(settingsSize)); |
| bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize); |
| if (read) { |
| converted = V3_2::implementation::convertFromHidl(physicalFmq[i], &settings); |
| physicalCameraSettings.push_back(settings); |
| } else { |
| ALOGE("%s: physical camera settings metadata couldn't be read from fmq!", |
| __FUNCTION__); |
| converted = false; |
| } |
| } else { |
| converted = V3_2::implementation::convertFromHidl( |
| request.physicalCameraSettings[i].settings, &settings); |
| physicalCameraSettings.push_back(settings); |
| } |
| |
| if (!converted) { |
| ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__); |
| return Status::ILLEGAL_ARGUMENT; |
| } |
| physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str()); |
| } |
| } |
| halRequest.num_physcam_settings = settingsCount; |
| halRequest.physcam_id = physicalCameraIds.data(); |
| halRequest.physcam_settings = physicalCameraSettings.data(); |
| |
| ATRACE_ASYNC_BEGIN("frame capture", request.v3_2.frameNumber); |
| ATRACE_BEGIN("camera3->process_capture_request"); |
| status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest); |
| ATRACE_END(); |
| if (aeCancelTriggerNeeded) { |
| settingsOverride.unlock(halRequest.settings); |
| } |
| if (ret != OK) { |
| Mutex::Autolock _l(mInflightLock); |
| ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__); |
| |
| cleanupInflightFences(allFences, numBufs); |
| if (hasInputBuf) { |
| auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber); |
| mInflightBuffers.erase(key); |
| } |
| for (size_t i = 0; i < numOutputBufs; i++) { |
| auto key = std::make_pair(request.v3_2.outputBuffers[i].streamId, |
| request.v3_2.frameNumber); |
| mInflightBuffers.erase(key); |
| } |
| if (aeCancelTriggerNeeded) { |
| mInflightAETriggerOverrides.erase(request.v3_2.frameNumber); |
| } |
| |
| if (ret == BAD_VALUE) { |
| return Status::ILLEGAL_ARGUMENT; |
| } else { |
| return Status::INTERNAL_ERROR; |
| } |
| } |
| |
| mFirstRequest = false; |
| return Status::OK; |
| } |
| |
| } // namespace implementation |
| } // namespace V3_4 |
| } // namespace device |
| } // namespace camera |
| } // namespace hardware |
| } // namespace android |