/* * Copyright (C) 2017-2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "CamDevSession@3.4-impl" #include #include #include #include #include #include "CameraDeviceSession.h" namespace android { namespace hardware { namespace camera { namespace device { namespace V3_4 { namespace implementation { CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp& callback) : V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback), mResultBatcher_3_4(callback) { mHasCallback_3_4 = false; auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { sp 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); camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); bool isLogicalMultiCamera = false; for (size_t i = 0; i < capabilities.count; i++) { if (capabilities.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) { isLogicalMultiCamera = true; break; } } if (isLogicalMultiCamera) { camera_metadata_entry entry = mDeviceInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS); const uint8_t* ids = entry.data.u8; size_t start = 0; for (size_t i = 0; i < entry.count; ++i) { if (ids[i] == '\0') { if (start != i) { const char* physicalId = reinterpret_cast(ids+start); mPhysicalCameraIds.emplace(physicalId); } start = i + 1; } } } } CameraDeviceSession::~CameraDeviceSession() { } Return CameraDeviceSession::configureStreams_3_4( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) { 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 Void(); } } } // hold the inflight lock for entire configureStreams scope since there must not be any // inflight request/results during stream configuration. Mutex::Autolock _l(mInflightLock); if (!mInflightBuffers.empty()) { ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", __FUNCTION__, mInflightBuffers.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); return Void(); } if (!mInflightAETriggerOverrides.empty()) { ALOGE("%s: trying to configureStreams while there are still %zu inflight" " trigger overrides!", __FUNCTION__, mInflightAETriggerOverrides.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); return Void(); } if (!mInflightRawBoostPresent.empty()) { ALOGE("%s: trying to configureStreams while there are still %zu inflight" " boost overrides!", __FUNCTION__, mInflightRawBoostPresent.size()); _hidl_cb(Status::INTERNAL_ERROR, outStreams); return Void(); } if (status != Status::OK) { _hidl_cb(status, outStreams); return Void(); } const camera_metadata_t *paramBuffer = nullptr; if (0 < requestedConfiguration.sessionParams.size()) { V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, ¶mBuffer); } camera3_stream_configuration_t stream_list{}; hidl_vec streams; stream_list.session_parameters = paramBuffer; if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) { _hidl_cb(Status::INTERNAL_ERROR, outStreams); return Void(); } ATRACE_BEGIN("camera3->configure_streams"); status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); ATRACE_END(); // In case Hal returns error most likely it was not able to release // the corresponding resources of the deleted streams. if (ret == OK) { postProcessConfigurationLocked_3_4(requestedConfiguration); } 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 Void(); } bool CameraDeviceSession::preProcessConfigurationLocked_3_4( const StreamConfiguration& requestedConfiguration, camera3_stream_configuration_t *stream_list /*out*/, hidl_vec *streams /*out*/) { if ((stream_list == nullptr) || (streams == nullptr)) { return false; } stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode; stream_list->num_streams = requestedConfiguration.streams.size(); streams->resize(stream_list->num_streams); stream_list->streams = streams->data(); for (uint32_t i = 0; i < stream_list->num_streams; i++) { int id = requestedConfiguration.streams[i].v3_2.id; if (mStreamMap.count(id) == 0) { Camera3Stream stream; convertFromHidl(requestedConfiguration.streams[i], &stream); mStreamMap[id] = stream; mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId; mStreamMap[id].data_space = mapToLegacyDataspace( mStreamMap[id].data_space); mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str(); mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); } else { // width/height/format must not change, but usage/rotation might need to change if (mStreamMap[id].stream_type != (int) requestedConfiguration.streams[i].v3_2.streamType || mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width || mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height || mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format || mStreamMap[id].data_space != mapToLegacyDataspace( static_cast ( requestedConfiguration.streams[i].v3_2.dataSpace)) || mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) { ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); return false; } mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation; mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage; } (*streams)[i] = &mStreamMap[id]; } 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 CameraDeviceSession::processCaptureRequest_3_4( const hidl_vec& requests, const hidl_vec& 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 allBufPtrs; hidl_vec 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 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 physicalCameraIds; std::vector physicalCameraSettings; std::vector 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(static_cast(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 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(static_cast(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(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& 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 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 filledStreams; std::vector 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; pushStreamBuffer(std::move(buffer), bb.mBuffers); filledStreams.push_back(buffer.streamId); } 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 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 &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& results) { for (auto& result : results) { if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) { native_handle_t* handle = const_cast( 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( 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