| /* |
| * Copyright (C) 2022 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 "HidlCamera3-Device" |
| #define ATRACE_TAG ATRACE_TAG_CAMERA |
| //#define LOG_NDEBUG 0 |
| //#define LOG_NNDEBUG 0 // Per-frame verbose logging |
| |
| #ifdef LOG_NNDEBUG |
| #define ALOGVV(...) ALOGV(__VA_ARGS__) |
| #else |
| #define ALOGVV(...) ((void)0) |
| #endif |
| |
| // Convenience macro for transient errors |
| #define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.c_str(), __FUNCTION__, \ |
| ##__VA_ARGS__) |
| |
| // Convenience macros for transitioning to the error state |
| #define SET_ERR(fmt, ...) setErrorState( \ |
| "%s: " fmt, __FUNCTION__, \ |
| ##__VA_ARGS__) |
| #define SET_ERR_L(fmt, ...) setErrorStateLocked( \ |
| "%s: " fmt, __FUNCTION__, \ |
| ##__VA_ARGS__) |
| |
| |
| #include <inttypes.h> |
| |
| #include <utility> |
| |
| #include <utils/Log.h> |
| #include <utils/Trace.h> |
| #include <utils/Timers.h> |
| #include <cutils/properties.h> |
| #include <camera/StringUtils.h> |
| |
| #include <android/hardware/camera/device/3.7/ICameraInjectionSession.h> |
| #include <android/hardware/camera2/ICameraDeviceUser.h> |
| |
| #include "device3/hidl/HidlCamera3OutputUtils.h" |
| #include "device3/hidl/HidlCamera3OfflineSession.h" |
| #include "utils/SessionConfigurationUtilsHidl.h" |
| #include "utils/TraceHFR.h" |
| |
| #include "../../common/hidl/HidlProviderInfo.h" |
| #include "HidlCamera3Device.h" |
| |
| #include <algorithm> |
| #include <tuple> |
| |
| using namespace android::camera3; |
| using namespace android::hardware::camera; |
| using namespace android::hardware::camera::device::V3_2; |
| using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode; |
| |
| namespace android { |
| |
| hardware::graphics::common::V1_0::PixelFormat HidlCamera3Device::mapToPixelFormat( |
| int frameworkFormat) { |
| return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat; |
| } |
| |
| DataspaceFlags HidlCamera3Device::mapToHidlDataspace( |
| android_dataspace dataSpace) { |
| return dataSpace; |
| } |
| |
| BufferUsageFlags HidlCamera3Device::mapToConsumerUsage( |
| uint64_t usage) { |
| return usage; |
| } |
| |
| StreamRotation HidlCamera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) { |
| switch (rotation) { |
| case CAMERA_STREAM_ROTATION_0: |
| return StreamRotation::ROTATION_0; |
| case CAMERA_STREAM_ROTATION_90: |
| return StreamRotation::ROTATION_90; |
| case CAMERA_STREAM_ROTATION_180: |
| return StreamRotation::ROTATION_180; |
| case CAMERA_STREAM_ROTATION_270: |
| return StreamRotation::ROTATION_270; |
| } |
| ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation); |
| return StreamRotation::ROTATION_0; |
| } |
| |
| status_t HidlCamera3Device::mapToStreamConfigurationMode( |
| camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) { |
| if (mode == nullptr) return BAD_VALUE; |
| if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) { |
| switch(operationMode) { |
| case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE: |
| *mode = StreamConfigurationMode::NORMAL_MODE; |
| break; |
| case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE: |
| *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE; |
| break; |
| default: |
| ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode); |
| return BAD_VALUE; |
| } |
| } else { |
| *mode = static_cast<StreamConfigurationMode>(operationMode); |
| } |
| return OK; |
| } |
| |
| int HidlCamera3Device::mapToFrameworkFormat( |
| hardware::graphics::common::V1_0::PixelFormat pixelFormat) { |
| return static_cast<uint32_t>(pixelFormat); |
| } |
| |
| android_dataspace HidlCamera3Device::mapToFrameworkDataspace( |
| DataspaceFlags dataSpace) { |
| return static_cast<android_dataspace>(dataSpace); |
| } |
| |
| uint64_t HidlCamera3Device::mapConsumerToFrameworkUsage( |
| BufferUsageFlags usage) { |
| return usage; |
| } |
| |
| uint64_t HidlCamera3Device::mapProducerToFrameworkUsage( |
| BufferUsageFlags usage) { |
| return usage; |
| } |
| |
| status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager, |
| const std::string& monitorTags) { |
| ATRACE_CALL(); |
| Mutex::Autolock il(mInterfaceLock); |
| Mutex::Autolock l(mLock); |
| |
| ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.c_str()); |
| if (mStatus != STATUS_UNINITIALIZED) { |
| CLOGE("Already initialized!"); |
| return INVALID_OPERATION; |
| } |
| if (manager == nullptr) return INVALID_OPERATION; |
| |
| sp<ICameraDeviceSession> session; |
| ATRACE_BEGIN("CameraHal::openSession"); |
| status_t res = manager->openHidlSession(mId, this, |
| /*out*/ &session); |
| ATRACE_END(); |
| if (res != OK) { |
| SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res); |
| return res; |
| } |
| |
| res = manager->getCameraCharacteristics(mId, mOverrideForPerfClass, &mDeviceInfo, |
| /*overrideToPortrait*/false); |
| if (res != OK) { |
| SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res); |
| session->close(); |
| return res; |
| } |
| mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId); |
| |
| std::vector<std::string> physicalCameraIds; |
| bool isLogical = manager->isLogicalCamera(mId, &physicalCameraIds); |
| if (isLogical) { |
| for (auto& physicalId : physicalCameraIds) { |
| // Do not override characteristics for physical cameras |
| res = manager->getCameraCharacteristics( |
| physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId], |
| /*overrideToPortrait*/false); |
| if (res != OK) { |
| SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)", |
| physicalId.c_str(), strerror(-res), res); |
| session->close(); |
| return res; |
| } |
| |
| bool usePrecorrectArray = |
| DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]); |
| if (usePrecorrectArray) { |
| res = mDistortionMappers[physicalId].setupStaticInfo( |
| mPhysicalDeviceInfoMap[physicalId]); |
| if (res != OK) { |
| SET_ERR_L("Unable to read camera %s's calibration fields for distortion " |
| "correction", physicalId.c_str()); |
| session->close(); |
| return res; |
| } |
| } |
| |
| mZoomRatioMappers[physicalId] = ZoomRatioMapper( |
| &mPhysicalDeviceInfoMap[physicalId], |
| mSupportNativeZoomRatio, usePrecorrectArray); |
| |
| if (SessionConfigurationUtils::supportsUltraHighResolutionCapture( |
| mPhysicalDeviceInfoMap[physicalId])) { |
| mUHRCropAndMeteringRegionMappers[physicalId] = |
| UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId], |
| usePrecorrectArray); |
| } |
| } |
| } |
| |
| std::shared_ptr<RequestMetadataQueue> queue; |
| auto requestQueueRet = session->getCaptureRequestMetadataQueue( |
| [&queue](const auto& descriptor) { |
| queue = std::make_shared<RequestMetadataQueue>(descriptor); |
| if (!queue->isValid() || queue->availableToWrite() <= 0) { |
| ALOGE("HAL returns empty request metadata fmq, not use it"); |
| queue = nullptr; |
| // don't use the queue onwards. |
| } |
| }); |
| if (!requestQueueRet.isOk()) { |
| ALOGE("Transaction error when getting request metadata fmq: %s, not use it", |
| requestQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| |
| std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue; |
| auto resultQueueRet = session->getCaptureResultMetadataQueue( |
| [&resQueue](const auto& descriptor) { |
| resQueue = std::make_unique<ResultMetadataQueue>(descriptor); |
| if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) { |
| ALOGE("HAL returns empty result metadata fmq, not use it"); |
| resQueue = nullptr; |
| // Don't use the resQueue onwards. |
| } |
| }); |
| if (!resultQueueRet.isOk()) { |
| ALOGE("Transaction error when getting result metadata queue from camera session: %s", |
| resultQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| IF_ALOGV() { |
| session->interfaceChain([]( |
| ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) { |
| ALOGV("Session interface chain:"); |
| for (const auto& iface : interfaceChain) { |
| ALOGV(" %s", iface.c_str()); |
| } |
| }); |
| } |
| |
| camera_metadata_entry bufMgrMode = |
| mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION); |
| if (bufMgrMode.count > 0) { |
| mUseHalBufManager = (bufMgrMode.data.u8[0] == |
| ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); |
| } |
| |
| camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); |
| for (size_t i = 0; i < capabilities.count; i++) { |
| uint8_t capability = capabilities.data.u8[i]; |
| if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) { |
| mSupportOfflineProcessing = true; |
| } |
| } |
| |
| mInterface = new HidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing); |
| |
| std::string providerType; |
| mVendorTagId = manager->getProviderTagIdLocked(mId); |
| mTagMonitor.initialize(mVendorTagId); |
| if (!monitorTags.empty()) { |
| mTagMonitor.parseTagsToMonitor(monitorTags); |
| } |
| |
| // Metadata tags needs fixup for monochrome camera device version less |
| // than 3.5. |
| hardware::hidl_version maxVersion{0,0}; |
| IPCTransport transport = IPCTransport::HIDL; |
| res = manager->getHighestSupportedVersion(mId, &maxVersion, &transport); |
| if (res != OK) { |
| ALOGE("%s: Error in getting camera device version id: %s (%d)", |
| __FUNCTION__, strerror(-res), res); |
| return res; |
| } |
| int deviceVersion = HARDWARE_DEVICE_API_VERSION( |
| maxVersion.get_major(), maxVersion.get_minor()); |
| |
| bool isMonochrome = false; |
| for (size_t i = 0; i < capabilities.count; i++) { |
| uint8_t capability = capabilities.data.u8[i]; |
| if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) { |
| isMonochrome = true; |
| } |
| } |
| mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5); |
| |
| return initializeCommonLocked(); |
| } |
| |
| hardware::Return<void> HidlCamera3Device::requestStreamBuffers( |
| const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs, |
| requestStreamBuffers_cb _hidl_cb) { |
| RequestBufferStates states { |
| mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, |
| *this, *mInterface, *this}; |
| camera3::requestStreamBuffers(states, bufReqs, _hidl_cb); |
| return hardware::Void(); |
| } |
| |
| hardware::Return<void> HidlCamera3Device::returnStreamBuffers( |
| const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) { |
| ReturnBufferStates states { |
| mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface}; |
| camera3::returnStreamBuffers(states, buffers); |
| return hardware::Void(); |
| } |
| |
| hardware::Return<void> HidlCamera3Device::processCaptureResult_3_4( |
| const hardware::hidl_vec< |
| hardware::camera::device::V3_4::CaptureResult>& results) { |
| // Ideally we should grab mLock, but that can lead to deadlock, and |
| // it's not super important to get up to date value of mStatus for this |
| // warning print, hence skipping the lock here |
| if (mStatus == STATUS_ERROR) { |
| // Per API contract, HAL should act as closed after device error |
| // But mStatus can be set to error by framework as well, so just log |
| // a warning here. |
| ALOGW("%s: received capture result in error state.", __FUNCTION__); |
| } |
| |
| sp<NotificationListener> listener; |
| { |
| std::lock_guard<std::mutex> l(mOutputLock); |
| listener = mListener.promote(); |
| } |
| |
| if (mProcessCaptureResultLock.tryLock() != OK) { |
| // This should never happen; it indicates a wrong client implementation |
| // that doesn't follow the contract. But, we can be tolerant here. |
| ALOGE("%s: callback overlapped! waiting 1s...", |
| __FUNCTION__); |
| if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) { |
| ALOGE("%s: cannot acquire lock in 1s, dropping results", |
| __FUNCTION__); |
| // really don't know what to do, so bail out. |
| return hardware::Void(); |
| } |
| } |
| HidlCaptureOutputStates states { |
| { |
| mId, |
| mInFlightLock, mLastCompletedRegularFrameNumber, |
| mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber, |
| mInFlightMap, mOutputLock, mResultQueue, mResultSignal, |
| mNextShutterFrameNumber, |
| mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber, |
| mNextResultFrameNumber, |
| mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber, |
| mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags, |
| mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap, |
| mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers, |
| mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this, |
| *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait, |
| mActivePhysicalId}, mResultMetadataQueue |
| }; |
| |
| //HidlCaptureOutputStates hidlStates { |
| //} |
| |
| for (const auto& result : results) { |
| processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata); |
| } |
| mProcessCaptureResultLock.unlock(); |
| return hardware::Void(); |
| } |
| |
| // Only one processCaptureResult should be called at a time, so |
| // the locks won't block. The locks are present here simply to enforce this. |
| hardware::Return<void> HidlCamera3Device::processCaptureResult( |
| const hardware::hidl_vec< |
| hardware::camera::device::V3_2::CaptureResult>& results) { |
| hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata; |
| |
| // Ideally we should grab mLock, but that can lead to deadlock, and |
| // it's not super important to get up to date value of mStatus for this |
| // warning print, hence skipping the lock here |
| if (mStatus == STATUS_ERROR) { |
| // Per API contract, HAL should act as closed after device error |
| // But mStatus can be set to error by framework as well, so just log |
| // a warning here. |
| ALOGW("%s: received capture result in error state.", __FUNCTION__); |
| } |
| |
| sp<NotificationListener> listener; |
| { |
| std::lock_guard<std::mutex> l(mOutputLock); |
| listener = mListener.promote(); |
| } |
| |
| if (mProcessCaptureResultLock.tryLock() != OK) { |
| // This should never happen; it indicates a wrong client implementation |
| // that doesn't follow the contract. But, we can be tolerant here. |
| ALOGE("%s: callback overlapped! waiting 1s...", |
| __FUNCTION__); |
| if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) { |
| ALOGE("%s: cannot acquire lock in 1s, dropping results", |
| __FUNCTION__); |
| // really don't know what to do, so bail out. |
| return hardware::Void(); |
| } |
| } |
| |
| HidlCaptureOutputStates states { |
| { mId, |
| mInFlightLock, mLastCompletedRegularFrameNumber, |
| mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber, |
| mInFlightMap, mOutputLock, mResultQueue, mResultSignal, |
| mNextShutterFrameNumber, |
| mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber, |
| mNextResultFrameNumber, |
| mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber, |
| mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags, |
| mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap, |
| mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers, |
| mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this, |
| *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait, |
| mActivePhysicalId}, mResultMetadataQueue |
| }; |
| |
| for (const auto& result : results) { |
| processOneCaptureResultLocked(states, result, noPhysMetadata); |
| } |
| mProcessCaptureResultLock.unlock(); |
| return hardware::Void(); |
| } |
| |
| hardware::Return<void> HidlCamera3Device::notify( |
| const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) { |
| return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs); |
| } |
| |
| template<typename NotifyMsgType> |
| hardware::Return<void> HidlCamera3Device::notifyHelper( |
| const hardware::hidl_vec<NotifyMsgType>& msgs) { |
| // Ideally we should grab mLock, but that can lead to deadlock, and |
| // it's not super important to get up to date value of mStatus for this |
| // warning print, hence skipping the lock here |
| if (mStatus == STATUS_ERROR) { |
| // Per API contract, HAL should act as closed after device error |
| // But mStatus can be set to error by framework as well, so just log |
| // a warning here. |
| ALOGW("%s: received notify message in error state.", __FUNCTION__); |
| } |
| |
| sp<NotificationListener> listener; |
| { |
| std::lock_guard<std::mutex> l(mOutputLock); |
| listener = mListener.promote(); |
| } |
| |
| HidlCaptureOutputStates states { |
| { mId, |
| mInFlightLock, mLastCompletedRegularFrameNumber, |
| mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber, |
| mInFlightMap, mOutputLock, mResultQueue, mResultSignal, |
| mNextShutterFrameNumber, |
| mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber, |
| mNextResultFrameNumber, |
| mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber, |
| mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags, |
| mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap, |
| mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers, |
| mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this, |
| *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait, |
| mActivePhysicalId}, mResultMetadataQueue |
| }; |
| for (const auto& msg : msgs) { |
| camera3::notify(states, msg); |
| } |
| return hardware::Void(); |
| } |
| |
| status_t HidlCamera3Device::switchToOffline( |
| const std::vector<int32_t>& streamsToKeep, |
| /*out*/ sp<CameraOfflineSessionBase>* session) { |
| ATRACE_CALL(); |
| if (session == nullptr) { |
| ALOGE("%s: session must not be null", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| Mutex::Autolock il(mInterfaceLock); |
| |
| bool hasInputStream = mInputStream != nullptr; |
| int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1; |
| bool inputStreamSupportsOffline = hasInputStream ? |
| mInputStream->getOfflineProcessingSupport() : false; |
| auto outputStreamIds = mOutputStreams.getStreamIds(); |
| auto streamIds = outputStreamIds; |
| if (hasInputStream) { |
| streamIds.push_back(mInputStream->getId()); |
| } |
| |
| // Check all streams in streamsToKeep supports offline mode |
| for (auto id : streamsToKeep) { |
| if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) { |
| ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id); |
| return BAD_VALUE; |
| } else if (id == inputStreamId) { |
| if (!inputStreamSupportsOffline) { |
| ALOGE("%s: input stream %d cannot be switched to offline", |
| __FUNCTION__, id); |
| return BAD_VALUE; |
| } |
| } else { |
| sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id); |
| if (!stream->getOfflineProcessingSupport()) { |
| ALOGE("%s: output stream %d cannot be switched to offline", |
| __FUNCTION__, id); |
| return BAD_VALUE; |
| } |
| } |
| } |
| // TODO: block surface sharing and surface group streams until we can support them |
| |
| // Stop repeating request, wait until all remaining requests are submitted, then call into |
| // HAL switchToOffline |
| hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo; |
| sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession; |
| camera3::BufferRecords bufferRecords; |
| status_t ret = static_cast<HidlRequestThread *>(mRequestThread.get())->switchToOffline( |
| streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords); |
| |
| if (ret != OK) { |
| SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret); |
| return ret; |
| } |
| |
| bool succ = mRequestBufferSM.onSwitchToOfflineSuccess(); |
| if (!succ) { |
| SET_ERR("HAL must not be calling requestStreamBuffers call"); |
| // TODO: block ALL callbacks from HAL till app configured new streams? |
| return UNKNOWN_ERROR; |
| } |
| |
| // Verify offlineSessionInfo |
| std::vector<int32_t> offlineStreamIds; |
| offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size()); |
| for (auto offlineStream : offlineSessionInfo.offlineStreams) { |
| // verify stream IDs |
| int32_t id = offlineStream.id; |
| if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) { |
| SET_ERR("stream ID %d not found!", id); |
| return UNKNOWN_ERROR; |
| } |
| |
| // When not using HAL buf manager, only allow streams requested by app to be preserved |
| if (!mUseHalBufManager) { |
| if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) { |
| SET_ERR("stream ID %d must not be switched to offline!", id); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| offlineStreamIds.push_back(id); |
| sp<Camera3StreamInterface> stream = (id == inputStreamId) ? |
| static_cast<sp<Camera3StreamInterface>>(mInputStream) : |
| static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id)); |
| // Verify number of outstanding buffers |
| if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) { |
| SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)", |
| id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| // Verify all streams to be deleted don't have any outstanding buffers |
| if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(), |
| inputStreamId) == offlineStreamIds.end()) { |
| if (mInputStream->hasOutstandingBuffers()) { |
| SET_ERR("Input stream %d still has %zu outstanding buffer!", |
| inputStreamId, mInputStream->getOutstandingBuffersCount()); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| for (const auto& outStreamId : outputStreamIds) { |
| if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(), |
| outStreamId) == offlineStreamIds.end()) { |
| auto outStream = mOutputStreams.get(outStreamId); |
| if (outStream->hasOutstandingBuffers()) { |
| SET_ERR("Output stream %d still has %zu outstanding buffer!", |
| outStreamId, outStream->getOutstandingBuffersCount()); |
| return UNKNOWN_ERROR; |
| } |
| } |
| } |
| |
| InFlightRequestMap offlineReqs; |
| // Verify inflight requests and their pending buffers |
| { |
| std::lock_guard<std::mutex> l(mInFlightLock); |
| for (auto offlineReq : offlineSessionInfo.offlineRequests) { |
| int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber); |
| if (idx == NAME_NOT_FOUND) { |
| SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber); |
| return UNKNOWN_ERROR; |
| } |
| |
| const auto& inflightReq = mInFlightMap.valueAt(idx); |
| // TODO: check specific stream IDs |
| size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft); |
| if (numBuffersLeft != offlineReq.pendingStreams.size()) { |
| SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)", |
| inflightReq.numBuffersLeft, offlineReq.pendingStreams.size()); |
| return UNKNOWN_ERROR; |
| } |
| offlineReqs.add(offlineReq.frameNumber, inflightReq); |
| } |
| } |
| |
| // Create Camera3OfflineSession and transfer object ownership |
| // (streams, inflight requests, buffer caches) |
| camera3::StreamSet offlineStreamSet; |
| sp<camera3::Camera3Stream> inputStream; |
| for (auto offlineStream : offlineSessionInfo.offlineStreams) { |
| int32_t id = offlineStream.id; |
| if (mInputStream != nullptr && id == mInputStream->getId()) { |
| inputStream = mInputStream; |
| } else { |
| offlineStreamSet.add(id, mOutputStreams.get(id)); |
| } |
| } |
| |
| // TODO: check if we need to lock before copying states |
| // though technically no other thread should be talking to Camera3Device at this point |
| Camera3OfflineStates offlineStates( |
| mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags, |
| mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber, |
| mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber, |
| mNextResultFrameNumber, mNextReprocessResultFrameNumber, |
| mNextZslStillResultFrameNumber, mNextShutterFrameNumber, |
| mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber, |
| mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers, |
| mZoomRatioMappers, mRotateAndCropMappers); |
| |
| *session = new HidlCamera3OfflineSession(mId, inputStream, offlineStreamSet, |
| std::move(bufferRecords), offlineReqs, offlineStates, offlineSession); |
| |
| // Delete all streams that has been transferred to offline session |
| Mutex::Autolock l(mLock); |
| for (auto offlineStream : offlineSessionInfo.offlineStreams) { |
| int32_t id = offlineStream.id; |
| if (mInputStream != nullptr && id == mInputStream->getId()) { |
| mInputStream.clear(); |
| } else { |
| mOutputStreams.remove(id); |
| } |
| } |
| |
| // disconnect all other streams and switch to UNCONFIGURED state |
| if (mInputStream != nullptr) { |
| ret = mInputStream->disconnect(); |
| if (ret != OK) { |
| SET_ERR_L("disconnect input stream failed!"); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| for (auto streamId : mOutputStreams.getStreamIds()) { |
| sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId); |
| ret = stream->disconnect(); |
| if (ret != OK) { |
| SET_ERR_L("disconnect output stream %d failed!", streamId); |
| return UNKNOWN_ERROR; |
| } |
| } |
| |
| mInputStream.clear(); |
| mOutputStreams.clear(); |
| mNeedConfig = true; |
| internalUpdateStatusLocked(STATUS_UNCONFIGURED); |
| mOperatingMode = NO_MODE; |
| mIsConstrainedHighSpeedConfiguration = false; |
| mRequestThread->clearPreviousRequest(); |
| |
| return OK; |
| // TO be done by CameraDeviceClient/Camera3OfflineSession |
| // register the offline client to camera service |
| // Setup result passthing threads etc |
| // Initialize offline session so HAL can start sending callback to it (result Fmq) |
| // TODO: check how many onIdle callback will be sent |
| // Java side to make sure the CameraCaptureSession is properly closed |
| } |
| |
| void HidlCamera3Device::applyMaxBatchSizeLocked( |
| RequestList* requestList, const sp<camera3::Camera3OutputStreamInterface>& stream) { |
| int batchSize = requestList->size(); |
| |
| (*requestList->begin())->mBatchSize = batchSize; |
| stream->setBatchSize(batchSize); |
| } |
| |
| sp<Camera3Device::RequestThread> HidlCamera3Device::createNewRequestThread( |
| wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker, |
| sp<Camera3Device::HalInterface> interface, |
| const Vector<int32_t>& sessionParamKeys, |
| bool useHalBufManager, |
| bool supportCameraMute, |
| bool overrideToPortrait, |
| bool supportSettingsOverride) { |
| return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys, |
| useHalBufManager, supportCameraMute, overrideToPortrait, supportSettingsOverride); |
| }; |
| |
| sp<Camera3Device::Camera3DeviceInjectionMethods> |
| HidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) { |
| return new HidlCamera3DeviceInjectionMethods(parent); |
| } |
| |
| status_t HidlCamera3Device::injectionCameraInitialize(const std::string &injectedCamId, |
| sp<CameraProviderManager> manager) { |
| return (static_cast<HidlCamera3DeviceInjectionMethods *>( |
| mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager, this); |
| }; |
| |
| |
| HidlCamera3Device::HidlHalInterface::HidlHalInterface( |
| sp<device::V3_2::ICameraDeviceSession> &session, |
| std::shared_ptr<RequestMetadataQueue> queue, |
| bool useHalBufManager, bool supportOfflineProcessing) : |
| HalInterface(useHalBufManager, supportOfflineProcessing), |
| mHidlSession(session), |
| mRequestMetadataQueue(queue) { |
| // Check with hardware service manager if we can downcast these interfaces |
| // Somewhat expensive, so cache the results at startup |
| auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_7.isOk()) { |
| mHidlSession_3_7 = castResult_3_7; |
| } |
| auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_6.isOk()) { |
| mHidlSession_3_6 = castResult_3_6; |
| } |
| auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_5.isOk()) { |
| mHidlSession_3_5 = castResult_3_5; |
| } |
| auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_4.isOk()) { |
| mHidlSession_3_4 = castResult_3_4; |
| } |
| auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_3.isOk()) { |
| mHidlSession_3_3 = castResult_3_3; |
| } |
| } |
| |
| bool HidlCamera3Device::HidlHalInterface::valid() { |
| return (mHidlSession != nullptr); |
| } |
| |
| void HidlCamera3Device::HidlHalInterface::clear() { |
| mHidlSession_3_7.clear(); |
| mHidlSession_3_6.clear(); |
| mHidlSession_3_5.clear(); |
| mHidlSession_3_4.clear(); |
| mHidlSession_3_3.clear(); |
| mHidlSession.clear(); |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::constructDefaultRequestSettings( |
| camera_request_template_t templateId, |
| /*out*/ camera_metadata_t **requestTemplate) { |
| ATRACE_NAME("CameraHidlHal::constructDefaultRequestSettings"); |
| if (!valid()) return INVALID_OPERATION; |
| status_t res = OK; |
| |
| common::V1_0::Status status; |
| |
| auto requestCallback = [&status, &requestTemplate] |
| (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) { |
| status = s; |
| if (status == common::V1_0::Status::OK) { |
| const camera_metadata *r = |
| reinterpret_cast<const camera_metadata_t*>(request.data()); |
| size_t expectedSize = request.size(); |
| int ret = validate_camera_metadata_structure(r, &expectedSize); |
| if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) { |
| *requestTemplate = clone_camera_metadata(r); |
| if (*requestTemplate == nullptr) { |
| ALOGE("%s: Unable to clone camera metadata received from HAL", |
| __FUNCTION__); |
| status = common::V1_0::Status::INTERNAL_ERROR; |
| } |
| } else { |
| ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__); |
| status = common::V1_0::Status::INTERNAL_ERROR; |
| } |
| } |
| }; |
| hardware::Return<void> err; |
| RequestTemplate id; |
| switch (templateId) { |
| case CAMERA_TEMPLATE_PREVIEW: |
| id = RequestTemplate::PREVIEW; |
| break; |
| case CAMERA_TEMPLATE_STILL_CAPTURE: |
| id = RequestTemplate::STILL_CAPTURE; |
| break; |
| case CAMERA_TEMPLATE_VIDEO_RECORD: |
| id = RequestTemplate::VIDEO_RECORD; |
| break; |
| case CAMERA_TEMPLATE_VIDEO_SNAPSHOT: |
| id = RequestTemplate::VIDEO_SNAPSHOT; |
| break; |
| case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG: |
| id = RequestTemplate::ZERO_SHUTTER_LAG; |
| break; |
| case CAMERA_TEMPLATE_MANUAL: |
| id = RequestTemplate::MANUAL; |
| break; |
| default: |
| // Unknown template ID, or this HAL is too old to support it |
| return BAD_VALUE; |
| } |
| err = mHidlSession->constructDefaultRequestSettings(id, requestCallback); |
| |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| res = DEAD_OBJECT; |
| } else { |
| res = HidlProviderInfo::mapToStatusT(status); |
| } |
| |
| return res; |
| } |
| |
| bool HidlCamera3Device::HidlHalInterface::isReconfigurationRequired( |
| CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) { |
| // We do reconfiguration by default; |
| bool ret = true; |
| if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) { |
| android::hardware::hidl_vec<uint8_t> oldParams, newParams; |
| camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>( |
| oldSessionParams.getAndLock()); |
| camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>( |
| newSessionParams.getAndLock()); |
| oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta), |
| get_camera_metadata_size(oldSessioMeta)); |
| newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta), |
| get_camera_metadata_size(newSessioMeta)); |
| hardware::camera::common::V1_0::Status callStatus; |
| bool required; |
| auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s, |
| bool requiredFlag) { |
| callStatus = s; |
| required = requiredFlag; |
| }; |
| auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb); |
| oldSessionParams.unlock(oldSessioMeta); |
| newSessionParams.unlock(newSessioMeta); |
| if (err.isOk()) { |
| switch (callStatus) { |
| case hardware::camera::common::V1_0::Status::OK: |
| ret = required; |
| break; |
| case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED: |
| mIsReconfigurationQuerySupported = false; |
| ret = true; |
| break; |
| default: |
| ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus); |
| ret = true; |
| } |
| } else { |
| ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str()); |
| ret = true; |
| } |
| } |
| |
| return ret; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::configureStreams( |
| const camera_metadata_t *sessionParams, |
| camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes, |
| int64_t /*logId*/) { |
| ATRACE_NAME("CameraHal::configureStreams"); |
| if (!valid()) return INVALID_OPERATION; |
| status_t res = OK; |
| |
| if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) { |
| ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| // Convert stream config to HIDL |
| std::set<int> activeStreams; |
| device::V3_2::StreamConfiguration requestedConfiguration3_2; |
| device::V3_4::StreamConfiguration requestedConfiguration3_4; |
| device::V3_7::StreamConfiguration requestedConfiguration3_7; |
| requestedConfiguration3_2.streams.resize(config->num_streams); |
| requestedConfiguration3_4.streams.resize(config->num_streams); |
| requestedConfiguration3_7.streams.resize(config->num_streams); |
| for (size_t i = 0; i < config->num_streams; i++) { |
| device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i]; |
| device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i]; |
| device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i]; |
| camera3::camera_stream_t *src = config->streams[i]; |
| |
| Camera3Stream* cam3stream = Camera3Stream::cast(src); |
| cam3stream->setBufferFreedListener(this); |
| int streamId = cam3stream->getId(); |
| StreamType streamType; |
| switch (src->stream_type) { |
| case CAMERA_STREAM_OUTPUT: |
| streamType = StreamType::OUTPUT; |
| break; |
| case CAMERA_STREAM_INPUT: |
| streamType = StreamType::INPUT; |
| break; |
| default: |
| ALOGE("%s: Stream %d: Unsupported stream type %d", |
| __FUNCTION__, streamId, config->streams[i]->stream_type); |
| return BAD_VALUE; |
| } |
| dst3_2.id = streamId; |
| dst3_2.streamType = streamType; |
| dst3_2.width = src->width; |
| dst3_2.height = src->height; |
| dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage()); |
| dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation); |
| // For HidlSession version 3.5 or newer, the format and dataSpace sent |
| // to HAL are original, not the overridden ones. |
| if (mHidlSession_3_5 != nullptr) { |
| dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ? |
| cam3stream->getOriginalFormat() : src->format); |
| dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ? |
| cam3stream->getOriginalDataSpace() : src->data_space); |
| } else { |
| dst3_2.format = mapToPixelFormat(src->format); |
| dst3_2.dataSpace = mapToHidlDataspace(src->data_space); |
| } |
| dst3_4.v3_2 = dst3_2; |
| dst3_4.bufferSize = bufferSizes[i]; |
| if (!src->physical_camera_id.empty()) { |
| dst3_4.physicalCameraId = src->physical_camera_id; |
| } |
| dst3_7.v3_4 = dst3_4; |
| dst3_7.groupId = cam3stream->getHalStreamGroupId(); |
| dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size()); |
| size_t j = 0; |
| for (int mode : src->sensor_pixel_modes_used) { |
| dst3_7.sensorPixelModesUsed[j++] = |
| static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode); |
| } |
| if (src->dynamic_range_profile != |
| ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) { |
| ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %" PRIx64, |
| __FUNCTION__, src->dynamic_range_profile); |
| return BAD_VALUE; |
| } |
| if (src->use_case != ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) { |
| ALOGE("%s: Camera device doesn't support non-default stream use case %" PRId64 "!", |
| __FUNCTION__, src->use_case); |
| return BAD_VALUE; |
| } |
| activeStreams.insert(streamId); |
| // Create Buffer ID map if necessary |
| mBufferRecords.tryCreateBufferCache(streamId); |
| } |
| // remove BufferIdMap for deleted streams |
| mBufferRecords.removeInactiveBufferCaches(activeStreams); |
| |
| StreamConfigurationMode operationMode; |
| res = mapToStreamConfigurationMode( |
| (camera_stream_configuration_mode_t) config->operation_mode, |
| /*out*/ &operationMode); |
| if (res != OK) { |
| return res; |
| } |
| requestedConfiguration3_2.operationMode = operationMode; |
| requestedConfiguration3_4.operationMode = operationMode; |
| requestedConfiguration3_7.operationMode = operationMode; |
| size_t sessionParamSize = get_camera_metadata_size(sessionParams); |
| requestedConfiguration3_4.sessionParams.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)), |
| sessionParamSize); |
| requestedConfiguration3_7.sessionParams.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)), |
| sessionParamSize); |
| |
| // Invoke configureStreams |
| device::V3_3::HalStreamConfiguration finalConfiguration; |
| device::V3_4::HalStreamConfiguration finalConfiguration3_4; |
| device::V3_6::HalStreamConfiguration finalConfiguration3_6; |
| common::V1_0::Status status; |
| |
| auto configStream34Cb = [&status, &finalConfiguration3_4] |
| (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) { |
| finalConfiguration3_4 = halConfiguration; |
| status = s; |
| }; |
| |
| auto configStream36Cb = [&status, &finalConfiguration3_6] |
| (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) { |
| finalConfiguration3_6 = halConfiguration; |
| status = s; |
| }; |
| |
| auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4] |
| (hardware::Return<void>& err) -> status_t { |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| finalConfiguration.streams.resize(finalConfiguration3_4.streams.size()); |
| for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) { |
| finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3; |
| } |
| return OK; |
| }; |
| |
| auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6] |
| (hardware::Return<void>& err) -> status_t { |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| finalConfiguration.streams.resize(finalConfiguration3_6.streams.size()); |
| for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) { |
| finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3; |
| } |
| return OK; |
| }; |
| |
| if (mHidlSession_3_7 != nullptr) { |
| ALOGV("%s: v3.7 device found", __FUNCTION__); |
| requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++; |
| requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution; |
| auto err = mHidlSession_3_7->configureStreams_3_7( |
| requestedConfiguration3_7, configStream36Cb); |
| res = postprocConfigStream36(err); |
| if (res != OK) { |
| return res; |
| } |
| } else if (mHidlSession_3_6 != nullptr) { |
| ALOGV("%s: v3.6 device found", __FUNCTION__); |
| device::V3_5::StreamConfiguration requestedConfiguration3_5; |
| requestedConfiguration3_5.v3_4 = requestedConfiguration3_4; |
| requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++; |
| auto err = mHidlSession_3_6->configureStreams_3_6( |
| requestedConfiguration3_5, configStream36Cb); |
| res = postprocConfigStream36(err); |
| if (res != OK) { |
| return res; |
| } |
| } else if (mHidlSession_3_5 != nullptr) { |
| ALOGV("%s: v3.5 device found", __FUNCTION__); |
| device::V3_5::StreamConfiguration requestedConfiguration3_5; |
| requestedConfiguration3_5.v3_4 = requestedConfiguration3_4; |
| requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++; |
| auto err = mHidlSession_3_5->configureStreams_3_5( |
| requestedConfiguration3_5, configStream34Cb); |
| res = postprocConfigStream34(err); |
| if (res != OK) { |
| return res; |
| } |
| } else if (mHidlSession_3_4 != nullptr) { |
| // We do; use v3.4 for the call |
| ALOGV("%s: v3.4 device found", __FUNCTION__); |
| auto err = mHidlSession_3_4->configureStreams_3_4( |
| requestedConfiguration3_4, configStream34Cb); |
| res = postprocConfigStream34(err); |
| if (res != OK) { |
| return res; |
| } |
| } else if (mHidlSession_3_3 != nullptr) { |
| // We do; use v3.3 for the call |
| ALOGV("%s: v3.3 device found", __FUNCTION__); |
| auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2, |
| [&status, &finalConfiguration] |
| (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) { |
| finalConfiguration = halConfiguration; |
| status = s; |
| }); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| } else { |
| // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration |
| ALOGV("%s: v3.2 device found", __FUNCTION__); |
| HalStreamConfiguration finalConfiguration_3_2; |
| auto err = mHidlSession->configureStreams(requestedConfiguration3_2, |
| [&status, &finalConfiguration_3_2] |
| (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) { |
| finalConfiguration_3_2 = halConfiguration; |
| status = s; |
| }); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size()); |
| for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) { |
| finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i]; |
| finalConfiguration.streams[i].overrideDataSpace = |
| requestedConfiguration3_2.streams[i].dataSpace; |
| } |
| } |
| |
| if (status != common::V1_0::Status::OK ) { |
| return HidlProviderInfo::mapToStatusT(status); |
| } |
| |
| // And convert output stream configuration from HIDL |
| |
| for (size_t i = 0; i < config->num_streams; i++) { |
| camera3::camera_stream_t *dst = config->streams[i]; |
| int streamId = Camera3Stream::cast(dst)->getId(); |
| |
| // Start scan at i, with the assumption that the stream order matches |
| size_t realIdx = i; |
| bool found = false; |
| size_t halStreamCount = finalConfiguration.streams.size(); |
| for (size_t idx = 0; idx < halStreamCount; idx++) { |
| if (finalConfiguration.streams[realIdx].v3_2.id == streamId) { |
| found = true; |
| break; |
| } |
| realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1; |
| } |
| if (!found) { |
| ALOGE("%s: Stream %d not found in stream configuration response from HAL", |
| __FUNCTION__, streamId); |
| return INVALID_OPERATION; |
| } |
| device::V3_3::HalStream &src = finalConfiguration.streams[realIdx]; |
| device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx]; |
| |
| Camera3Stream* dstStream = Camera3Stream::cast(dst); |
| int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat); |
| android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace); |
| |
| if (mHidlSession_3_6 != nullptr) { |
| dstStream->setOfflineProcessingSupport(src_36.supportOffline); |
| } |
| |
| if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { |
| dstStream->setFormatOverride(false); |
| dstStream->setDataSpaceOverride(false); |
| if (dst->format != overrideFormat) { |
| ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__, |
| streamId, dst->format); |
| } |
| if (dst->data_space != overrideDataSpace) { |
| ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__, |
| streamId, dst->format); |
| } |
| } else { |
| bool needFormatOverride = |
| requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat; |
| bool needDataspaceOverride = |
| requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace; |
| // Override allowed with IMPLEMENTATION_DEFINED |
| dstStream->setFormatOverride(needFormatOverride); |
| dstStream->setDataSpaceOverride(needDataspaceOverride); |
| dst->format = overrideFormat; |
| dst->data_space = overrideDataSpace; |
| } |
| |
| if (dst->stream_type == CAMERA_STREAM_INPUT) { |
| if (src.v3_2.producerUsage != 0) { |
| ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage", |
| __FUNCTION__, streamId); |
| return INVALID_OPERATION; |
| } |
| dstStream->setUsage( |
| mapConsumerToFrameworkUsage(src.v3_2.consumerUsage)); |
| } else { |
| // OUTPUT |
| if (src.v3_2.consumerUsage != 0) { |
| ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage", |
| __FUNCTION__, streamId); |
| return INVALID_OPERATION; |
| } |
| dstStream->setUsage( |
| mapProducerToFrameworkUsage(src.v3_2.producerUsage)); |
| } |
| dst->max_buffers = src.v3_2.maxBuffers; |
| } |
| |
| return res; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::configureInjectedStreams( |
| const camera_metadata_t* sessionParams, camera_stream_configuration* config, |
| const std::vector<uint32_t>& bufferSizes, |
| const CameraMetadata& cameraCharacteristics) { |
| ATRACE_NAME("InjectionCameraHal::configureStreams"); |
| if (!valid()) return INVALID_OPERATION; |
| status_t res = OK; |
| |
| if (config->input_is_multi_resolution) { |
| ALOGE("%s: Injection camera device doesn't support multi-resolution input " |
| "stream", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| // Convert stream config to HIDL |
| std::set<int> activeStreams; |
| device::V3_2::StreamConfiguration requestedConfiguration3_2; |
| device::V3_4::StreamConfiguration requestedConfiguration3_4; |
| device::V3_7::StreamConfiguration requestedConfiguration3_7; |
| requestedConfiguration3_2.streams.resize(config->num_streams); |
| requestedConfiguration3_4.streams.resize(config->num_streams); |
| requestedConfiguration3_7.streams.resize(config->num_streams); |
| for (size_t i = 0; i < config->num_streams; i++) { |
| device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i]; |
| device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i]; |
| device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i]; |
| camera3::camera_stream_t* src = config->streams[i]; |
| |
| Camera3Stream* cam3stream = Camera3Stream::cast(src); |
| cam3stream->setBufferFreedListener(this); |
| int streamId = cam3stream->getId(); |
| StreamType streamType; |
| switch (src->stream_type) { |
| case CAMERA_STREAM_OUTPUT: |
| streamType = StreamType::OUTPUT; |
| break; |
| case CAMERA_STREAM_INPUT: |
| streamType = StreamType::INPUT; |
| break; |
| default: |
| ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__, |
| streamId, config->streams[i]->stream_type); |
| return BAD_VALUE; |
| } |
| dst3_2.id = streamId; |
| dst3_2.streamType = streamType; |
| dst3_2.width = src->width; |
| dst3_2.height = src->height; |
| dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage()); |
| dst3_2.rotation = |
| mapToStreamRotation((camera_stream_rotation_t)src->rotation); |
| // For HidlSession version 3.5 or newer, the format and dataSpace sent |
| // to HAL are original, not the overridden ones. |
| if (mHidlSession_3_5 != nullptr) { |
| dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() |
| ? cam3stream->getOriginalFormat() |
| : src->format); |
| dst3_2.dataSpace = |
| mapToHidlDataspace(cam3stream->isDataSpaceOverridden() |
| ? cam3stream->getOriginalDataSpace() |
| : src->data_space); |
| } else { |
| dst3_2.format = mapToPixelFormat(src->format); |
| dst3_2.dataSpace = mapToHidlDataspace(src->data_space); |
| } |
| dst3_4.v3_2 = dst3_2; |
| dst3_4.bufferSize = bufferSizes[i]; |
| if (!src->physical_camera_id.empty()) { |
| dst3_4.physicalCameraId = src->physical_camera_id; |
| } |
| dst3_7.v3_4 = dst3_4; |
| dst3_7.groupId = cam3stream->getHalStreamGroupId(); |
| dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size()); |
| size_t j = 0; |
| for (int mode : src->sensor_pixel_modes_used) { |
| dst3_7.sensorPixelModesUsed[j++] = |
| static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode); |
| } |
| activeStreams.insert(streamId); |
| // Create Buffer ID map if necessary |
| mBufferRecords.tryCreateBufferCache(streamId); |
| } |
| // remove BufferIdMap for deleted streams |
| mBufferRecords.removeInactiveBufferCaches(activeStreams); |
| |
| StreamConfigurationMode operationMode; |
| res = mapToStreamConfigurationMode( |
| (camera_stream_configuration_mode_t)config->operation_mode, |
| /*out*/ &operationMode); |
| if (res != OK) { |
| return res; |
| } |
| requestedConfiguration3_7.operationMode = operationMode; |
| size_t sessionParamSize = get_camera_metadata_size(sessionParams); |
| requestedConfiguration3_7.operationMode = operationMode; |
| requestedConfiguration3_7.sessionParams.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)), |
| sessionParamSize); |
| |
| // See which version of HAL we have |
| if (mHidlSession_3_7 != nullptr) { |
| requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++; |
| requestedConfiguration3_7.multiResolutionInputImage = |
| config->input_is_multi_resolution; |
| |
| const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock(); |
| ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {}; |
| hidlChars.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)), |
| get_camera_metadata_size(rawMetadata)); |
| cameraCharacteristics.unlock(rawMetadata); |
| |
| sp<hardware::camera::device::V3_7::ICameraInjectionSession> |
| hidlInjectionSession_3_7; |
| auto castInjectionResult_3_7 = |
| device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7); |
| if (castInjectionResult_3_7.isOk()) { |
| hidlInjectionSession_3_7 = castInjectionResult_3_7; |
| } else { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, |
| castInjectionResult_3_7.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| |
| auto err = hidlInjectionSession_3_7->configureInjectionStreams( |
| requestedConfiguration3_7, hidlChars); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, |
| err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| } else { |
| ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection " |
| "session is 3.7", __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| return res; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::wrapAsHidlRequest(camera_capture_request_t* request, |
| /*out*/device::V3_2::CaptureRequest* captureRequest, |
| /*out*/std::vector<native_handle_t*>* handlesCreated, |
| /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) { |
| ATRACE_CALL(); |
| if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) { |
| ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) " |
| "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers); |
| return BAD_VALUE; |
| } |
| |
| captureRequest->frameNumber = request->frame_number; |
| |
| captureRequest->fmqSettingsSize = 0; |
| |
| { |
| if (request->input_buffer != nullptr) { |
| int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId(); |
| buffer_handle_t buf = *(request->input_buffer->buffer); |
| auto pair = getBufferId(buf, streamId); |
| bool isNewBuffer = pair.first; |
| uint64_t bufferId = pair.second; |
| captureRequest->inputBuffer.streamId = streamId; |
| captureRequest->inputBuffer.bufferId = bufferId; |
| captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr; |
| captureRequest->inputBuffer.status = BufferStatus::OK; |
| native_handle_t *acquireFence = nullptr; |
| if (request->input_buffer->acquire_fence != -1) { |
| acquireFence = native_handle_create(1,0); |
| acquireFence->data[0] = request->input_buffer->acquire_fence; |
| handlesCreated->push_back(acquireFence); |
| } |
| captureRequest->inputBuffer.acquireFence = acquireFence; |
| captureRequest->inputBuffer.releaseFence = nullptr; |
| |
| mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId, |
| request->input_buffer->buffer); |
| inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId)); |
| } else { |
| captureRequest->inputBuffer.streamId = -1; |
| captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER; |
| } |
| |
| captureRequest->outputBuffers.resize(request->num_output_buffers); |
| for (size_t i = 0; i < request->num_output_buffers; i++) { |
| const camera_stream_buffer_t *src = request->output_buffers + i; |
| StreamBuffer &dst = captureRequest->outputBuffers[i]; |
| int32_t streamId = Camera3Stream::cast(src->stream)->getId(); |
| if (src->buffer != nullptr) { |
| buffer_handle_t buf = *(src->buffer); |
| auto pair = getBufferId(buf, streamId); |
| bool isNewBuffer = pair.first; |
| dst.bufferId = pair.second; |
| dst.buffer = isNewBuffer ? buf : nullptr; |
| native_handle_t *acquireFence = nullptr; |
| if (src->acquire_fence != -1) { |
| acquireFence = native_handle_create(1,0); |
| acquireFence->data[0] = src->acquire_fence; |
| handlesCreated->push_back(acquireFence); |
| } |
| dst.acquireFence = acquireFence; |
| } else if (mUseHalBufManager) { |
| // HAL buffer management path |
| dst.bufferId = BUFFER_ID_NO_BUFFER; |
| dst.buffer = nullptr; |
| dst.acquireFence = nullptr; |
| } else { |
| ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| dst.streamId = streamId; |
| dst.status = BufferStatus::OK; |
| dst.releaseFence = nullptr; |
| |
| // Output buffers are empty when using HAL buffer manager |
| if (!mUseHalBufManager) { |
| mBufferRecords.pushInflightBuffer( |
| captureRequest->frameNumber, streamId, src->buffer); |
| inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId)); |
| } |
| } |
| } |
| return OK; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::flush() { |
| ATRACE_NAME("CameraHal::flush"); |
| if (!valid()) return INVALID_OPERATION; |
| status_t res = OK; |
| |
| auto err = mHidlSession->flush(); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| res = DEAD_OBJECT; |
| } else { |
| res = HidlProviderInfo::mapToStatusT(err); |
| } |
| |
| return res; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::dump(int /*fd*/) { |
| ATRACE_NAME("CameraHal::dump"); |
| if (!valid()) return INVALID_OPERATION; |
| |
| // Handled by CameraProviderManager::dump |
| |
| return OK; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::repeatingRequestEnd(uint32_t /*frameNumber*/, |
| const std::vector<int32_t> &/*streamIds*/) { |
| ATRACE_NAME("CameraHal::repeatingRequestEnd"); |
| return INVALID_OPERATION; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::close() { |
| ATRACE_NAME("CameraHal::close()"); |
| if (!valid()) return INVALID_OPERATION; |
| status_t res = OK; |
| |
| auto err = mHidlSession->close(); |
| // Interface will be dead shortly anyway, so don't log errors |
| if (!err.isOk()) { |
| res = DEAD_OBJECT; |
| } |
| |
| return res; |
| } |
| |
| void HidlCamera3Device::HidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) { |
| ATRACE_NAME("CameraHal::signalPipelineDrain"); |
| if (!valid() || mHidlSession_3_5 == nullptr) { |
| ALOGE("%s called on invalid camera!", __FUNCTION__); |
| return; |
| } |
| |
| auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1); |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return; |
| } |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::processBatchCaptureRequests( |
| std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) { |
| ATRACE_NAME("CameraHal::processBatchCaptureRequests"); |
| if (!valid()) return INVALID_OPERATION; |
| |
| sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4; |
| sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7; |
| auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_7.isOk()) { |
| hidlSession_3_7 = castResult_3_7; |
| } |
| auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession); |
| if (castResult_3_4.isOk()) { |
| hidlSession_3_4 = castResult_3_4; |
| } |
| |
| hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests; |
| hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4; |
| hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7; |
| size_t batchSize = requests.size(); |
| if (hidlSession_3_7 != nullptr) { |
| captureRequests_3_7.resize(batchSize); |
| } else if (hidlSession_3_4 != nullptr) { |
| captureRequests_3_4.resize(batchSize); |
| } else { |
| captureRequests.resize(batchSize); |
| } |
| std::vector<native_handle_t*> handlesCreated; |
| std::vector<std::pair<int32_t, int32_t>> inflightBuffers; |
| |
| status_t res = OK; |
| for (size_t i = 0; i < batchSize; i++) { |
| if (hidlSession_3_7 != nullptr) { |
| res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2, |
| /*out*/&handlesCreated, /*out*/&inflightBuffers); |
| } else if (hidlSession_3_4 != nullptr) { |
| res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2, |
| /*out*/&handlesCreated, /*out*/&inflightBuffers); |
| } else { |
| res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i], |
| /*out*/&handlesCreated, /*out*/&inflightBuffers); |
| } |
| if (res != OK) { |
| mBufferRecords.popInflightBuffers(inflightBuffers); |
| cleanupNativeHandles(&handlesCreated); |
| return res; |
| } |
| } |
| |
| std::vector<device::V3_2::BufferCache> cachesToRemove; |
| { |
| std::lock_guard<std::mutex> lock(mFreedBuffersLock); |
| for (auto& pair : mFreedBuffers) { |
| // The stream might have been removed since onBufferFreed |
| if (mBufferRecords.isStreamCached(pair.first)) { |
| cachesToRemove.push_back({pair.first, pair.second}); |
| } |
| } |
| mFreedBuffers.clear(); |
| } |
| |
| common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR; |
| *numRequestProcessed = 0; |
| |
| // Write metadata to FMQ. |
| for (size_t i = 0; i < batchSize; i++) { |
| camera_capture_request_t* request = requests[i]; |
| device::V3_2::CaptureRequest* captureRequest; |
| if (hidlSession_3_7 != nullptr) { |
| captureRequest = &captureRequests_3_7[i].v3_4.v3_2; |
| } else if (hidlSession_3_4 != nullptr) { |
| captureRequest = &captureRequests_3_4[i].v3_2; |
| } else { |
| captureRequest = &captureRequests[i]; |
| } |
| |
| if (request->settings != nullptr) { |
| size_t settingsSize = get_camera_metadata_size(request->settings); |
| if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write( |
| reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) { |
| captureRequest->settings.resize(0); |
| captureRequest->fmqSettingsSize = settingsSize; |
| } else { |
| if (mRequestMetadataQueue != nullptr) { |
| ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__); |
| } |
| captureRequest->settings.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>( |
| request->settings)), |
| get_camera_metadata_size(request->settings)); |
| captureRequest->fmqSettingsSize = 0u; |
| } |
| } else { |
| // A null request settings maps to a size-0 CameraMetadata |
| captureRequest->settings.resize(0); |
| captureRequest->fmqSettingsSize = 0u; |
| } |
| |
| // hidl session 3.7 specific handling. |
| if (hidlSession_3_7 != nullptr) { |
| captureRequests_3_7[i].inputWidth = request->input_width; |
| captureRequests_3_7[i].inputHeight = request->input_height; |
| } |
| |
| // hidl session 3.7 and 3.4 specific handling. |
| if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) { |
| hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings = |
| (hidlSession_3_7 != nullptr) ? |
| captureRequests_3_7[i].v3_4.physicalCameraSettings : |
| captureRequests_3_4[i].physicalCameraSettings; |
| physicalCameraSettings.resize(request->num_physcam_settings); |
| for (size_t j = 0; j < request->num_physcam_settings; j++) { |
| if (request->physcam_settings != nullptr) { |
| size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]); |
| if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write( |
| reinterpret_cast<const uint8_t*>(request->physcam_settings[j]), |
| settingsSize)) { |
| physicalCameraSettings[j].settings.resize(0); |
| physicalCameraSettings[j].fmqSettingsSize = settingsSize; |
| } else { |
| if (mRequestMetadataQueue != nullptr) { |
| ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__); |
| } |
| physicalCameraSettings[j].settings.setToExternal( |
| reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>( |
| request->physcam_settings[j])), |
| get_camera_metadata_size(request->physcam_settings[j])); |
| physicalCameraSettings[j].fmqSettingsSize = 0u; |
| } |
| } else { |
| physicalCameraSettings[j].fmqSettingsSize = 0u; |
| physicalCameraSettings[j].settings.resize(0); |
| } |
| physicalCameraSettings[j].physicalCameraId = request->physcam_id[j]; |
| } |
| } |
| } |
| |
| hardware::details::return_status err; |
| auto resultCallback = |
| [&status, &numRequestProcessed] (auto s, uint32_t n) { |
| status = s; |
| *numRequestProcessed = n; |
| }; |
| if (hidlSession_3_7 != nullptr) { |
| err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove, |
| resultCallback); |
| } else if (hidlSession_3_4 != nullptr) { |
| err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove, |
| resultCallback); |
| } else { |
| err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove, |
| resultCallback); |
| } |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| status = common::V1_0::Status::CAMERA_DISCONNECTED; |
| } |
| |
| if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) { |
| ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests", |
| __FUNCTION__, *numRequestProcessed, batchSize); |
| status = common::V1_0::Status::INTERNAL_ERROR; |
| } |
| |
| res = HidlProviderInfo::mapToStatusT(status); |
| if (res == OK) { |
| if (mHidlSession->isRemote()) { |
| // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been |
| // sent to camera HAL processes) |
| cleanupNativeHandles(&handlesCreated, /*closeFd*/true); |
| } else { |
| // In passthrough mode the FDs are now owned by HAL |
| cleanupNativeHandles(&handlesCreated); |
| } |
| } else { |
| mBufferRecords.popInflightBuffers(inflightBuffers); |
| cleanupNativeHandles(&handlesCreated); |
| } |
| return res; |
| } |
| |
| status_t HidlCamera3Device::HidlHalInterface::switchToOffline( |
| const std::vector<int32_t>& streamsToKeep, |
| /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo, |
| /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession, |
| /*out*/camera3::BufferRecords* bufferRecords) { |
| ATRACE_NAME("CameraHal::switchToOffline"); |
| if (!valid() || mHidlSession_3_6 == nullptr) { |
| ALOGE("%s called on invalid camera!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) { |
| ALOGE("%s: output arguments must not be null!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR; |
| auto resultCallback = |
| [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) { |
| status = s; |
| *offlineSessionInfo = info; |
| *offlineSession = session; |
| }; |
| auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback); |
| |
| if (!err.isOk()) { |
| ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| |
| status_t ret = HidlProviderInfo::mapToStatusT(status); |
| if (ret != OK) { |
| return ret; |
| } |
| |
| return verifyBufferCaches(offlineSessionInfo, bufferRecords); |
| } |
| |
| HidlCamera3Device::HidlRequestThread::HidlRequestThread(wp<Camera3Device> parent, |
| sp<camera3::StatusTracker> statusTracker, |
| sp<HalInterface> interface, |
| const Vector<int32_t>& sessionParamKeys, |
| bool useHalBufManager, |
| bool supportCameraMute, |
| bool overrideToPortrait, |
| bool supportSettingsOverride) : |
| RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager, |
| supportCameraMute, overrideToPortrait, supportSettingsOverride) {} |
| |
| status_t HidlCamera3Device::HidlRequestThread::switchToOffline( |
| const std::vector<int32_t>& streamsToKeep, |
| /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo, |
| /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession, |
| /*out*/camera3::BufferRecords* bufferRecords) { |
| Mutex::Autolock l(mRequestLock); |
| clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr); |
| |
| // Wait until request thread is fully stopped |
| // TBD: check if request thread is being paused by other APIs (shouldn't be) |
| |
| // We could also check for mRepeatingRequests.empty(), but the API interface |
| // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any |
| // new requests during the call; hence skip that check. |
| bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty(); |
| while (!queueEmpty) { |
| status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout); |
| if (res == TIMED_OUT) { |
| ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__); |
| return res; |
| } else if (res != OK) { |
| ALOGE("%s: request thread failed to submit a request: %s (%d)!", |
| __FUNCTION__, strerror(-res), res); |
| return res; |
| } |
| queueEmpty = mNextRequests.empty() && mRequestQueue.empty(); |
| } |
| return (static_cast<HidlHalInterface *>(mInterface.get()))->switchToOffline( |
| streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords); |
| } |
| |
| status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::injectionInitialize( |
| const std::string& injectedCamId, sp<CameraProviderManager> manager, |
| const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>& |
| callback) { |
| ATRACE_CALL(); |
| Mutex::Autolock lock(mInjectionLock); |
| |
| if (manager == nullptr) { |
| ALOGE("%s: manager does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| mInjectedCamId = injectedCamId; |
| sp<ICameraDeviceSession> session; |
| ATRACE_BEGIN("Injection CameraHal::openSession"); |
| status_t res = manager->openHidlSession(injectedCamId, callback, |
| /*out*/ &session); |
| ATRACE_END(); |
| if (res != OK) { |
| ALOGE("Injection camera could not open camera session: %s (%d)", |
| strerror(-res), res); |
| return res; |
| } |
| |
| std::shared_ptr<RequestMetadataQueue> queue; |
| auto requestQueueRet = |
| session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) { |
| queue = std::make_shared<RequestMetadataQueue>(descriptor); |
| if (!queue->isValid() || queue->availableToWrite() <= 0) { |
| ALOGE("Injection camera HAL returns empty request metadata fmq, not " |
| "use it"); |
| queue = nullptr; |
| // don't use the queue onwards. |
| } |
| }); |
| if (!requestQueueRet.isOk()) { |
| ALOGE("Injection camera transaction error when getting request metadata fmq: " |
| "%s, not use it", requestQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| |
| std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue; |
| auto resultQueueRet = session->getCaptureResultMetadataQueue( |
| [&resQueue](const auto& descriptor) { |
| resQueue = std::make_unique<ResultMetadataQueue>(descriptor); |
| if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) { |
| ALOGE("Injection camera HAL returns empty result metadata fmq, not use " |
| "it"); |
| resQueue = nullptr; |
| // Don't use the resQueue onwards. |
| } |
| }); |
| if (!resultQueueRet.isOk()) { |
| ALOGE("Injection camera transaction error when getting result metadata queue " |
| "from camera session: %s", resultQueueRet.description().c_str()); |
| return DEAD_OBJECT; |
| } |
| IF_ALOGV() { |
| session->interfaceChain( |
| [](::android::hardware::hidl_vec<::android::hardware::hidl_string> |
| interfaceChain) { |
| ALOGV("Injection camera session interface chain:"); |
| for (const auto& iface : interfaceChain) { |
| ALOGV(" %s", iface.c_str()); |
| } |
| }); |
| } |
| |
| ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__); |
| |
| mInjectedCamHalInterface = |
| new HidlHalInterface(session, queue, parent->mUseHalBufManager, |
| parent->mSupportOfflineProcessing); |
| if (mInjectedCamHalInterface == nullptr) { |
| ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| return OK; |
| } |
| |
| status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::replaceHalInterface( |
| sp<HalInterface> newHalInterface, bool keepBackup) { |
| Mutex::Autolock lock(mInjectionLock); |
| if (newHalInterface.get() == nullptr) { |
| ALOGE("%s: The newHalInterface does not exist, to stop replacing.", |
| __FUNCTION__); |
| return DEAD_OBJECT; |
| } |
| |
| sp<Camera3Device> parent = mParent.promote(); |
| if (parent == nullptr) { |
| ALOGE("%s: parent does not exist!", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| if (newHalInterface->getTransportType() != IPCTransport::HIDL) { |
| ALOGE("%s Replacing HIDL HalInterface with another transport unsupported", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| HidlCamera3Device *hidlParent = static_cast<HidlCamera3Device *>(parent.get()); |
| if (keepBackup) { |
| if (mBackupHalInterface == nullptr) { |
| mBackupHalInterface = parent->mInterface; |
| } |
| if (mBackupResultMetadataQueue == nullptr) { |
| mBackupResultMetadataQueue = std::move(hidlParent->mResultMetadataQueue); |
| hidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue); |
| } |
| } else { |
| mBackupHalInterface = nullptr; |
| hidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue); |
| mBackupResultMetadataQueue = nullptr; |
| } |
| parent->mInterface = newHalInterface; |
| |
| return OK; |
| } |
| |
| }; // namespace android |