diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal index bf51da2133..69715dec64 100644 --- a/camera/device/3.2/ICameraDeviceCallback.hal +++ b/camera/device/3.2/ICameraDeviceCallback.hal @@ -42,7 +42,9 @@ interface ICameraDeviceCallback { * metadata and low-resolution buffers to be returned in one call, and * post-processed JPEG buffers in a later call, once it is available. Each * call must include the frame number of the request it is returning - * metadata or buffers for. + * metadata or buffers for. Only one call to processCaptureResult + * may be made at a time by the HAL although the calls may come from + * different threads in the HAL. * * A component (buffer or metadata) of the complete result may only be * included in one process_capture_result call. A buffer for each stream, diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal index bf568813ba..477a3cc5d0 100644 --- a/camera/device/3.2/ICameraDeviceSession.hal +++ b/camera/device/3.2/ICameraDeviceSession.hal @@ -262,6 +262,24 @@ interface ICameraDeviceSession { */ getCaptureRequestMetadataQueue() generates (fmq_sync queue); + /** + * getCaptureResultMetadataQueue: + * + * Retrieves the queue used along with + * ICameraDeviceCallback.processCaptureResult. + * + * Clients to ICameraDeviceSession must: + * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue; + * - In implementation of ICameraDeviceCallback, test whether + * .fmqResultSize field is zero. + * - If .fmqResultSize != 0, read result metadata from the fast message + * queue; + * - otherwise, read result metadata in CaptureResult.result. + * + * @return queue the queue that implementation writes result metadata to. + */ + getCaptureResultMetadataQueue() generates (fmq_sync queue); + /** * flush: * diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index ebb8fcb735..2499b1abea 100644 --- a/camera/device/3.2/default/CameraDeviceSession.cpp +++ b/camera/device/3.2/default/CameraDeviceSession.cpp @@ -32,6 +32,8 @@ namespace implementation { // Size of request metadata fast message queue. Change to 0 to always use hwbinder buffer. static constexpr size_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1MB */; +// Size of result metadata fast message queue. Change to 0 to always use hwbinder buffer. +static constexpr size_t CAMERA_RESULT_METADATA_QUEUE_SIZE = 1 << 20 /* 1MB */; HandleImporter& CameraDeviceSession::sHandleImporter = HandleImporter::getInstance(); const int CameraDeviceSession::ResultBatcher::NOT_BATCHED; @@ -73,9 +75,16 @@ bool CameraDeviceSession::initialize() { mRequestMetadataQueue = std::make_unique( CAMERA_REQUEST_METADATA_QUEUE_SIZE, false /* non blocking */); if (!mRequestMetadataQueue->isValid()) { - ALOGE("%s: invalid fmq", __FUNCTION__); + ALOGE("%s: invalid request fmq", __FUNCTION__); return true; } + mResultMetadataQueue = std::make_shared( + CAMERA_RESULT_METADATA_QUEUE_SIZE, false /* non blocking */); + if (!mResultMetadataQueue->isValid()) { + ALOGE("%s: invalid result fmq", __FUNCTION__); + return true; + } + mResultBatcher.setResultMetadataQueue(mResultMetadataQueue); return false; } @@ -231,6 +240,11 @@ void CameraDeviceSession::ResultBatcher::setBatchedStreams( mStreamsToBatch = streamsToBatch; } +void CameraDeviceSession::ResultBatcher::setResultMetadataQueue(std::shared_ptr q) { + Mutex::Autolock _l(mLock); + mResultMetadataQueue = q; +} + void CameraDeviceSession::ResultBatcher::registerBatch( const hidl_vec& requests) { auto batch = std::make_shared(); @@ -350,6 +364,7 @@ void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked( results.resize(batchSize); for (size_t i = 0; i < batchSize; i++) { results[i].frameNumber = batch->mFirstFrame + i; + results[i].fmqResultSize = 0; results[i].partialResult = 0; // 0 for buffer only results results[i].inputBuffer.streamId = -1; results[i].inputBuffer.bufferId = 0; @@ -366,7 +381,7 @@ void CameraDeviceSession::ResultBatcher::sendBatchBuffersLocked( } results[i].outputBuffers = outBufs; } - mCallback->processCaptureResult(results); + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */false); freeReleaseFences(results); for (int streamId : streams) { InflightBatch::BufferBatch& bb = batch->mBatchBufs[streamId]; @@ -396,6 +411,7 @@ void CameraDeviceSession::ResultBatcher::sendBatchMetadataLocked( CaptureResult result; result.frameNumber = p.first; result.result = std::move(p.second); + result.fmqResultSize = 0; result.inputBuffer.streamId = -1; result.inputBuffer.bufferId = 0; result.inputBuffer.buffer = nullptr; @@ -404,7 +420,9 @@ void CameraDeviceSession::ResultBatcher::sendBatchMetadataLocked( } mb.mMds.clear(); } - mCallback->processCaptureResult(results); + hidl_vec hResults; + hResults.setToExternal(results.data(), results.size()); + invokeProcessCaptureResultCallback(hResults, /* tryWriteFmq */true); batch->mPartialResultProgress = lastPartialResultIdx; for (uint32_t partialIdx : toBeRemovedIdxes) { batch->mResultMds.erase(partialIdx); @@ -477,9 +495,37 @@ void CameraDeviceSession::ResultBatcher::notify(NotifyMsg& msg) { } } +void CameraDeviceSession::ResultBatcher::invokeProcessCaptureResultCallback( + hidl_vec &results, bool tryWriteFmq) { + if (mProcessCaptureResultLock.tryLock() != OK) { + ALOGW("%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.result.size() > 0) { + if (mResultMetadataQueue->write(result.result.data(), result.result.size())) { + result.fmqResultSize = result.result.size(); + result.result.resize(0); + } else { + ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__); + result.fmqResultSize = 0; + } + } + } + } + mCallback->processCaptureResult(results); + mProcessCaptureResultLock.unlock(); +} + void CameraDeviceSession::ResultBatcher::processOneCaptureResult(CaptureResult& result) { hidl_vec results = {result}; - mCallback->processCaptureResult(results); + invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true); freeReleaseFences(results); return; } @@ -526,6 +572,7 @@ void CameraDeviceSession::ResultBatcher::processCaptureResult(CaptureResult& res if (nonBatchedBuffers.size() > 0 || result.inputBuffer.streamId != -1) { CaptureResult nonBatchedResult; nonBatchedResult.frameNumber = result.frameNumber; + nonBatchedResult.fmqResultSize = 0; nonBatchedResult.outputBuffers = nonBatchedBuffers; nonBatchedResult.inputBuffer = result.inputBuffer; nonBatchedResult.partialResult = 0; // 0 for buffer only results @@ -716,6 +763,12 @@ Return CameraDeviceSession::getCaptureRequestMetadataQueue( return Void(); } +Return CameraDeviceSession::getCaptureResultMetadataQueue( + getCaptureResultMetadataQueue_cb _hidl_cb) { + _hidl_cb(*mResultMetadataQueue->getDesc()); + return Void(); +} + Return CameraDeviceSession::processCaptureRequest( const hidl_vec& requests, const hidl_vec& cachesToRemove, @@ -915,6 +968,7 @@ void CameraDeviceSession::sProcessCaptureResult( // 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 (hasInputBuf) { diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h index f59f503b9a..7682165c15 100644 --- a/camera/device/3.2/default/CameraDeviceSession.h +++ b/camera/device/3.2/default/CameraDeviceSession.h @@ -90,6 +90,8 @@ struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callba const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override; Return getCaptureRequestMetadataQueue( getCaptureRequestMetadataQueue_cb _hidl_cb) override; + Return getCaptureResultMetadataQueue( + getCaptureResultMetadataQueue_cb _hidl_cb) override; Return processCaptureRequest( const hidl_vec& requests, const hidl_vec& cachesToRemove, @@ -134,12 +136,15 @@ private: using RequestMetadataQueue = MessageQueue; std::unique_ptr mRequestMetadataQueue; + using ResultMetadataQueue = MessageQueue; + std::shared_ptr mResultMetadataQueue; class ResultBatcher { public: ResultBatcher(const sp& callback); void setNumPartialResults(uint32_t n); void setBatchedStreams(const std::vector& streamsToBatch); + void setResultMetadataQueue(std::shared_ptr q); void registerBatch(const hidl_vec& requests); void notify(NotifyMsg& msg); @@ -217,6 +222,7 @@ private: void freeReleaseFences(hidl_vec&); void notifySingleMsg(NotifyMsg& msg); void processOneCaptureResult(CaptureResult& result); + void invokeProcessCaptureResultCallback(hidl_vec &results, bool tryWriteFmq); // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch // processCaptureRequest, processCaptureResult, notify will compete for this lock @@ -226,6 +232,11 @@ private: uint32_t mNumPartialResults; std::vector mStreamsToBatch; const sp mCallback; + std::shared_ptr mResultMetadataQueue; + + // Protect against invokeProcessCaptureResultCallback() + Mutex mProcessCaptureResultLock; + } mResultBatcher; std::vector mVideoStreamIds; diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal index 8e433f62b1..276e92a3ee 100644 --- a/camera/device/3.2/types.hal +++ b/camera/device/3.2/types.hal @@ -852,6 +852,13 @@ struct CaptureResult { */ uint32_t frameNumber; + /** + * If non-zero, read result from result queue instead + * (see ICameraDeviceSession.getCaptureResultMetadataQueue). + * If zero, read result from .result field. + */ + uint64_t fmqResultSize; + /** * The result metadata for this capture. This contains information about the * final capture parameters, the state of the capture and post-processing