From patchwork Thu Aug 5 22:24:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13240 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 8AF6FC323E for ; Thu, 5 Aug 2021 22:25:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6BBCC68823; Fri, 6 Aug 2021 00:25:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kz1g+d6s"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AF6CA68864 for ; Fri, 6 Aug 2021 00:24:58 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5891D4FB for ; Fri, 6 Aug 2021 00:24:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1628202298; bh=rk2i+0Hbv2WpzF5aFkIirl35cpNkySJgXP5j1JzuCCc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kz1g+d6sF7Y4fX5ajgjudC36ilxZQr77YphAXFBphYNDZ3UWE9M0bCCi3jXyTEkl2 F46UiV6FibG1Kbvrd8f9mC+9h9HjHww8TJb5084fIQUiconmxtjI4MfS1V6pu3+8LN o+EK95pvTrhy2oHgQKu17DxlWzvqE9jKmzHseZVE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Fri, 6 Aug 2021 01:24:35 +0300 Message-Id: <20210805222436.6263-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210805222436.6263-1-laurent.pinchart@ideasonboard.com> References: <20210805222436.6263-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/10] libcamera: pipeline: simple: Move bufferReady handler to SimpleCameraData 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" To use multiple cameras at the same time, a per-camera buffer ready handler is needed. Move the bufferReady() function connected to the V4L2VideoDevice bufferReady signal from the SimplePipelineHandler class to the SimpleCameraData class. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/simple/simple.cpp | 186 +++++++++++------------ 1 file changed, 90 insertions(+), 96 deletions(-) diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 961262b7803d..aa4542ed26b1 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -179,6 +179,7 @@ public: int setupLinks(); int setupFormats(V4L2SubdeviceFormat *format, V4L2Subdevice::Whence whence); + void bufferReady(FrameBuffer *buffer); unsigned int streamIndex(const Stream *stream) const { @@ -307,8 +308,6 @@ private: const MediaPad *acquirePipeline(SimpleCameraData *data); void releasePipeline(SimpleCameraData *data); - void bufferReady(FrameBuffer *buffer); - MediaDevice *media_; std::map entities_; @@ -621,6 +620,91 @@ int SimpleCameraData::setupFormats(V4L2SubdeviceFormat *format, return 0; } +void SimpleCameraData::bufferReady(FrameBuffer *buffer) +{ + /* + * If an error occurred during capture, or if the buffer was cancelled, + * complete the request, even if the converter is in use as there's no + * point converting an erroneous buffer. + */ + if (buffer->metadata().status != FrameMetadata::FrameSuccess) { + if (!useConverter_) { + /* No conversion, just complete the request. */ + Request *request = buffer->request(); + pipe_->completeBuffer(request, buffer); + pipe_->completeRequest(request); + return; + } + + /* + * The converter is in use. Requeue the internal buffer for + * capture (unless the stream is being stopped), and complete + * the request with all the user-facing buffers. + */ + if (buffer->metadata().status != FrameMetadata::FrameCancelled) + video_->queueBuffer(buffer); + + if (converterQueue_.empty()) + return; + + Request *request = nullptr; + for (auto &item : converterQueue_.front()) { + FrameBuffer *outputBuffer = item.second; + request = outputBuffer->request(); + pipe_->completeBuffer(request, outputBuffer); + } + converterQueue_.pop(); + + if (request) + pipe_->completeRequest(request); + return; + } + + /* + * Record the sensor's timestamp in the request metadata. The request + * needs to be obtained from the user-facing buffer, as internal + * buffers are free-wheeling and have no request associated with them. + * + * \todo The sensor timestamp should be better estimated by connecting + * to the V4L2Device::frameStart signal if the platform provides it. + */ + Request *request = buffer->request(); + + if (useConverter_ && !converterQueue_.empty()) { + const std::map &outputs = + converterQueue_.front(); + if (!outputs.empty()) { + FrameBuffer *outputBuffer = outputs.begin()->second; + if (outputBuffer) + request = outputBuffer->request(); + } + } + + if (request) + request->metadata().set(controls::SensorTimestamp, + buffer->metadata().timestamp); + + /* + * Queue the captured and the request buffer to the converter if format + * conversion is needed. If there's no queued request, just requeue the + * captured buffer for capture. + */ + if (useConverter_) { + if (converterQueue_.empty()) { + video_->queueBuffer(buffer); + return; + } + + converter_->queueBuffers(buffer, converterQueue_.front()); + converterQueue_.pop(); + return; + } + + /* Otherwise simply complete the request. */ + pipe_->completeBuffer(request, buffer); + pipe_->completeRequest(request); +} + void SimpleCameraData::converterInputDone(FrameBuffer *buffer) { /* Queue the input buffer back for capture. */ @@ -921,6 +1005,8 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL return ret; } + video->bufferReady.connect(data, &SimpleCameraData::bufferReady); + ret = video->streamOn(); if (ret < 0) { stop(camera); @@ -955,6 +1041,8 @@ void SimplePipelineHandler::stop(Camera *camera) video->streamOff(); video->releaseBuffers(); + video->bufferReady.disconnect(data, &SimpleCameraData::bufferReady); + data->converterBuffers_.clear(); activeCamera_ = nullptr; @@ -1135,8 +1223,6 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator) << ": " << strerror(-ret); return false; } - - video->bufferReady.connect(this, &SimplePipelineHandler::bufferReady); break; case MediaEntity::Type::V4L2Subdevice: @@ -1250,98 +1336,6 @@ void SimplePipelineHandler::releasePipeline(SimpleCameraData *data) } } -/* ----------------------------------------------------------------------------- - * Buffer Handling - */ - -void SimplePipelineHandler::bufferReady(FrameBuffer *buffer) -{ - ASSERT(activeCamera_); - SimpleCameraData *data = cameraData(activeCamera_); - - /* - * If an error occurred during capture, or if the buffer was cancelled, - * complete the request, even if the converter is in use as there's no - * point converting an erroneous buffer. - */ - if (buffer->metadata().status != FrameMetadata::FrameSuccess) { - if (!data->useConverter_) { - /* No conversion, just complete the request. */ - Request *request = buffer->request(); - completeBuffer(request, buffer); - completeRequest(request); - return; - } - - /* - * The converter is in use. Requeue the internal buffer for - * capture (unless the stream is being stopped), and complete - * the request with all the user-facing buffers. - */ - if (buffer->metadata().status != FrameMetadata::FrameCancelled) - data->video_->queueBuffer(buffer); - - if (data->converterQueue_.empty()) - return; - - Request *request = nullptr; - for (auto &item : data->converterQueue_.front()) { - FrameBuffer *outputBuffer = item.second; - request = outputBuffer->request(); - completeBuffer(request, outputBuffer); - } - data->converterQueue_.pop(); - - if (request) - completeRequest(request); - return; - } - - /* - * Record the sensor's timestamp in the request metadata. The request - * needs to be obtained from the user-facing buffer, as internal - * buffers are free-wheeling and have no request associated with them. - * - * \todo The sensor timestamp should be better estimated by connecting - * to the V4L2Device::frameStart signal if the platform provides it. - */ - Request *request = buffer->request(); - - if (data->useConverter_ && !data->converterQueue_.empty()) { - const std::map &outputs = - data->converterQueue_.front(); - if (!outputs.empty()) { - FrameBuffer *outputBuffer = outputs.begin()->second; - if (outputBuffer) - request = outputBuffer->request(); - } - } - - if (request) - request->metadata().set(controls::SensorTimestamp, - buffer->metadata().timestamp); - - /* - * Queue the captured and the request buffer to the converter if format - * conversion is needed. If there's no queued request, just requeue the - * captured buffer for capture. - */ - if (data->useConverter_) { - if (data->converterQueue_.empty()) { - data->video_->queueBuffer(buffer); - return; - } - - data->converter_->queueBuffers(buffer, data->converterQueue_.front()); - data->converterQueue_.pop(); - return; - } - - /* Otherwise simply complete the request. */ - completeBuffer(request, buffer); - completeRequest(request); -} - REGISTER_PIPELINE_HANDLER(SimplePipelineHandler) } /* namespace libcamera */