From patchwork Tue Jul 26 18:25:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Hanlin Chen X-Patchwork-Id: 16807 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4408BBE173 for ; Tue, 26 Jul 2022 18:25:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 00AFE63326; Tue, 26 Jul 2022 20:25:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1658859942; bh=kC/obOEbRUaRNbcrPqopvP2rrKB/+JQCu9KyLBSHlK0=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=pEKf82/5OCeaka/LCWvx/SuvtJ0I/T6ldPUabtO1YWdtddRkgonpSaKMbdumQtz00 MvP1qfl9aFqQeheJFE6yiTKts69yqGOXDIfg4MLAvnOgNto0+i6CTryy4mPg1sopXX 1icfFS5hy5Obqq783IjsY/wSbFGk6wFEND/r/6v26xeBcLGHY4Dgy4pzMe2pm/ncXY QE5ZIwW/4d61edWndIgWDp8cGbSjHEYHY9JuqHGdiON3y6yRJjrTKHsw0yUz7MHuiO LDm1Pfm6N5fuMuAlac3B+rgFmvMcfo9hGQHZ8mXXur/7v7+3oIy96p61ZvymN1gPzA 1VC7T3addQ+9Q== Received: from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com [IPv6:2607:f8b0:4864:20::62f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 07DEB60487 for ; Tue, 26 Jul 2022 20:25:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="gAuWm/Yv"; dkim-atps=neutral Received: by mail-pl1-x62f.google.com with SMTP id x7so169046pll.7 for ; Tue, 26 Jul 2022 11:25:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Q9AjxhyfkzdksonddqwU0JC18QtJBL2g9AqgOm7NYi4=; b=gAuWm/YvG2VrCEroIkL4QXy7PTqG4kFrTaE3WoV5y+076nSv3ZcvmhjVdlVBVqg01I Mn+5EUoKCNyJTO4dlk9kda6gecx5FUZZBP0T35UXf1AxJEB3jA6Gi7zjQhtol0W/CQbf +O+P2LVnz+71tuIFK8uLgfM8si1hyJFdERgFA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Q9AjxhyfkzdksonddqwU0JC18QtJBL2g9AqgOm7NYi4=; b=C9t+Ls03jeShg8x5CadzerDUDgBj9z7/RyvER05hCHhKwnfGyanKcrSas3MnGyyDG8 LBqS3i6c0DEY/+1lqr+pyMUTRCemTai9b9EEzcPKWhl64UMoHWVk7RAmvHsz/9j65OMw burBeRFpBdAJ1DHjr7u+GVKONjh0RrbJegLJDzO88K9DXUBJGDniAgdaQxWqt/rJXqpE bXGJPr6jD8LYz+R5bqGzMivDeYeA7l2AJCokBcGyrPuBnvpo5rzRo591z7D6tcX3Ib7P xjSzau1hayapu2DuLrqJti7fG8i2Kt/lzkr+9jzjeGGGPBIZYCX0aesYHWk50V08Crfd je1Q== X-Gm-Message-State: AJIora/PnU9UFnIZyjRcSplltRZCpfqRfWSHAXafeZKqLVZJNk7ANOVI BrQVMIGTOYvVa5cMtm3C1tFqszJ6XokeYw== X-Google-Smtp-Source: AGRyM1v6uXAmT/3AgvKSdiR+/UtTUev3Sjvn1spiqjDEFk/w0I/0cvlWR0sRvnJdyGqhBnmy/ffSQg== X-Received: by 2002:a17:903:124f:b0:16b:8167:e34e with SMTP id u15-20020a170903124f00b0016b8167e34emr18140779plh.52.1658859937591; Tue, 26 Jul 2022 11:25:37 -0700 (PDT) Received: from localhost ([2401:fa00:1:17:739:6574:4032:5911]) by smtp.gmail.com with UTF8SMTPSA id e25-20020aa79819000000b0052aaff953aesm11923558pfl.115.2022.07.26.11.25.36 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 26 Jul 2022 11:25:37 -0700 (PDT) To: libcamera-devel@lists.libcamera.org Date: Wed, 27 Jul 2022 02:25:00 +0800 Message-Id: <20220726182500.425182-7-hanlinchen@chromium.org> X-Mailer: git-send-email 2.37.1.359.gd136c6c3e2-goog In-Reply-To: <20220726182500.425182-1-hanlinchen@chromium.org> References: <20220726182500.425182-1-hanlinchen@chromium.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 6/6] android: Implement partial result feature based on partialResultCompleted signal X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Han-Lin Chen via libcamera-devel From: Hanlin Chen Reply-To: Han-Lin Chen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" To impelement partial result feature. The patch includes the following: 1. Set Camera::RequestCompletionMode to Immediately. 2. Return partial results on Camera::partialResultCompleted signal, and recycle requests on Camera::requestCompleted. 3. Refactory usage of pendingStreamsToProcess_ and starts post-processing on partial result receved. Signed-off-by: Han-Lin Chen --- src/android/camera_capabilities.cpp | 2 +- src/android/camera_capabilities.h | 2 + src/android/camera_device.cpp | 687 ++++++++++++++--------- src/android/camera_device.h | 23 +- src/android/camera_request.cpp | 50 +- src/android/camera_request.h | 46 +- src/android/jpeg/post_processor_jpeg.cpp | 2 +- 7 files changed, 522 insertions(+), 290 deletions(-) diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp index 64bd8dde..6ed040d0 100644 --- a/src/android/camera_capabilities.cpp +++ b/src/android/camera_capabilities.cpp @@ -1374,7 +1374,7 @@ int CameraCapabilities::initializeStaticMetadata() staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType); /* Request static metadata. */ - int32_t partialResultCount = 1; + int32_t partialResultCount = MaxMetadataPackIndex; staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, partialResultCount); diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h index 6f66f221..b8fc20f1 100644 --- a/src/android/camera_capabilities.h +++ b/src/android/camera_capabilities.h @@ -23,6 +23,8 @@ class CameraCapabilities { public: + static constexpr int32_t MaxMetadataPackIndex = 64; + CameraCapabilities() = default; int initialize(std::shared_ptr camera, diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index a14d5de9..6d79fd34 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -24,9 +24,8 @@ #include #include -#include "system/graphics.h" - #include "camera_buffer.h" +#include "camera_capabilities.h" #include "camera_hal_config.h" #include "camera_ops.h" #include "camera_request.h" @@ -249,7 +248,11 @@ CameraDevice::CameraDevice(unsigned int id, std::shared_ptr camera) : id_(id), state_(State::Stopped), camera_(std::move(camera)), facing_(CAMERA_FACING_FRONT), orientation_(0) { + /* Set RequestCompletionMode to Immediately to send result early */ + camera_->setRequestCompletionMode(Camera::Immediately); + camera_->requestCompleted.connect(this, &CameraDevice::requestComplete); + camera_->partialResultCompleted.connect(this, &CameraDevice::partialResultComplete); maker_ = "libcamera"; model_ = "cameraModel"; @@ -439,7 +442,7 @@ void CameraDevice::stop() { MutexLocker descriptorsLock(descriptorsMutex_); - descriptors_ = {}; + descriptors_.clear(); } streams_.clear(); @@ -855,14 +858,30 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) return 0; } -void CameraDevice::abortRequest(Camera3RequestDescriptor *descriptor) const +void CameraDevice::abortRequest(Camera3RequestDescriptor *descriptor) { - notifyError(descriptor->frameNumber_, nullptr, CAMERA3_MSG_ERROR_REQUEST); + Camera3ResultDescriptor *result = new Camera3ResultDescriptor(descriptor); - for (auto &buffer : descriptor->buffers_) - buffer.status = StreamBuffer::Status::Error; + for (auto &buffer : descriptor->buffers_) { + setBufferStatus(buffer, StreamBuffer::Status::Error); + result->buffers_.emplace_back(&buffer); + } - descriptor->status_ = Camera3RequestDescriptor::Status::Error; + { + MutexLocker lock(descriptor->resultsMutex_); + descriptor->status_ = Camera3RequestDescriptor::Status::Flushed; + descriptor->results_.emplace_back(result); + } + + /* + * After CAMERA3_MSG_ERROR_REQUEST is notified, for a given frame, + * only process_capture_results with buffers in + * CAMERA3_BUFFER_STATUS_ERROR are allowed. No further notifys or + * process_capture_result with non-null metadata is allowed. + */ + notifyError(descriptor->frameNumber_, nullptr, CAMERA3_MSG_ERROR_REQUEST); + + completeResultDescriptor(result); } bool CameraDevice::isValidRequest(camera3_capture_request_t *camera3Request) const @@ -962,9 +981,9 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques * to a libcamera stream. Streams of type Mapped will be handled later. * * Collect the CameraStream associated to each requested capture stream. - * Since requestedStreams is an std:set<>, no duplications can happen. + * Since requestedStreams is an std:map<>, no duplications can happen. */ - std::set requestedStreams; + std::map requestedStreams; for (const auto &[i, buffer] : utils::enumerate(descriptor->buffers_)) { CameraStream *cameraStream = buffer.stream; camera3_stream_t *camera3Stream = cameraStream->camera3Stream(); @@ -983,8 +1002,6 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques FrameBuffer *frameBuffer = nullptr; UniqueFD acquireFence; - MutexLocker lock(descriptor->streamsProcessMutex_); - switch (cameraStream->type()) { case CameraStream::Type::Mapped: /* Mapped streams will be handled in the next loop. */ @@ -1016,10 +1033,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques */ frameBuffer = cameraStream->getBuffer(); buffer.internalBuffer = frameBuffer; + buffer.srcBuffer = frameBuffer; LOG(HAL, Debug) << ss.str() << " (internal)"; - - descriptor->pendingStreamsToProcess_.insert( - { cameraStream, &buffer }); break; } @@ -1032,7 +1047,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques descriptor->request_->addBuffer(cameraStream->stream(), frameBuffer, std::move(fence)); - requestedStreams.insert(cameraStream); + requestedStreams[cameraStream] = frameBuffer; } /* @@ -1054,29 +1069,38 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques << cameraStream->configuration().pixelFormat << "]" << " (mapped)"; - MutexLocker lock(descriptor->streamsProcessMutex_); - descriptor->pendingStreamsToProcess_.insert({ cameraStream, &buffer }); - /* * Make sure the CameraStream this stream is mapped on has been * added to the request. */ CameraStream *sourceStream = cameraStream->sourceStream(); + ASSERT(sourceStream); - if (requestedStreams.find(sourceStream) != requestedStreams.end()) + ASSERT(sourceStream->type() == CameraStream::Type::Direct); + + /* + * If the buffer for the source stream is requested, use its + * framebuffer as the source buffer for post-processing. + */ + auto iter = requestedStreams.find(sourceStream); + if (iter != requestedStreams.end()) { + buffer.srcBuffer = iter->second; continue; + } /* - * If that's not the case, we need to add a buffer to the request - * for this stream. + * If that's not the case, we need to add an internal buffer + * to the request for this stream. + * + * \todo Handle the case that multiple mapped streams need to + * create one internal buffer for the same source stream. */ - FrameBuffer *frameBuffer = cameraStream->getBuffer(); + FrameBuffer *frameBuffer = sourceStream->getBuffer(); buffer.internalBuffer = frameBuffer; + buffer.srcBuffer = frameBuffer; descriptor->request_->addBuffer(sourceStream->stream(), frameBuffer, nullptr); - - requestedStreams.erase(sourceStream); } /* @@ -1098,11 +1122,9 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques Camera3RequestDescriptor *rawDescriptor = descriptor.get(); { MutexLocker descriptorsLock(descriptorsMutex_); - descriptors_.push(std::move(descriptor)); + descriptors_.push_back(std::move(descriptor)); } abortRequest(rawDescriptor); - completeDescriptor(rawDescriptor); - return 0; } @@ -1120,7 +1142,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques { MutexLocker descriptorsLock(descriptorsMutex_); - descriptors_.push(std::move(descriptor)); + descriptors_.push_back(std::move(descriptor)); } camera_->queueRequest(request); @@ -1128,131 +1150,238 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques return 0; } -void CameraDevice::requestComplete(Request *request) +void CameraDevice::partialResultComplete(Request *request, Result *result) { Camera3RequestDescriptor *descriptor = reinterpret_cast(request->cookie()); - /* - * Prepare the capture result for the Android camera stack. - * - * The buffer status is set to Success and later changed to Error if - * post-processing/compression fails. - */ - for (auto &buffer : descriptor->buffers_) { - CameraStream *stream = buffer.stream; + if (result->buffers().empty() && result->metadata().empty()) + LOG(HAL, Fatal) + << "Partial result should have at least buffer or metadata " + << descriptor->frameNumber_; + Camera3ResultDescriptor *camera3Result = new Camera3ResultDescriptor(descriptor); + + const ControlList &metadata = result->metadata(); + if (!metadata.empty()) { /* - * Streams of type Direct have been queued to the - * libcamera::Camera and their acquire fences have - * already been waited on by the library. - * - * Acquire fences of streams of type Internal and Mapped - * will be handled during post-processing. + * Notify shutter as soon as we have received SensorTimestamp. */ - if (stream->type() == CameraStream::Type::Direct) { - /* If handling of the fence has failed restore buffer.fence. */ - std::unique_ptr fence = buffer.frameBuffer->releaseFence(); - if (fence) - buffer.fence = fence->release(); + + const auto ×tamp = metadata.get(controls::SensorTimestamp); + if (timestamp) { + notifyShutter(descriptor->frameNumber_, *timestamp); + LOG(HAL, Debug) << "Request " << request->cookie() << " notifies shutter"; } - buffer.status = StreamBuffer::Status::Success; + + camera3Result->resultMetadata_ = getDynamicResultMetadata(metadata); } - /* - * If the Request has failed, abort the request by notifying the error - * and complete the request with all buffers in error state. - */ - if (request->status() != Request::RequestComplete) { - LOG(HAL, Error) << "Request " << request->cookie() - << " not successfully completed: " - << request->status(); + MutexLocker locker(camera3Result->streamsProcessMutex_); - abortRequest(descriptor); - completeDescriptor(descriptor); + for (auto &buffer : descriptor->buffers_) { + CameraStream *cameraStream = buffer.stream; + for (auto *frameBuffer : result->buffers()) { + if (buffer.srcBuffer != frameBuffer && + buffer.frameBuffer.get() != frameBuffer) + continue; - return; + buffer.result = camera3Result; + camera3Result->buffers_.emplace_back(&buffer); + + StreamBuffer::Status status = StreamBuffer::Status::Success; + if (frameBuffer->metadata().status != FrameMetadata::FrameSuccess) { + status = StreamBuffer::Status::Error; + } + setBufferStatus(buffer, status); + + switch (cameraStream->type()) { + case CameraStream::Type::Direct: { + ASSERT(buffer.frameBuffer.get() == frameBuffer); + /* + * Streams of type Direct have been queued to the + * libcamera::Camera and their acquire fences have + * already been waited on by the library. + */ + std::unique_ptr fence = buffer.frameBuffer->releaseFence(); + if (fence) + buffer.fence = fence->release(); + break; + } + case CameraStream::Type::Mapped: + case CameraStream::Type::Internal: + ASSERT(buffer.srcBuffer == frameBuffer); + if (status == StreamBuffer::Status::Error) { + /* + * If the framebuffer is internal to CameraStream return + * it back now that we're done processing it. + */ + if (buffer.internalBuffer) + returnInternalBuffer(buffer); + break; + } + + /* + * Acquire fences of streams of type Internal and Mapped + * will be handled during post-processing. + */ + buffer.srcBuffer = frameBuffer; + camera3Result->pendingBuffersToProcess_.emplace_back(&buffer); + + if (cameraStream->isJpegStream()) { + generateJpegExifMetadata(descriptor, &buffer); + + /* + * Allocate for post-processor to fill + * in JPEG related metadata. + */ + if (!camera3Result->resultMetadata_) + camera3Result->resultMetadata_ = getDynamicResultMetadata(metadata); + } + break; + } + } + } + + { + /* + * Adding result to the request before sending it to the + * post-processing threads, so the streamProcessingComplete() + * slot can safely call compeleteResult(). + */ + MutexLocker lock(descriptor->resultsMutex_); + descriptor->results_.emplace_back(camera3Result); } /* - * Notify shutter as soon as we have verified we have a valid request. - * - * \todo The shutter event notification should be sent to the framework - * as soon as possible, earlier than request completion time. + * Queue all the post-processing streams request at once. The completion + * slot streamProcessingComplete() can only execute when we are out + * this critical section (result->streamsProcessMutex_). This helps to + * handle synchronous errors here itself. */ - uint64_t sensorTimestamp = static_cast(request->metadata() - .get(controls::SensorTimestamp) - .value_or(0)); - notifyShutter(descriptor->frameNumber_, sensorTimestamp); + for (auto *buffer : camera3Result->pendingBuffersToProcess_) { + int ret = buffer->stream->process(buffer); + if (ret) { + setBufferStatus(*buffer, StreamBuffer::Status::Error); + + /* + * If the framebuffer is internal to CameraStream return + * it back now that we're done processing it. + */ + if (buffer->internalBuffer) + buffer->stream->putBuffer(buffer->internalBuffer); - LOG(HAL, Debug) << "Request " << request->cookie() << " completed with " - << descriptor->request_->buffers().size() << " streams"; + LOG(HAL, Error) << "Failed to run post process of request " << descriptor->frameNumber_; + } + } + + if (!camera3Result->pendingBuffersToProcess_.empty()) + return; + + locker.unlock(); + completeResultDescriptor(camera3Result); +} + +void CameraDevice::requestComplete(Request *request) +{ + Camera3RequestDescriptor *camera3Request = + reinterpret_cast(request->cookie()); /* - * Generate the metadata associated with the captured buffers. + * On Android, each new partial result with a metadata must set a + * field (partial_result) to a distinct inclusive value between + * 1 and ANDROID_REQUEST_PARTIAL_RESULT_COUNT and the final result with + * metadata has to set the field as ANDROID_REQUEST_PARTIAL_RESULT_COUNT. + * + * An empty metadata with ANDROID_REQUEST_PARTIAL_RESULT_COUNT is not + * allowed. Add a result with a fixed metadata on requestComplete() + * in case all of previous metadata are sent early, and no more metadata + * can be sent as the final with ANDROID_REQUEST_PARTIAL_RESULT_COUNT. * - * Notify if the metadata generation has failed, but continue processing - * buffers and return an empty metadata pack. + * See comments in completeResultDescriptor(). */ - descriptor->resultMetadata_ = getResultMetadata(*descriptor); - if (!descriptor->resultMetadata_) { - notifyError(descriptor->frameNumber_, nullptr, CAMERA3_MSG_ERROR_RESULT); + Camera3ResultDescriptor *result = new Camera3ResultDescriptor(camera3Request); + result->resultMetadata_ = getFixedResultMetadata(camera3Request->settings_); - /* - * The camera framework expects an empty metadata pack on error. - * - * \todo Check that the post-processor code handles this situation - * correctly. - */ - descriptor->resultMetadata_ = std::make_unique(0, 0); + { + MutexLocker lock(camera3Request->resultsMutex_); + + switch (request->status()) { + case Request::RequestComplete: + camera3Request->status_ = Camera3RequestDescriptor::Status::Success; + break; + case Request::RequestCancelled: + camera3Request->status_ = Camera3RequestDescriptor::Status::Cancelled; + break; + case Request::RequestPending: + LOG(HAL, Fatal) << "Try to complete an unfinished request"; + break; + } + + camera3Request->results_.emplace_back(result); } - /* Handle post-processing. */ - MutexLocker locker(descriptor->streamsProcessMutex_); + completeResultDescriptor(result); + return; +} + +void CameraDevice::completeResultDescriptor(Camera3ResultDescriptor *result) +{ + Camera3RequestDescriptor *request = result->request_; + result->complete_ = true; + + MutexLocker lock(request->resultsMutex_); + + bool requestCompleted = (request->status_ != Camera3RequestDescriptor::Status::Pending); + bool requestCancelled = (request->status_ == Camera3RequestDescriptor::Status::Cancelled); + + bool hasPendingMetadata = false; + bool hasPendingResult = false; + + for (auto &r : request->results_) { + if (!r->complete_) { + hasPendingResult = true; + if (r->resultMetadata_) + hasPendingMetadata = true; + } + } /* - * Queue all the post-processing streams request at once. The completion - * slot streamProcessingComplete() can only execute when we are out - * this critical section. This helps to handle synchronous errors here - * itself. + * Android requires value of metadataPackIndex follows the rules: + * + * Set to 0: Result contains no metadata (buffers only). + * Set between 1 and (MaxMetadataPackIndex - 1): Result contains metadata. + * Set to MaxMetadataPackIndex: The final result having metadata. */ - auto iter = descriptor->pendingStreamsToProcess_.begin(); - while (iter != descriptor->pendingStreamsToProcess_.end()) { - CameraStream *stream = iter->first; - StreamBuffer *buffer = iter->second; + uint32_t &metadataPackIndex = result->metadataPackIndex_ = 0; + if (result->resultMetadata_) { + metadataPackIndex = request->nextPartialResultIndex_++; - if (stream->isJpegStream()) { - generateJpegExifMetadata(descriptor, buffer); + if (requestCompleted && !hasPendingMetadata) { + metadataPackIndex = CameraCapabilities::MaxMetadataPackIndex; } - - FrameBuffer *src = request->findBuffer(stream->stream()); - if (!src) { - LOG(HAL, Error) << "Failed to find a source stream buffer"; - setBufferStatus(*buffer, StreamBuffer::Status::Error); - iter = descriptor->pendingStreamsToProcess_.erase(iter); - continue; + if (metadataPackIndex > CameraCapabilities::MaxMetadataPackIndex) { + LOG(HAL, Fatal) << "Partial result exceed limited count " + << CameraCapabilities::MaxMetadataPackIndex; } + } - buffer->srcBuffer = src; + lock.unlock(); - ++iter; - int ret = stream->process(buffer); - if (ret) { - setBufferStatus(*buffer, StreamBuffer::Status::Error); - descriptor->pendingStreamsToProcess_.erase(stream); + sendCaptureResult(result); - /* - * If the framebuffer is internal to CameraStream return - * it back now that we're done processing it. - */ - if (buffer->internalBuffer) - stream->putBuffer(buffer->internalBuffer); - } + /* + * Call notify with CAMERA3_MSG_ERROR_RESULT to indicate some of the + * expected result metadata might not be available for the capture. Only + * calls when all pending metadata are sent, since Android ignores + * the following metadata after the notice. + */ + if (requestCancelled && !hasPendingMetadata) { + notifyError(request->frameNumber_, nullptr, CAMERA3_MSG_ERROR_RESULT); } - if (descriptor->pendingStreamsToProcess_.empty()) { - locker.unlock(); - completeDescriptor(descriptor); + if (requestCompleted && !hasPendingResult) { + completeRequestDescriptor(request); } } @@ -1260,91 +1389,99 @@ void CameraDevice::requestComplete(Request *request) * \brief Complete the Camera3RequestDescriptor * \param[in] descriptor The Camera3RequestDescriptor that has completed * - * The function marks the Camera3RequestDescriptor as 'complete'. It shall be - * called when all the streams in the Camera3RequestDescriptor have completed - * capture (or have been generated via post-processing) and the request is ready - * to be sent back to the framework. + * The function shall be called when all the buffers and metadata in the + * Camera3RequestDescriptor have completed (or have been generated via + * post-processing) and all results are sent back to the framework. * * \context This function is \threadsafe. */ -void CameraDevice::completeDescriptor(Camera3RequestDescriptor *descriptor) +void CameraDevice::completeRequestDescriptor(Camera3RequestDescriptor *descriptor) { MutexLocker lock(descriptorsMutex_); - descriptor->complete_ = true; - sendCaptureResults(); + auto iter = find_if(descriptors_.begin(), descriptors_.end(), + [&descriptor](auto &item) { + return item.get() == descriptor; + }); + + if (iter == descriptors_.end()) { + LOG(HAL, Error) << "Complete an unrecognized request"; + return; + } + + descriptors_.erase(iter); } -/** - * \brief Sequentially send capture results to the framework - * - * Iterate over the descriptors queue to send completed descriptors back to the - * framework, in the same order as they have been queued. For each complete - * descriptor, populate a locally-scoped camera3_capture_result_t from the - * descriptor, send the capture result back by calling the - * process_capture_result() callback, and remove the descriptor from the queue. - * Stop iterating if the descriptor at the front of the queue is not complete. - * - * This function should never be called directly in the codebase. Use - * completeDescriptor() instead. - */ -void CameraDevice::sendCaptureResults() +void CameraDevice::setBufferStatus(StreamBuffer &streamBuffer, + StreamBuffer::Status status) const { - while (!descriptors_.empty() && !descriptors_.front()->isPending()) { - auto descriptor = std::move(descriptors_.front()); - descriptors_.pop(); + streamBuffer.status = status; + if (status != StreamBuffer::Status::Success) { + notifyError(streamBuffer.request->frameNumber_, + streamBuffer.stream->camera3Stream(), + CAMERA3_MSG_ERROR_BUFFER); + } +} - camera3_capture_result_t captureResult = {}; +void CameraDevice::returnInternalBuffer(StreamBuffer &streamBuffer) const +{ + if (!streamBuffer.internalBuffer) { + return; + } - captureResult.frame_number = descriptor->frameNumber_; + CameraStream *stream = streamBuffer.stream; + switch (stream->type()) { + case CameraStream::Type::Internal: + stream->putBuffer(streamBuffer.internalBuffer); + break; + case CameraStream::Type::Mapped: + /* + * The internal buffer of a mapped stream is allocated from + * its source stream + */ + stream->sourceStream()->putBuffer(streamBuffer.internalBuffer); + break; + case CameraStream::Type::Direct: + LOG(HAL, Fatal) << "Direct stream buffer has internal buffer"; + break; + } +} - if (descriptor->resultMetadata_) - captureResult.result = - descriptor->resultMetadata_->getMetadata(); +void CameraDevice::sendCaptureResult(Camera3ResultDescriptor *result) const +{ + camera3_capture_result_t captureResult = {}; - std::vector resultBuffers; - resultBuffers.reserve(descriptor->buffers_.size()); + captureResult.frame_number = result->request_->frameNumber_; - for (auto &buffer : descriptor->buffers_) { - camera3_buffer_status status = CAMERA3_BUFFER_STATUS_ERROR; + std::vector resultBuffers; + resultBuffers.reserve(result->buffers_.size()); - if (buffer.status == StreamBuffer::Status::Success) - status = CAMERA3_BUFFER_STATUS_OK; + for (auto &buffer : result->buffers_) { + camera3_buffer_status status = CAMERA3_BUFFER_STATUS_ERROR; - /* - * Pass the buffer fence back to the camera framework as - * a release fence. This instructs the framework to wait - * on the acquire fence in case we haven't done so - * ourselves for any reason. - */ - resultBuffers.push_back({ buffer.stream->camera3Stream(), - buffer.camera3Buffer, status, - -1, buffer.fence.release() }); - } + if (buffer->status == StreamBuffer::Status::Success) + status = CAMERA3_BUFFER_STATUS_OK; - captureResult.num_output_buffers = resultBuffers.size(); - captureResult.output_buffers = resultBuffers.data(); + /* + * Pass the buffer fence back to the camera framework as + * a release fence. This instructs the framework to wait + * on the acquire fence in case we haven't done so + * ourselves for any reason. + */ + resultBuffers.push_back({ buffer->stream->camera3Stream(), + buffer->camera3Buffer, status, + -1, buffer->fence.release() }); + } - if (descriptor->status_ == Camera3RequestDescriptor::Status::Success) - captureResult.partial_result = 1; + captureResult.num_output_buffers = resultBuffers.size(); + captureResult.output_buffers = resultBuffers.data(); - callbacks_->process_capture_result(callbacks_, &captureResult); - } -} + if (result->resultMetadata_) + captureResult.result = result->resultMetadata_->getMetadata(); -void CameraDevice::setBufferStatus(StreamBuffer &streamBuffer, - StreamBuffer::Status status) -{ - streamBuffer.status = status; - if (status != StreamBuffer::Status::Success) { - notifyError(streamBuffer.request->frameNumber_, - streamBuffer.stream->camera3Stream(), - CAMERA3_MSG_ERROR_BUFFER); + captureResult.partial_result = result->metadataPackIndex_; - /* Also set error status on entire request descriptor. */ - streamBuffer.request->status_ = - Camera3RequestDescriptor::Status::Error; - } + callbacks_->process_capture_result(callbacks_, &captureResult); } /** @@ -1354,11 +1491,11 @@ void CameraDevice::setBufferStatus(StreamBuffer &streamBuffer, * * This function is called from the post-processor's thread whenever a camera * stream has finished post processing. The corresponding entry is dropped from - * the descriptor's pendingStreamsToProcess_ map. + * the result's pendingBufferToProcess_ list. * - * If the pendingStreamsToProcess_ map is then empty, all streams requiring to - * be generated from post-processing have been completed. Mark the descriptor as - * complete using completeDescriptor() in that case. + * If the pendingBufferToProcess_ list is then empty, all streams requiring to + * be generated from post-processing have been completed. Mark the result as + * complete using completeResultDescriptor() in that case. */ void CameraDevice::streamProcessingComplete(StreamBuffer *streamBuffer, StreamBuffer::Status status) @@ -1370,19 +1507,18 @@ void CameraDevice::streamProcessingComplete(StreamBuffer *streamBuffer, * that we're done processing it. */ if (streamBuffer->internalBuffer) - streamBuffer->stream->putBuffer(streamBuffer->internalBuffer); - - Camera3RequestDescriptor *request = streamBuffer->request; + returnInternalBuffer(*streamBuffer); + Camera3ResultDescriptor *result = streamBuffer->result; { - MutexLocker locker(request->streamsProcessMutex_); + MutexLocker locker(result->streamsProcessMutex_); + result->pendingBuffersToProcess_.remove(streamBuffer); - request->pendingStreamsToProcess_.erase(streamBuffer->stream); - if (!request->pendingStreamsToProcess_.empty()) + if (!result->pendingBuffersToProcess_.empty()) return; } - completeDescriptor(streamBuffer->request); + completeResultDescriptor(streamBuffer->result); } std::string CameraDevice::logPrefix() const @@ -1414,6 +1550,99 @@ void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream, callbacks_->notify(callbacks_, ¬ify); } +std::unique_ptr +CameraDevice::getDynamicResultMetadata(const ControlList &metadata) const +{ + /* + * \todo Keep this in sync with the actual number of entries. + * + * Reserve capacity for the metadata larger than 4 bytes which cannot + * store in entries. + * Currently: 6 entries, 40 bytes extra capaticy. + * + * ANDROID_SENSOR_TIMESTAMP (int64) = 8 bytes + * ANDROID_SENSOR_EXPOSURE_TIME (int64) = 8 bytes + * ANDROID_SENSOR_FRAME_DURATION (int64) = 8 bytes + * ANDROID_SCALER_CROP_REGION (int32 X 4) = 16 bytes + * Total bytes for capacity: 40 + * + * Reserve more capacity for the JPEG metadata set by the post-processor. + * Currently: 8 entries, 72 bytes extra capaticy. + * + * ANDROID_JPEG_GPS_COORDINATES (double x 3) = 24 bytes + * ANDROID_JPEG_GPS_PROCESSING_METHOD (byte x 32) = 32 bytes + * ANDROID_JPEG_GPS_TIMESTAMP (int64) = 8 bytes + * ANDROID_JPEG_SIZE (int32_t) = 4 bytes + * ANDROID_JPEG_QUALITY (byte) = 1 byte + * ANDROID_JPEG_ORIENTATION (int32_t) = 4 bytes + * ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte + * ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes + * Total bytes for JPEG metadata: 72 + * + * \todo Calculate the entries and capacity by the input ControlList. + */ + std::unique_ptr resultMetadata = + std::make_unique(14, 112); + if (!resultMetadata->isValid()) { + LOG(HAL, Error) << "Failed to allocate result metadata"; + return nullptr; + } + + /* Add metadata tags reported by libcamera. */ + const auto ×tamp = metadata.get(controls::SensorTimestamp); + if (timestamp) + resultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, *timestamp); + + const auto &pipelineDepth = metadata.get(controls::draft::PipelineDepth); + if (pipelineDepth) + resultMetadata->addEntry(ANDROID_REQUEST_PIPELINE_DEPTH, + *pipelineDepth); + + const auto &exposureTime = metadata.get(controls::ExposureTime); + if (exposureTime) + resultMetadata->addEntry(ANDROID_SENSOR_EXPOSURE_TIME, + *exposureTime * 1000ULL); + + const auto &frameDuration = metadata.get(controls::FrameDuration); + if (frameDuration) + resultMetadata->addEntry(ANDROID_SENSOR_FRAME_DURATION, + *frameDuration * 1000); + + const auto &scalerCrop = metadata.get(controls::ScalerCrop); + if (scalerCrop) { + const Rectangle &crop = *scalerCrop; + int32_t cropRect[] = { + crop.x, + crop.y, + static_cast(crop.width), + static_cast(crop.height), + }; + resultMetadata->addEntry(ANDROID_SCALER_CROP_REGION, cropRect); + } + + const auto &testPatternMode = metadata.get(controls::draft::TestPatternMode); + if (testPatternMode) + resultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, + *testPatternMode); + + /* + * Return the result metadata pack even is not valid: get() will return + * nullptr. + */ + if (!resultMetadata->isValid()) { + LOG(HAL, Error) << "Failed to construct result metadata"; + } + + if (resultMetadata->resized()) { + auto [entryCount, dataCount] = resultMetadata->usage(); + LOG(HAL, Info) + << "Result metadata resized: " << entryCount + << " entries and " << dataCount << " bytes used"; + } + + return resultMetadata; +} + /* * Set jpeg metadata used to generate EXIF in the JPEG post processing. */ @@ -1424,10 +1653,8 @@ void CameraDevice::generateJpegExifMetadata(Camera3RequestDescriptor *request, auto &jpegExifMetadata = buffer->jpegExifMetadata; jpegExifMetadata.emplace(StreamBuffer::JpegExifMetadata()); - jpegExifMetadata->sensorExposureTime = 0; - if (metadata.contains(controls::ExposureTime)) { - jpegExifMetadata->sensorExposureTime = metadata.get(controls::ExposureTime) * 1000ULL; - } + const int64_t exposureTime = metadata.get(controls::ExposureTime).value_or(0); + jpegExifMetadata->sensorExposureTime = exposureTime; /* * todo: Android Sensitivity = analog gain X digital gain only on sensor. @@ -1441,31 +1668,26 @@ void CameraDevice::generateJpegExifMetadata(Camera3RequestDescriptor *request, * Produce a set of fixed result metadata. */ std::unique_ptr -CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) const +CameraDevice::getFixedResultMetadata(const CameraMetadata &settings) const { - const ControlList &metadata = descriptor.request_->metadata(); - const CameraMetadata &settings = descriptor.settings_; camera_metadata_ro_entry_t entry; bool found; /* + * \todo Retrieve metadata from corresponding libcamera controls. * \todo Keep this in sync with the actual number of entries. - * Currently: 40 entries, 156 bytes * - * Reserve more space for the JPEG metadata set by the post-processor. - * Currently: - * ANDROID_JPEG_GPS_COORDINATES (double x 3) = 24 bytes - * ANDROID_JPEG_GPS_PROCESSING_METHOD (byte x 32) = 32 bytes - * ANDROID_JPEG_GPS_TIMESTAMP (int64) = 8 bytes - * ANDROID_JPEG_SIZE (int32_t) = 4 bytes - * ANDROID_JPEG_QUALITY (byte) = 1 byte - * ANDROID_JPEG_ORIENTATION (int32_t) = 4 bytes - * ANDROID_JPEG_THUMBNAIL_QUALITY (byte) = 1 byte - * ANDROID_JPEG_THUMBNAIL_SIZE (int32 x 2) = 8 bytes - * Total bytes for JPEG metadata: 82 + * Reserve capacity for the metadata larger than 4 bytes which cannot + * store in entries. + * Currently: 31 entries, 16 bytes + * + * ANDROID_CONTROL_AE_TARGET_FPS_RANGE (int32 X 2) = 8 bytes + * ANDROID_SENSOR_ROLLING_SHUTTER_SKEW (int64) = 8 bytes + * + * Total bytes: 16 */ std::unique_ptr resultMetadata = - std::make_unique(88, 166); + std::make_unique(31, 16); if (!resultMetadata->isValid()) { LOG(HAL, Error) << "Failed to allocate result metadata"; return nullptr; @@ -1563,9 +1785,6 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons resultMetadata->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE, value); - value32 = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF; - resultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, value32); - value = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF; resultMetadata->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, value); @@ -1587,40 +1806,6 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons resultMetadata->addEntry(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, rolling_shutter_skew); - /* Add metadata tags reported by libcamera. */ - const int64_t timestamp = metadata.get(controls::SensorTimestamp).value_or(0); - resultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, timestamp); - - const auto &pipelineDepth = metadata.get(controls::draft::PipelineDepth); - if (pipelineDepth) - resultMetadata->addEntry(ANDROID_REQUEST_PIPELINE_DEPTH, - *pipelineDepth); - - const auto &exposureTime = metadata.get(controls::ExposureTime); - if (exposureTime) - resultMetadata->addEntry(ANDROID_SENSOR_EXPOSURE_TIME, - *exposureTime * 1000ULL); - - const auto &frameDuration = metadata.get(controls::FrameDuration); - if (frameDuration) - resultMetadata->addEntry(ANDROID_SENSOR_FRAME_DURATION, - *frameDuration * 1000); - - const auto &scalerCrop = metadata.get(controls::ScalerCrop); - if (scalerCrop) { - const Rectangle &crop = *scalerCrop; - int32_t cropRect[] = { - crop.x, crop.y, static_cast(crop.width), - static_cast(crop.height), - }; - resultMetadata->addEntry(ANDROID_SCALER_CROP_REGION, cropRect); - } - - const auto &testPatternMode = metadata.get(controls::draft::TestPatternMode); - if (testPatternMode) - resultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, - *testPatternMode); - /* * Return the result metadata pack even is not valid: get() will return * nullptr. diff --git a/src/android/camera_device.h b/src/android/camera_device.h index 7b279895..0c4237a6 100644 --- a/src/android/camera_device.h +++ b/src/android/camera_device.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include "camera_capabilities.h" #include "camera_metadata.h" #include "camera_stream.h" -#include "jpeg/encoder.h" class Camera3RequestDescriptor; struct CameraConfigData; @@ -63,6 +63,8 @@ public: const camera_metadata_t *constructDefaultRequestSettings(int type); int configureStreams(camera3_stream_configuration_t *stream_list); int processCaptureRequest(camera3_capture_request_t *request); + void partialResultComplete(libcamera::Request *request, + libcamera::Result *result); void requestComplete(libcamera::Request *request); void streamProcessingComplete(StreamBuffer *bufferStream, StreamBuffer::Status status); @@ -87,20 +89,25 @@ private: createFrameBuffer(const buffer_handle_t camera3buffer, libcamera::PixelFormat pixelFormat, const libcamera::Size &size); - void abortRequest(Camera3RequestDescriptor *descriptor) const; bool isValidRequest(camera3_capture_request_t *request) const; void notifyShutter(uint32_t frameNumber, uint64_t timestamp); void notifyError(uint32_t frameNumber, camera3_stream_t *stream, camera3_error_msg_code code) const; int processControls(Camera3RequestDescriptor *descriptor); - void completeDescriptor(Camera3RequestDescriptor *descriptor) + void abortRequest(Camera3RequestDescriptor *descriptor); + void completeResultDescriptor(Camera3ResultDescriptor *result); + void completeRequestDescriptor(Camera3RequestDescriptor *descriptor) LIBCAMERA_TSA_EXCLUDES(descriptorsMutex_); - void sendCaptureResults() LIBCAMERA_TSA_REQUIRES(descriptorsMutex_); - void setBufferStatus(StreamBuffer &buffer, StreamBuffer::Status status); + void sendCaptureResult(Camera3ResultDescriptor *partialResult) const; + void setBufferStatus(StreamBuffer &buffer, StreamBuffer::Status status) const; + void returnInternalBuffer(StreamBuffer &buffer) const; void generateJpegExifMetadata(Camera3RequestDescriptor *request, StreamBuffer *buffer) const; - std::unique_ptr getResultMetadata( - const Camera3RequestDescriptor &descriptor) const; + + std::unique_ptr getDynamicResultMetadata( + const libcamera::ControlList &metadata) const; + std::unique_ptr getFixedResultMetadata( + const CameraMetadata &settings) const; unsigned int id_; camera3_device_t camera3Device_; @@ -118,7 +125,7 @@ private: std::vector streams_; libcamera::Mutex descriptorsMutex_ LIBCAMERA_TSA_ACQUIRED_AFTER(stateMutex_); - std::queue> descriptors_ + std::list> descriptors_ LIBCAMERA_TSA_GUARDED_BY(descriptorsMutex_); std::string maker_; diff --git a/src/android/camera_request.cpp b/src/android/camera_request.cpp index f5d4d314..31751b5c 100644 --- a/src/android/camera_request.cpp +++ b/src/android/camera_request.cpp @@ -42,25 +42,25 @@ using namespace libcamera; * │ processCaptureRequest(camera3_capture_request_t request) │ * │ │ * │ - Create Camera3RequestDescriptor tracking this request │ - * │ - Streams requiring post-processing are stored in the │ - * │ pendingStreamsToProcess map │ + * │ - Buffer requiring post-processing are marked by the │ + * │ CameraStream::Type as Mapped or Internal │ * │ - Add this Camera3RequestDescriptor to descriptors' queue │ * │ CameraDevice::descriptors_ │ - * │ │ ┌─────────────────────────┐ - * │ - Queue the capture request to libcamera core ────────────┤►│libcamera core │ - * │ │ ├─────────────────────────┤ - * │ │ │- Capture from Camera │ - * │ │ │ │ - * │ │ │- Emit │ - * │ │ │ Camera::requestComplete│ - * │ requestCompleted(Request *request) ◄───────────────────────┼─┼──── │ - * │ │ │ │ - * │ - Check request completion status │ └─────────────────────────┘ + * │ │ ┌───────────────────────────────┐ + * │ - Queue the capture request to libcamera core ────────────┤►│libcamera core │ + * │ │ ├───────────────────────────────┤ + * │ │ │- Capture from Camera │ + * │ │ │ │ + * │ │ │- Emit │ + * │ │ │ Camera::partialResultComplete│ + * │ partialResultComplete(Request *request, Result result*) ◄──┼─┼──── │ + * │ │ │ │ + * │ - Check request completion status │ └───────────────────────────────┘ * │ │ - * │ - if (pendingStreamsToProcess > 0) │ - * │ Queue all entries from pendingStreamsToProcess │ + * │ - if (pendingBuffersToProcess > 0) │ + * │ Queue all entries from pendingBuffersToProcess │ * │ else │ │ - * │ completeDescriptor() │ └──────────────────────┐ + * │ completeResultDescriptor() │ └──────────────────────┐ * │ │ │ * │ ┌──────────────────────────┴───┬──────────────────┐ │ * │ │ │ │ │ @@ -93,10 +93,10 @@ using namespace libcamera; * │ | | | | │ * │ | - Check and set buffer status | | .... | │ * │ | - Remove post+processing entry | | | │ - * │ | from pendingStreamsToProcess | | | │ + * │ | from pendingBuffersToProcess | | | │ * │ | | | | │ - * │ | - if (pendingStreamsToProcess.empty())| | | │ - * │ | completeDescriptor | | | │ + * │ | - if (pendingBuffersToProcess.empty())| | | │ + * │ | completeResultDescriptor | | | │ * │ | | | | │ * │ +---------------------------------------+ +--------------+ │ * │ │ @@ -110,6 +110,7 @@ using namespace libcamera; Camera3RequestDescriptor::Camera3RequestDescriptor( Camera *camera, const camera3_capture_request_t *camera3Request) + : status_(Status::Pending), nextPartialResultIndex_(1) { frameNumber_ = camera3Request->frame_number; @@ -140,6 +141,19 @@ Camera3RequestDescriptor::Camera3RequestDescriptor( Camera3RequestDescriptor::~Camera3RequestDescriptor() = default; +/* + * \class Camera3ResultDescriptor + * + * A utility class that groups information about a capture result to be later + * sent to framework. + */ +Camera3ResultDescriptor::Camera3ResultDescriptor(Camera3RequestDescriptor *request) + : complete_(false), request_(request), metadataPackIndex_(1) +{ +} + +Camera3ResultDescriptor::~Camera3ResultDescriptor() = default; + /** * \class StreamBuffer * \brief Group information for per-stream buffer of Camera3RequestDescriptor diff --git a/src/android/camera_request.h b/src/android/camera_request.h index f91de955..b5d9e3ee 100644 --- a/src/android/camera_request.h +++ b/src/android/camera_request.h @@ -24,6 +24,7 @@ class CameraBuffer; class CameraStream; +class Camera3ResultDescriptor; class Camera3RequestDescriptor; class StreamBuffer @@ -56,41 +57,64 @@ public: const libcamera::FrameBuffer *srcBuffer = nullptr; std::unique_ptr dstBuffer; std::optional jpegExifMetadata; + Camera3ResultDescriptor *result; Camera3RequestDescriptor *request; private: LIBCAMERA_DISABLE_COPY(StreamBuffer) }; +class Camera3ResultDescriptor +{ +public: + Camera3ResultDescriptor(Camera3RequestDescriptor *request); + ~Camera3ResultDescriptor(); + + bool complete_; + Camera3RequestDescriptor *request_; + uint32_t metadataPackIndex_; + + std::unique_ptr resultMetadata_; + std::vector buffers_; + + /* Keeps track of buffers waiting for post-processing. */ + std::list pendingBuffersToProcess_ + LIBCAMERA_TSA_GUARDED_BY(streamsProcessMutex_); + libcamera::Mutex streamsProcessMutex_; + +private: + LIBCAMERA_DISABLE_COPY(Camera3ResultDescriptor) +}; + class Camera3RequestDescriptor { public: enum class Status { + Pending, Success, - Error, + Cancelled, + Flushed, }; - /* Keeps track of streams requiring post-processing. */ - std::map pendingStreamsToProcess_ - LIBCAMERA_TSA_GUARDED_BY(streamsProcessMutex_); - libcamera::Mutex streamsProcessMutex_; - Camera3RequestDescriptor(libcamera::Camera *camera, const camera3_capture_request_t *camera3Request); ~Camera3RequestDescriptor(); - bool isPending() const { return !complete_; } - uint32_t frameNumber_ = 0; std::vector buffers_; CameraMetadata settings_; std::unique_ptr request_; - std::unique_ptr resultMetadata_; - bool complete_ = false; - Status status_ = Status::Success; + std::vector> results_ + LIBCAMERA_TSA_GUARDED_BY(resultsMutex_); + + Status status_ LIBCAMERA_TSA_GUARDED_BY(resultsMutex_); + + uint32_t nextPartialResultIndex_ LIBCAMERA_TSA_GUARDED_BY(resultsMutex_); + + libcamera::Mutex resultsMutex_; private: LIBCAMERA_DISABLE_COPY(Camera3RequestDescriptor) diff --git a/src/android/jpeg/post_processor_jpeg.cpp b/src/android/jpeg/post_processor_jpeg.cpp index 91fd329c..0cb5fd9a 100644 --- a/src/android/jpeg/post_processor_jpeg.cpp +++ b/src/android/jpeg/post_processor_jpeg.cpp @@ -111,7 +111,7 @@ void PostProcessorJpeg::process(StreamBuffer *streamBuffer) ASSERT(jpegExifMetadata.has_value()); const CameraMetadata &requestMetadata = streamBuffer->request->settings_; - CameraMetadata *resultMetadata = streamBuffer->request->resultMetadata_.get(); + CameraMetadata *resultMetadata = streamBuffer->result->resultMetadata_.get(); camera_metadata_ro_entry_t entry; int ret;