/* * 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 #include #include #include #include #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& callback) : V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) { } CameraDeviceSession::~CameraDeviceSession() { } Return 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 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 *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 ( 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 CameraDeviceSession::processCaptureRequest_3_4( const hidl_vec& requests, const hidl_vec& cachesToRemove, ICameraDeviceSession::processCaptureRequest_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); } _hidl_cb(s, numRequestProcessed); return Void(); } Status CameraDeviceSession::processOneCaptureRequest_3_4(const 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.frameNumber; bool converted = true; V3_2::CameraMetadata settingsFmq; // settings from FMQ if (request.fmqSettingsSize > 0) { // non-blocking read; client must write metadata before calling // processOneCaptureRequest settingsFmq.resize(request.fmqSettingsSize); bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.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.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 allBufPtrs; hidl_vec allFences; bool hasInputBuf = (request.inputBuffer.streamId != -1 && request.inputBuffer.bufferId != 0); size_t numOutputBufs = request.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, allBufPtrs, allFences); if (status != Status::OK) { return status; } hidl_vec 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.inputBuffer.streamId; auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber); auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; convertFromHidl( allBufPtrs[numOutputBufs], request.inputBuffer.status, &mStreamMap[request.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.outputBuffers[i].streamId; auto key = std::make_pair(streamId, request.frameNumber); auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; convertFromHidl( allBufPtrs[i], request.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(); } } ATRACE_ASYNC_BEGIN("frame capture", request.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.inputBuffer.streamId, request.frameNumber); mInflightBuffers.erase(key); } for (size_t i = 0; i < numOutputBufs; i++) { auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber); mInflightBuffers.erase(key); } if (aeCancelTriggerNeeded) { mInflightAETriggerOverrides.erase(request.frameNumber); } return Status::INTERNAL_ERROR; } mFirstRequest = false; return Status::OK; } } // namespace implementation } // namespace V3_4 } // namespace device } // namespace camera } // namespace hardware } // namespace android