| /* |
| * 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" |
| #include "CameraModule.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace camera { |
| namespace device { |
| namespace V3_4 { |
| namespace implementation { |
| |
| using ::android::hardware::camera::common::V1_0::helper::CameraModule; |
| |
| CameraDeviceSession::CameraDeviceSession( |
| camera3_device_t* device, |
| const camera_metadata_t* deviceInfo, |
| const sp<V3_2::ICameraDeviceCallback>& callback) : |
| V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback), |
| mResultBatcher_3_4(callback) { |
| |
| mHasCallback_3_4 = false; |
| |
| auto castResult = ICameraDeviceCallback::castFrom(callback); |
| if (castResult.isOk()) { |
| sp<ICameraDeviceCallback> callback3_4 = castResult; |
| if (callback3_4 != nullptr) { |
| process_capture_result = sProcessCaptureResult_3_4; |
| notify = sNotify_3_4; |
| mHasCallback_3_4 = true; |
| if (!mInitFail) { |
| mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue); |
| } |
| } |
| } |
| |
| mResultBatcher_3_4.setNumPartialResults(mNumPartialResults); |
| |
| // Parse and store current logical camera's physical ids. |
| (void)CameraModule::isLogicalMultiCamera(mDeviceInfo, &mPhysicalCameraIds); |
| |
| } |
| |
| CameraDeviceSession::~CameraDeviceSession() { |
| } |
| |
| Return<void> CameraDeviceSession::configureStreams_3_4( |
| const StreamConfiguration& requestedConfiguration, |
| ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { |
| configureStreams_3_4_Impl(requestedConfiguration, _hidl_cb); |
| return Void(); |
| } |
| |
| void CameraDeviceSession::configureStreams_3_4_Impl( |
| const StreamConfiguration& requestedConfiguration, |
| ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb, |
| uint32_t streamConfigCounter, bool useOverriddenFields) { |
| Status status = initStatus(); |
| HalStreamConfiguration outStreams; |
| |
| // If callback is 3.2, make sure no physical stream is configured |
| if (!mHasCallback_3_4) { |
| for (size_t i = 0; i < requestedConfiguration.streams.size(); i++) { |
| if (requestedConfiguration.streams[i].physicalCameraId.size() > 0) { |
| ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback", |
| __FUNCTION__); |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return; |
| } |
| } |
| } |
| |
| // 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; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| if (status != Status::OK) { |
| _hidl_cb(status, outStreams); |
| return; |
| } |
| |
| const camera_metadata_t *paramBuffer = nullptr; |
| if (0 < requestedConfiguration.sessionParams.size()) { |
| V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, ¶mBuffer); |
| } |
| |
| camera3_stream_configuration_t stream_list{}; |
| // Block reading mStreamConfigCounter until configureStream returns |
| Mutex::Autolock _sccl(mStreamConfigCounterLock); |
| mStreamConfigCounter = streamConfigCounter; |
| hidl_vec<camera3_stream_t*> streams; |
| stream_list.session_parameters = paramBuffer; |
| if (!preProcessConfigurationLocked_3_4(requestedConfiguration, |
| useOverriddenFields, &stream_list, &streams)) { |
| _hidl_cb(Status::INTERNAL_ERROR, outStreams); |
| return; |
| } |
| |
| 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); |
| } else { |
| postProcessConfigurationFailureLocked_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; |
| } |
| |
| bool CameraDeviceSession::preProcessConfigurationLocked_3_4( |
| const StreamConfiguration& requestedConfiguration, bool useOverriddenFields, |
| 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); |
| mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); |
| } else { |
| // width/height/format must not change, but usage/rotation might need to change. |
| // format and data_space may 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 || |
| mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) { |
| ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); |
| return false; |
| } |
| if (useOverriddenFields) { |
| android_dataspace_t requestedDataSpace = |
| mapToLegacyDataspace(static_cast<android_dataspace_t>( |
| requestedConfiguration.streams[i].v3_2.dataSpace)); |
| if (mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format || |
| mStreamMap[id].data_space != requestedDataSpace) { |
| ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); |
| return false; |
| } |
| } else { |
| mStreamMap[id].format = |
| (int) requestedConfiguration.streams[i].v3_2.format; |
| mStreamMap[id].data_space = (android_dataspace_t) |
| requestedConfiguration.streams[i].v3_2.dataSpace; |
| } |
| mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation; |
| mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage; |
| } |
| // It is possible for the entry in 'mStreamMap' to get initialized by an older |
| // HIDL API. Make sure that the physical id is always initialized when using |
| // a more recent API call. |
| mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str(); |
| |
| (*streams)[i] = &mStreamMap[id]; |
| } |
| |
| if (mFreeBufEarly) { |
| // Remove buffers of deleted streams |
| for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) { |
| 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 |
| cleanupBuffersLocked(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. |
| if (!mFreeBufEarly) { |
| 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_3_4.setBatchedStreams(mVideoStreamIds); |
| } |
| |
| void CameraDeviceSession::postProcessConfigurationFailureLocked_3_4( |
| const StreamConfiguration& requestedConfiguration) { |
| if (mFreeBufEarly) { |
| // Re-build the buf cache entry for deleted streams |
| for(auto it = mStreamMap.begin(); it != mStreamMap.end(); it++) { |
| int id = it->first; |
| bool found = false; |
| for (const auto& stream : requestedConfiguration.streams) { |
| if (id == stream.v3_2.id) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| mCirculatingBuffers.emplace(id, CirculatingBuffers{}); |
| } |
| } |
| } |
| } |
| |
| 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_3_4.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; |
| } |
| // If callback is 3.2, make sure there are no physical settings. |
| if (!mHasCallback_3_4) { |
| if (request.physicalCameraSettings.size() > 0) { |
| ALOGE("%s: trying to call processCaptureRequest_3_4 with physical camera id " |
| "and V3.2 callback", __FUNCTION__); |
| return Status::INTERNAL_ERROR; |
| } |
| } |
| |
| 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 = nullptr; |
| 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; |
| } |
| |
| if (mFirstRequest && settings == nullptr) { |
| ALOGE("%s: Individual request settings must not be null for first request!", |
| __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; |
| } |
| |
| /** |
| * Static callback forwarding methods from HAL to instance |
| */ |
| void CameraDeviceSession::sProcessCaptureResult_3_4( |
| const camera3_callback_ops *cb, |
| const camera3_capture_result *hal_result) { |
| CameraDeviceSession *d = |
| const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); |
| |
| CaptureResult result = {}; |
| camera3_capture_result shadowResult; |
| bool handlePhysCam = (d->mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5); |
| std::vector<::android::hardware::camera::common::V1_0::helper::CameraMetadata> compactMds; |
| std::vector<const camera_metadata_t*> physCamMdArray; |
| sShrinkCaptureResult(&shadowResult, hal_result, &compactMds, &physCamMdArray, handlePhysCam); |
| |
| status_t ret = d->constructCaptureResult(result.v3_2, &shadowResult); |
| if (ret != OK) { |
| return; |
| } |
| |
| if (handlePhysCam) { |
| if (shadowResult.num_physcam_metadata > d->mPhysicalCameraIds.size()) { |
| ALOGE("%s: Fatal: Invalid num_physcam_metadata %u", __FUNCTION__, |
| shadowResult.num_physcam_metadata); |
| return; |
| } |
| result.physicalCameraMetadata.resize(shadowResult.num_physcam_metadata); |
| for (uint32_t i = 0; i < shadowResult.num_physcam_metadata; i++) { |
| std::string physicalId = shadowResult.physcam_ids[i]; |
| if (d->mPhysicalCameraIds.find(physicalId) == d->mPhysicalCameraIds.end()) { |
| ALOGE("%s: Fatal: Invalid physcam_ids[%u]: %s", __FUNCTION__, |
| i, shadowResult.physcam_ids[i]); |
| return; |
| } |
| V3_2::CameraMetadata physicalMetadata; |
| V3_2::implementation::convertToHidl( |
| shadowResult.physcam_metadata[i], &physicalMetadata); |
| PhysicalCameraMetadata physicalCameraMetadata = { |
| .fmqMetadataSize = 0, |
| .physicalCameraId = physicalId, |
| .metadata = physicalMetadata }; |
| result.physicalCameraMetadata[i] = physicalCameraMetadata; |
| } |
| } |
| d->mResultBatcher_3_4.processCaptureResult_3_4(result); |
| } |
| |
| void CameraDeviceSession::sNotify_3_4( |
| const camera3_callback_ops *cb, |
| const camera3_notify_msg *msg) { |
| CameraDeviceSession *d = |
| const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); |
| V3_2::NotifyMsg hidlMsg; |
| V3_2::implementation::convertToHidl(msg, &hidlMsg); |
| |
| if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR && |
| hidlMsg.msg.error.errorStreamId != -1) { |
| if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) { |
| ALOGE("%s: unknown stream ID %d reports an error!", |
| __FUNCTION__, hidlMsg.msg.error.errorStreamId); |
| return; |
| } |
| } |
| |
| if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) { |
| switch (hidlMsg.msg.error.errorCode) { |
| case V3_2::ErrorCode::ERROR_DEVICE: |
| case V3_2::ErrorCode::ERROR_REQUEST: |
| case V3_2::ErrorCode::ERROR_RESULT: { |
| Mutex::Autolock _l(d->mInflightLock); |
| auto entry = d->mInflightAETriggerOverrides.find( |
| hidlMsg.msg.error.frameNumber); |
| if (d->mInflightAETriggerOverrides.end() != entry) { |
| d->mInflightAETriggerOverrides.erase( |
| hidlMsg.msg.error.frameNumber); |
| } |
| |
| auto boostEntry = d->mInflightRawBoostPresent.find( |
| hidlMsg.msg.error.frameNumber); |
| if (d->mInflightRawBoostPresent.end() != boostEntry) { |
| d->mInflightRawBoostPresent.erase( |
| hidlMsg.msg.error.frameNumber); |
| } |
| |
| } |
| break; |
| case V3_2::ErrorCode::ERROR_BUFFER: |
| default: |
| break; |
| } |
| |
| } |
| |
| d->mResultBatcher_3_4.notify(hidlMsg); |
| } |
| |
| CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4( |
| const sp<V3_2::ICameraDeviceCallback>& callback) : |
| V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) { |
| auto castResult = ICameraDeviceCallback::castFrom(callback); |
| if (castResult.isOk()) { |
| mCallback_3_4 = castResult; |
| } |
| } |
| |
| void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) { |
| auto pair = getBatch(result.v3_2.frameNumber); |
| int batchIdx = pair.first; |
| if (batchIdx == NOT_BATCHED) { |
| processOneCaptureResult_3_4(result); |
| return; |
| } |
| std::shared_ptr<InflightBatch> batch = pair.second; |
| { |
| Mutex::Autolock _l(batch->mLock); |
| // Check if the batch is removed (mostly by notify error) before lock was acquired |
| if (batch->mRemoved) { |
| // Fall back to non-batch path |
| processOneCaptureResult_3_4(result); |
| return; |
| } |
| |
| // queue metadata |
| if (result.v3_2.result.size() != 0) { |
| // Save a copy of metadata |
| batch->mResultMds[result.v3_2.partialResult].mMds.push_back( |
| std::make_pair(result.v3_2.frameNumber, result.v3_2.result)); |
| } |
| |
| // queue buffer |
| std::vector<int> filledStreams; |
| std::vector<V3_2::StreamBuffer> nonBatchedBuffers; |
| for (auto& buffer : result.v3_2.outputBuffers) { |
| auto it = batch->mBatchBufs.find(buffer.streamId); |
| if (it != batch->mBatchBufs.end()) { |
| InflightBatch::BufferBatch& bb = it->second; |
| auto id = buffer.streamId; |
| pushStreamBuffer(std::move(buffer), bb.mBuffers); |
| filledStreams.push_back(id); |
| } else { |
| pushStreamBuffer(std::move(buffer), nonBatchedBuffers); |
| } |
| } |
| |
| // send non-batched buffers up |
| if (nonBatchedBuffers.size() > 0 || result.v3_2.inputBuffer.streamId != -1) { |
| CaptureResult nonBatchedResult; |
| nonBatchedResult.v3_2.frameNumber = result.v3_2.frameNumber; |
| nonBatchedResult.v3_2.fmqResultSize = 0; |
| nonBatchedResult.v3_2.outputBuffers.resize(nonBatchedBuffers.size()); |
| for (size_t i = 0; i < nonBatchedBuffers.size(); i++) { |
| moveStreamBuffer( |
| std::move(nonBatchedBuffers[i]), nonBatchedResult.v3_2.outputBuffers[i]); |
| } |
| moveStreamBuffer(std::move(result.v3_2.inputBuffer), nonBatchedResult.v3_2.inputBuffer); |
| nonBatchedResult.v3_2.partialResult = 0; // 0 for buffer only results |
| processOneCaptureResult_3_4(nonBatchedResult); |
| } |
| |
| if (result.v3_2.frameNumber == batch->mLastFrame) { |
| // Send data up |
| if (result.v3_2.partialResult > 0) { |
| sendBatchMetadataLocked(batch, result.v3_2.partialResult); |
| } |
| // send buffer up |
| if (filledStreams.size() > 0) { |
| sendBatchBuffersLocked(batch, filledStreams); |
| } |
| } |
| } // end of batch lock scope |
| |
| // see if the batch is complete |
| if (result.v3_2.frameNumber == batch->mLastFrame) { |
| checkAndRemoveFirstBatch(); |
| } |
| } |
| |
| void CameraDeviceSession::ResultBatcher_3_4::processOneCaptureResult_3_4(CaptureResult& result) { |
| hidl_vec<CaptureResult> results; |
| results.resize(1); |
| results[0] = std::move(result); |
| invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true); |
| freeReleaseFences_3_4(results); |
| return; |
| } |
| |
| void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4( |
| hidl_vec<CaptureResult> &results, bool tryWriteFmq) { |
| if (mProcessCaptureResultLock.tryLock() != OK) { |
| ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); |
| if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) { |
| ALOGE("%s: cannot acquire lock in 1s, cannot proceed", |
| __FUNCTION__); |
| return; |
| } |
| } |
| if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { |
| for (CaptureResult &result : results) { |
| if (result.v3_2.result.size() > 0) { |
| if (mResultMetadataQueue->write(result.v3_2.result.data(), |
| result.v3_2.result.size())) { |
| result.v3_2.fmqResultSize = result.v3_2.result.size(); |
| result.v3_2.result.resize(0); |
| } else { |
| ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); |
| result.v3_2.fmqResultSize = 0; |
| } |
| } |
| |
| for (auto& onePhysMetadata : result.physicalCameraMetadata) { |
| if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(), |
| onePhysMetadata.metadata.size())) { |
| onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size(); |
| onePhysMetadata.metadata.resize(0); |
| } else { |
| ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); |
| onePhysMetadata.fmqMetadataSize = 0; |
| } |
| } |
| } |
| } |
| mCallback_3_4->processCaptureResult_3_4(results); |
| mProcessCaptureResultLock.unlock(); |
| } |
| |
| void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) { |
| for (auto& result : results) { |
| if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) { |
| native_handle_t* handle = const_cast<native_handle_t*>( |
| result.v3_2.inputBuffer.releaseFence.getNativeHandle()); |
| native_handle_close(handle); |
| native_handle_delete(handle); |
| } |
| for (auto& buf : result.v3_2.outputBuffers) { |
| if (buf.releaseFence.getNativeHandle() != nullptr) { |
| native_handle_t* handle = const_cast<native_handle_t*>( |
| buf.releaseFence.getNativeHandle()); |
| native_handle_close(handle); |
| native_handle_delete(handle); |
| } |
| } |
| } |
| return; |
| } |
| |
| } // namespace implementation |
| } // namespace V3_4 |
| } // namespace device |
| } // namespace camera |
| } // namespace hardware |
| } // namespace android |