Loading camera/device/3.2/default/CameraDeviceSession.cpp +45 −39 Original line number Diff line number Diff line Loading @@ -1198,26 +1198,19 @@ Return<void> CameraDeviceSession::close() { return Void(); } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult( const camera3_callback_ops *cb, void CameraDeviceSession::constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); uint32_t frameNumber = hal_result->frame_number; bool hasInputBuf = (hal_result->input_buffer != nullptr); size_t numOutputBufs = hal_result->num_output_buffers; size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); if (numBufs > 0) { Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); if (hasInputBuf) { int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; // validate if buffer is inflight auto key = std::make_pair(streamId, frameNumber); if (d->mInflightBuffers.count(key) != 1) { if (mInflightBuffers.count(key) != 1) { ALOGE("%s: input buffer for stream %d frame %d is not inflight!", __FUNCTION__, streamId, frameNumber); return; Loading @@ -1228,7 +1221,7 @@ void CameraDeviceSession::sProcessCaptureResult( int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; // validate if buffer is inflight auto key = std::make_pair(streamId, frameNumber); if (d->mInflightBuffers.count(key) != 1) { if (mInflightBuffers.count(key) != 1) { ALOGE("%s: output buffer for stream %d frame %d is not inflight!", __FUNCTION__, streamId, frameNumber); return; Loading @@ -1237,64 +1230,63 @@ void CameraDeviceSession::sProcessCaptureResult( } // We don't need to validate/import fences here since we will be passing them to camera service // within the scope of this function CaptureResult result; result.frameNumber = frameNumber; result.fmqResultSize = 0; result.partialResult = hal_result->partial_result; convertToHidl(hal_result->result, &result.result); if (nullptr != hal_result->result) { bool resultOverriden = false; Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); // Derive some new keys for backward compatibility if (d->mDerivePostRawSensKey) { if (mDerivePostRawSensKey) { camera_metadata_ro_entry entry; if (find_camera_metadata_ro_entry(hal_result->result, ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, &entry) == 0) { d->mInflightRawBoostPresent[frameNumber] = true; mInflightRawBoostPresent[frameNumber] = true; } else { auto entry = d->mInflightRawBoostPresent.find(frameNumber); if (d->mInflightRawBoostPresent.end() == entry) { d->mInflightRawBoostPresent[frameNumber] = false; auto entry = mInflightRawBoostPresent.find(frameNumber); if (mInflightRawBoostPresent.end() == entry) { mInflightRawBoostPresent[frameNumber] = false; } } if ((hal_result->partial_result == d->mNumPartialResults)) { if (!d->mInflightRawBoostPresent[frameNumber]) { if ((hal_result->partial_result == mNumPartialResults)) { if (!mInflightRawBoostPresent[frameNumber]) { if (!resultOverriden) { d->mOverridenResult.clear(); d->mOverridenResult.append(hal_result->result); mOverridenResult.clear(); mOverridenResult.append(hal_result->result); resultOverriden = true; } int32_t defaultBoost[1] = {100}; d->mOverridenResult.update( mOverridenResult.update( ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, defaultBoost, 1); } d->mInflightRawBoostPresent.erase(frameNumber); mInflightRawBoostPresent.erase(frameNumber); } } auto entry = d->mInflightAETriggerOverrides.find(frameNumber); if (d->mInflightAETriggerOverrides.end() != entry) { auto entry = mInflightAETriggerOverrides.find(frameNumber); if (mInflightAETriggerOverrides.end() != entry) { if (!resultOverriden) { d->mOverridenResult.clear(); d->mOverridenResult.append(hal_result->result); mOverridenResult.clear(); mOverridenResult.append(hal_result->result); resultOverriden = true; } d->overrideResultForPrecaptureCancelLocked(entry->second, &d->mOverridenResult); if (hal_result->partial_result == d->mNumPartialResults) { d->mInflightAETriggerOverrides.erase(frameNumber); overrideResultForPrecaptureCancelLocked(entry->second, &mOverridenResult); if (hal_result->partial_result == mNumPartialResults) { mInflightAETriggerOverrides.erase(frameNumber); } } if (resultOverriden) { const camera_metadata_t *metaBuffer = d->mOverridenResult.getAndLock(); mOverridenResult.getAndLock(); convertToHidl(metaBuffer, &result.result); d->mOverridenResult.unlock(metaBuffer); mOverridenResult.unlock(metaBuffer); } } if (hasInputBuf) { Loading Loading @@ -1335,24 +1327,38 @@ void CameraDeviceSession::sProcessCaptureResult( // configure_streams right after the processCaptureResult call so we need to finish // updating inflight queues first if (numBufs > 0) { Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); if (hasInputBuf) { int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; auto key = std::make_pair(streamId, frameNumber); d->mInflightBuffers.erase(key); mInflightBuffers.erase(key); } for (size_t i = 0; i < numOutputBufs; i++) { int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; auto key = std::make_pair(streamId, frameNumber); d->mInflightBuffers.erase(key); mInflightBuffers.erase(key); } if (d->mInflightBuffers.empty()) { if (mInflightBuffers.empty()) { ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__); } } } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult( const camera3_callback_ops *cb, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); CaptureResult result; d->constructCaptureResult(result, hal_result); d->mResultBatcher.processCaptureResult(result); } Loading camera/device/3.2/default/CameraDeviceSession.h +14 −10 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ protected: void notify(NotifyMsg& msg); void processCaptureResult(CaptureResult& result); private: protected: struct InflightBatch { // Protect access to entire struct. Acquire this lock before read/write any data or // calling any methods. processCaptureResult and notify will compete for this lock Loading Loading @@ -235,7 +235,6 @@ protected: bool mRemoved = false; }; static const int NOT_BATCHED = -1; // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched) // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch Loading @@ -245,6 +244,16 @@ protected: // This method will hold ResultBatcher::mLock briefly std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber); static const int NOT_BATCHED = -1; // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native // handle void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst); void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst); void sendBatchMetadataLocked( std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx); // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so // This method will hold ResultBatcher::mLock briefly void checkAndRemoveFirstBatch(); Loading @@ -257,8 +266,6 @@ protected: // send buffers for specified streams void sendBatchBuffersLocked( std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams); void sendBatchMetadataLocked( std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx); // End of sendXXXX methods // helper methods Loading @@ -267,11 +274,6 @@ protected: void processOneCaptureResult(CaptureResult& result); void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq); // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native // handle void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst); void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst); // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch // processCaptureRequest, processCaptureResult, notify will compete for this lock // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error) Loading Loading @@ -325,6 +327,8 @@ protected: static callbacks_process_capture_result_t sProcessCaptureResult; static callbacks_notify_t sNotify; void constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result); private: struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession { Loading camera/device/3.4/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ hidl_interface { }, srcs: [ "types.hal", "ICameraDeviceCallback.hal", "ICameraDeviceSession.hal", ], interfaces: [ Loading @@ -19,8 +20,10 @@ hidl_interface { ], types: [ "CaptureRequest", "CaptureResult", "HalStream", "HalStreamConfiguration", "PhysicalCameraMetadata", "PhysicalCameraSetting", "RequestTemplate", "Stream", Loading camera/device/3.4/ICameraDeviceCallback.hal 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 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. */ package android.hardware.camera.device@3.4; import @3.2::ICameraDeviceCallback; /** * * Callback methods for the HAL to call into the framework. * * These methods are used to return metadata and image buffers for a completed * or failed captures, and to notify the framework of asynchronous events such * as errors. * * The framework must not call back into the HAL from within these callbacks, * and these calls must not block for extended periods. * */ interface ICameraDeviceCallback extends @3.2::ICameraDeviceCallback { /** * processCaptureResult_3_4: * * Identical to @3.2::ICameraDeviceCallback.processCaptureResult, except * that it takes a list of @3.4::CaptureResult, which could contain * physical camera metadata for logical multi-camera. * */ processCaptureResult_3_4(vec<@3.4::CaptureResult> results); }; camera/device/3.4/default/CameraDeviceSession.cpp +261 −3 Original line number Diff line number Diff line Loading @@ -34,7 +34,23 @@ CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp<V3_2::ICameraDeviceCallback>& callback) : V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) { V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback), mResultBatcher_3_4(callback) { mHasCallback_3_4 = false; auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { sp<ICameraDeviceCallback> callback3_4 = castResult; if (callback3_4 != nullptr) { process_capture_result = sProcessCaptureResult_3_4; notify = sNotify_3_4; mHasCallback_3_4 = true; if (!mInitFail) { mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue); } } } } CameraDeviceSession::~CameraDeviceSession() { Loading @@ -54,6 +70,18 @@ Return<void> CameraDeviceSession::configureStreams_3_4( 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); Loading Loading @@ -205,7 +233,7 @@ void CameraDeviceSession::postProcessConfigurationLocked_3_4( mVideoStreamIds.push_back(stream.v3_2.id); } } mResultBatcher.setBatchedStreams(mVideoStreamIds); mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds); } Return<void> CameraDeviceSession::processCaptureRequest_3_4( Loading @@ -224,7 +252,7 @@ Return<void> CameraDeviceSession::processCaptureRequest_3_4( } if (s == Status::OK && requests.size() > 1) { mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size()); mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size()); } _hidl_cb(s, numRequestProcessed); Loading @@ -237,6 +265,14 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ 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; Loading Loading @@ -407,6 +443,228 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ return Status::OK; } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult_3_4( const camera3_callback_ops *cb, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); CaptureResult result; d->constructCaptureResult(result.v3_2, hal_result); result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata); for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) { std::string physicalId = hal_result->physcam_ids[i]; V3_2::CameraMetadata physicalMetadata; V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata); PhysicalCameraMetadata physicalCameraMetadata = { .fmqMetadataSize = 0, .physicalCameraId = physicalId, .metadata = physicalMetadata }; result.physicalCameraMetadata[i] = physicalCameraMetadata; } d->mResultBatcher_3_4.processCaptureResult_3_4(result); } void CameraDeviceSession::sNotify_3_4( const camera3_callback_ops *cb, const camera3_notify_msg *msg) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); V3_2::NotifyMsg hidlMsg; V3_2::implementation::convertToHidl(msg, &hidlMsg); if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR && hidlMsg.msg.error.errorStreamId != -1) { if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) { ALOGE("%s: unknown stream ID %d reports an error!", __FUNCTION__, hidlMsg.msg.error.errorStreamId); return; } } if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) { switch (hidlMsg.msg.error.errorCode) { case V3_2::ErrorCode::ERROR_DEVICE: case V3_2::ErrorCode::ERROR_REQUEST: case V3_2::ErrorCode::ERROR_RESULT: { Mutex::Autolock _l(d->mInflightLock); auto entry = d->mInflightAETriggerOverrides.find( hidlMsg.msg.error.frameNumber); if (d->mInflightAETriggerOverrides.end() != entry) { d->mInflightAETriggerOverrides.erase( hidlMsg.msg.error.frameNumber); } auto boostEntry = d->mInflightRawBoostPresent.find( hidlMsg.msg.error.frameNumber); if (d->mInflightRawBoostPresent.end() != boostEntry) { d->mInflightRawBoostPresent.erase( hidlMsg.msg.error.frameNumber); } } break; case V3_2::ErrorCode::ERROR_BUFFER: default: break; } } d->mResultBatcher_3_4.notify(hidlMsg); } CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4( const sp<V3_2::ICameraDeviceCallback>& callback) : V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) { auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { mCallback_3_4 = castResult; } } void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) { auto pair = getBatch(result.v3_2.frameNumber); int batchIdx = pair.first; if (batchIdx == NOT_BATCHED) { processOneCaptureResult_3_4(result); return; } std::shared_ptr<InflightBatch> batch = pair.second; { Mutex::Autolock _l(batch->mLock); // Check if the batch is removed (mostly by notify error) before lock was acquired if (batch->mRemoved) { // Fall back to non-batch path processOneCaptureResult_3_4(result); return; } // queue metadata if (result.v3_2.result.size() != 0) { // Save a copy of metadata batch->mResultMds[result.v3_2.partialResult].mMds.push_back( std::make_pair(result.v3_2.frameNumber, result.v3_2.result)); } // queue buffer std::vector<int> filledStreams; std::vector<V3_2::StreamBuffer> nonBatchedBuffers; for (auto& buffer : result.v3_2.outputBuffers) { auto it = batch->mBatchBufs.find(buffer.streamId); if (it != batch->mBatchBufs.end()) { InflightBatch::BufferBatch& bb = it->second; 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<CaptureResult> results; results.resize(1); results[0] = std::move(result); invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true); freeReleaseFences_3_4(results); return; } void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4( hidl_vec<CaptureResult> &results, bool tryWriteFmq) { if (mProcessCaptureResultLock.tryLock() != OK) { ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) { ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__); return; } } if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { for (CaptureResult &result : results) { if (result.v3_2.result.size() > 0) { if (mResultMetadataQueue->write(result.v3_2.result.data(), result.v3_2.result.size())) { result.v3_2.fmqResultSize = result.v3_2.result.size(); result.v3_2.result.resize(0); } else { ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); result.v3_2.fmqResultSize = 0; } } for (auto& onePhysMetadata : result.physicalCameraMetadata) { if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(), onePhysMetadata.metadata.size())) { onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size(); onePhysMetadata.metadata.resize(0); } else { ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); onePhysMetadata.fmqMetadataSize = 0; } } } } mCallback_3_4->processCaptureResult_3_4(results); mProcessCaptureResultLock.unlock(); } void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) { for (auto& result : results) { if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) { native_handle_t* handle = const_cast<native_handle_t*>( result.v3_2.inputBuffer.releaseFence.getNativeHandle()); native_handle_close(handle); native_handle_delete(handle); } for (auto& buf : result.v3_2.outputBuffers) { if (buf.releaseFence.getNativeHandle() != nullptr) { native_handle_t* handle = const_cast<native_handle_t*>( buf.releaseFence.getNativeHandle()); native_handle_close(handle); native_handle_delete(handle); } } } return; } } // namespace implementation } // namespace V3_4 } // namespace device Loading Loading
camera/device/3.2/default/CameraDeviceSession.cpp +45 −39 Original line number Diff line number Diff line Loading @@ -1198,26 +1198,19 @@ Return<void> CameraDeviceSession::close() { return Void(); } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult( const camera3_callback_ops *cb, void CameraDeviceSession::constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); uint32_t frameNumber = hal_result->frame_number; bool hasInputBuf = (hal_result->input_buffer != nullptr); size_t numOutputBufs = hal_result->num_output_buffers; size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); if (numBufs > 0) { Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); if (hasInputBuf) { int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; // validate if buffer is inflight auto key = std::make_pair(streamId, frameNumber); if (d->mInflightBuffers.count(key) != 1) { if (mInflightBuffers.count(key) != 1) { ALOGE("%s: input buffer for stream %d frame %d is not inflight!", __FUNCTION__, streamId, frameNumber); return; Loading @@ -1228,7 +1221,7 @@ void CameraDeviceSession::sProcessCaptureResult( int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; // validate if buffer is inflight auto key = std::make_pair(streamId, frameNumber); if (d->mInflightBuffers.count(key) != 1) { if (mInflightBuffers.count(key) != 1) { ALOGE("%s: output buffer for stream %d frame %d is not inflight!", __FUNCTION__, streamId, frameNumber); return; Loading @@ -1237,64 +1230,63 @@ void CameraDeviceSession::sProcessCaptureResult( } // We don't need to validate/import fences here since we will be passing them to camera service // within the scope of this function CaptureResult result; result.frameNumber = frameNumber; result.fmqResultSize = 0; result.partialResult = hal_result->partial_result; convertToHidl(hal_result->result, &result.result); if (nullptr != hal_result->result) { bool resultOverriden = false; Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); // Derive some new keys for backward compatibility if (d->mDerivePostRawSensKey) { if (mDerivePostRawSensKey) { camera_metadata_ro_entry entry; if (find_camera_metadata_ro_entry(hal_result->result, ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, &entry) == 0) { d->mInflightRawBoostPresent[frameNumber] = true; mInflightRawBoostPresent[frameNumber] = true; } else { auto entry = d->mInflightRawBoostPresent.find(frameNumber); if (d->mInflightRawBoostPresent.end() == entry) { d->mInflightRawBoostPresent[frameNumber] = false; auto entry = mInflightRawBoostPresent.find(frameNumber); if (mInflightRawBoostPresent.end() == entry) { mInflightRawBoostPresent[frameNumber] = false; } } if ((hal_result->partial_result == d->mNumPartialResults)) { if (!d->mInflightRawBoostPresent[frameNumber]) { if ((hal_result->partial_result == mNumPartialResults)) { if (!mInflightRawBoostPresent[frameNumber]) { if (!resultOverriden) { d->mOverridenResult.clear(); d->mOverridenResult.append(hal_result->result); mOverridenResult.clear(); mOverridenResult.append(hal_result->result); resultOverriden = true; } int32_t defaultBoost[1] = {100}; d->mOverridenResult.update( mOverridenResult.update( ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, defaultBoost, 1); } d->mInflightRawBoostPresent.erase(frameNumber); mInflightRawBoostPresent.erase(frameNumber); } } auto entry = d->mInflightAETriggerOverrides.find(frameNumber); if (d->mInflightAETriggerOverrides.end() != entry) { auto entry = mInflightAETriggerOverrides.find(frameNumber); if (mInflightAETriggerOverrides.end() != entry) { if (!resultOverriden) { d->mOverridenResult.clear(); d->mOverridenResult.append(hal_result->result); mOverridenResult.clear(); mOverridenResult.append(hal_result->result); resultOverriden = true; } d->overrideResultForPrecaptureCancelLocked(entry->second, &d->mOverridenResult); if (hal_result->partial_result == d->mNumPartialResults) { d->mInflightAETriggerOverrides.erase(frameNumber); overrideResultForPrecaptureCancelLocked(entry->second, &mOverridenResult); if (hal_result->partial_result == mNumPartialResults) { mInflightAETriggerOverrides.erase(frameNumber); } } if (resultOverriden) { const camera_metadata_t *metaBuffer = d->mOverridenResult.getAndLock(); mOverridenResult.getAndLock(); convertToHidl(metaBuffer, &result.result); d->mOverridenResult.unlock(metaBuffer); mOverridenResult.unlock(metaBuffer); } } if (hasInputBuf) { Loading Loading @@ -1335,24 +1327,38 @@ void CameraDeviceSession::sProcessCaptureResult( // configure_streams right after the processCaptureResult call so we need to finish // updating inflight queues first if (numBufs > 0) { Mutex::Autolock _l(d->mInflightLock); Mutex::Autolock _l(mInflightLock); if (hasInputBuf) { int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; auto key = std::make_pair(streamId, frameNumber); d->mInflightBuffers.erase(key); mInflightBuffers.erase(key); } for (size_t i = 0; i < numOutputBufs; i++) { int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; auto key = std::make_pair(streamId, frameNumber); d->mInflightBuffers.erase(key); mInflightBuffers.erase(key); } if (d->mInflightBuffers.empty()) { if (mInflightBuffers.empty()) { ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__); } } } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult( const camera3_callback_ops *cb, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); CaptureResult result; d->constructCaptureResult(result, hal_result); d->mResultBatcher.processCaptureResult(result); } Loading
camera/device/3.2/default/CameraDeviceSession.h +14 −10 Original line number Diff line number Diff line Loading @@ -190,7 +190,7 @@ protected: void notify(NotifyMsg& msg); void processCaptureResult(CaptureResult& result); private: protected: struct InflightBatch { // Protect access to entire struct. Acquire this lock before read/write any data or // calling any methods. processCaptureResult and notify will compete for this lock Loading Loading @@ -235,7 +235,6 @@ protected: bool mRemoved = false; }; static const int NOT_BATCHED = -1; // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched) // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch Loading @@ -245,6 +244,16 @@ protected: // This method will hold ResultBatcher::mLock briefly std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber); static const int NOT_BATCHED = -1; // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native // handle void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst); void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst); void sendBatchMetadataLocked( std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx); // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so // This method will hold ResultBatcher::mLock briefly void checkAndRemoveFirstBatch(); Loading @@ -257,8 +266,6 @@ protected: // send buffers for specified streams void sendBatchBuffersLocked( std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams); void sendBatchMetadataLocked( std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx); // End of sendXXXX methods // helper methods Loading @@ -267,11 +274,6 @@ protected: void processOneCaptureResult(CaptureResult& result); void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq); // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native // handle void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst); void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst); // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch // processCaptureRequest, processCaptureResult, notify will compete for this lock // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error) Loading Loading @@ -325,6 +327,8 @@ protected: static callbacks_process_capture_result_t sProcessCaptureResult; static callbacks_notify_t sNotify; void constructCaptureResult(CaptureResult& result, const camera3_capture_result *hal_result); private: struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession { Loading
camera/device/3.4/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ hidl_interface { }, srcs: [ "types.hal", "ICameraDeviceCallback.hal", "ICameraDeviceSession.hal", ], interfaces: [ Loading @@ -19,8 +20,10 @@ hidl_interface { ], types: [ "CaptureRequest", "CaptureResult", "HalStream", "HalStreamConfiguration", "PhysicalCameraMetadata", "PhysicalCameraSetting", "RequestTemplate", "Stream", Loading
camera/device/3.4/ICameraDeviceCallback.hal 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 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. */ package android.hardware.camera.device@3.4; import @3.2::ICameraDeviceCallback; /** * * Callback methods for the HAL to call into the framework. * * These methods are used to return metadata and image buffers for a completed * or failed captures, and to notify the framework of asynchronous events such * as errors. * * The framework must not call back into the HAL from within these callbacks, * and these calls must not block for extended periods. * */ interface ICameraDeviceCallback extends @3.2::ICameraDeviceCallback { /** * processCaptureResult_3_4: * * Identical to @3.2::ICameraDeviceCallback.processCaptureResult, except * that it takes a list of @3.4::CaptureResult, which could contain * physical camera metadata for logical multi-camera. * */ processCaptureResult_3_4(vec<@3.4::CaptureResult> results); };
camera/device/3.4/default/CameraDeviceSession.cpp +261 −3 Original line number Diff line number Diff line Loading @@ -34,7 +34,23 @@ CameraDeviceSession::CameraDeviceSession( camera3_device_t* device, const camera_metadata_t* deviceInfo, const sp<V3_2::ICameraDeviceCallback>& callback) : V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) { V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback), mResultBatcher_3_4(callback) { mHasCallback_3_4 = false; auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { sp<ICameraDeviceCallback> callback3_4 = castResult; if (callback3_4 != nullptr) { process_capture_result = sProcessCaptureResult_3_4; notify = sNotify_3_4; mHasCallback_3_4 = true; if (!mInitFail) { mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue); } } } } CameraDeviceSession::~CameraDeviceSession() { Loading @@ -54,6 +70,18 @@ Return<void> CameraDeviceSession::configureStreams_3_4( 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); Loading Loading @@ -205,7 +233,7 @@ void CameraDeviceSession::postProcessConfigurationLocked_3_4( mVideoStreamIds.push_back(stream.v3_2.id); } } mResultBatcher.setBatchedStreams(mVideoStreamIds); mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds); } Return<void> CameraDeviceSession::processCaptureRequest_3_4( Loading @@ -224,7 +252,7 @@ Return<void> CameraDeviceSession::processCaptureRequest_3_4( } if (s == Status::OK && requests.size() > 1) { mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size()); mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size()); } _hidl_cb(s, numRequestProcessed); Loading @@ -237,6 +265,14 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ 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; Loading Loading @@ -407,6 +443,228 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ return Status::OK; } /** * Static callback forwarding methods from HAL to instance */ void CameraDeviceSession::sProcessCaptureResult_3_4( const camera3_callback_ops *cb, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); CaptureResult result; d->constructCaptureResult(result.v3_2, hal_result); result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata); for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) { std::string physicalId = hal_result->physcam_ids[i]; V3_2::CameraMetadata physicalMetadata; V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata); PhysicalCameraMetadata physicalCameraMetadata = { .fmqMetadataSize = 0, .physicalCameraId = physicalId, .metadata = physicalMetadata }; result.physicalCameraMetadata[i] = physicalCameraMetadata; } d->mResultBatcher_3_4.processCaptureResult_3_4(result); } void CameraDeviceSession::sNotify_3_4( const camera3_callback_ops *cb, const camera3_notify_msg *msg) { CameraDeviceSession *d = const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); V3_2::NotifyMsg hidlMsg; V3_2::implementation::convertToHidl(msg, &hidlMsg); if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR && hidlMsg.msg.error.errorStreamId != -1) { if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) { ALOGE("%s: unknown stream ID %d reports an error!", __FUNCTION__, hidlMsg.msg.error.errorStreamId); return; } } if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) { switch (hidlMsg.msg.error.errorCode) { case V3_2::ErrorCode::ERROR_DEVICE: case V3_2::ErrorCode::ERROR_REQUEST: case V3_2::ErrorCode::ERROR_RESULT: { Mutex::Autolock _l(d->mInflightLock); auto entry = d->mInflightAETriggerOverrides.find( hidlMsg.msg.error.frameNumber); if (d->mInflightAETriggerOverrides.end() != entry) { d->mInflightAETriggerOverrides.erase( hidlMsg.msg.error.frameNumber); } auto boostEntry = d->mInflightRawBoostPresent.find( hidlMsg.msg.error.frameNumber); if (d->mInflightRawBoostPresent.end() != boostEntry) { d->mInflightRawBoostPresent.erase( hidlMsg.msg.error.frameNumber); } } break; case V3_2::ErrorCode::ERROR_BUFFER: default: break; } } d->mResultBatcher_3_4.notify(hidlMsg); } CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4( const sp<V3_2::ICameraDeviceCallback>& callback) : V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) { auto castResult = ICameraDeviceCallback::castFrom(callback); if (castResult.isOk()) { mCallback_3_4 = castResult; } } void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) { auto pair = getBatch(result.v3_2.frameNumber); int batchIdx = pair.first; if (batchIdx == NOT_BATCHED) { processOneCaptureResult_3_4(result); return; } std::shared_ptr<InflightBatch> batch = pair.second; { Mutex::Autolock _l(batch->mLock); // Check if the batch is removed (mostly by notify error) before lock was acquired if (batch->mRemoved) { // Fall back to non-batch path processOneCaptureResult_3_4(result); return; } // queue metadata if (result.v3_2.result.size() != 0) { // Save a copy of metadata batch->mResultMds[result.v3_2.partialResult].mMds.push_back( std::make_pair(result.v3_2.frameNumber, result.v3_2.result)); } // queue buffer std::vector<int> filledStreams; std::vector<V3_2::StreamBuffer> nonBatchedBuffers; for (auto& buffer : result.v3_2.outputBuffers) { auto it = batch->mBatchBufs.find(buffer.streamId); if (it != batch->mBatchBufs.end()) { InflightBatch::BufferBatch& bb = it->second; 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<CaptureResult> results; results.resize(1); results[0] = std::move(result); invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true); freeReleaseFences_3_4(results); return; } void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4( hidl_vec<CaptureResult> &results, bool tryWriteFmq) { if (mProcessCaptureResultLock.tryLock() != OK) { ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__); if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) { ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__); return; } } if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) { for (CaptureResult &result : results) { if (result.v3_2.result.size() > 0) { if (mResultMetadataQueue->write(result.v3_2.result.data(), result.v3_2.result.size())) { result.v3_2.fmqResultSize = result.v3_2.result.size(); result.v3_2.result.resize(0); } else { ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); result.v3_2.fmqResultSize = 0; } } for (auto& onePhysMetadata : result.physicalCameraMetadata) { if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(), onePhysMetadata.metadata.size())) { onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size(); onePhysMetadata.metadata.resize(0); } else { ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); onePhysMetadata.fmqMetadataSize = 0; } } } } mCallback_3_4->processCaptureResult_3_4(results); mProcessCaptureResultLock.unlock(); } void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) { for (auto& result : results) { if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) { native_handle_t* handle = const_cast<native_handle_t*>( result.v3_2.inputBuffer.releaseFence.getNativeHandle()); native_handle_close(handle); native_handle_delete(handle); } for (auto& buf : result.v3_2.outputBuffers) { if (buf.releaseFence.getNativeHandle() != nullptr) { native_handle_t* handle = const_cast<native_handle_t*>( buf.releaseFence.getNativeHandle()); native_handle_close(handle); native_handle_delete(handle); } } } return; } } // namespace implementation } // namespace V3_4 } // namespace device Loading