From patchwork Thu Apr 18 10:47:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1033 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9AF6E60DC6 for ; Thu, 18 Apr 2019 12:46:30 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id CB2771C0004; Thu, 18 Apr 2019 10:46:29 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:02 +0200 Message-Id: <20190418104715.22622-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 01/14] libcamera: stream: Make Stream inheritable X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:31 -0000 In preparation for multiple streams support prepare to allow sub-classing the Stream class by removing the 'final' specifier from the class definition and make its private members protected. Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- include/libcamera/stream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index d0f7b0e12485..8a47930f8614 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -43,7 +43,7 @@ private: Size size_; }; -class Stream final +class Stream { public: class StillCapture : public StreamUsage @@ -68,7 +68,7 @@ public: BufferPool &bufferPool() { return bufferPool_; } const StreamConfiguration &configuration() const { return configuration_; } -private: +protected: friend class Camera; BufferPool bufferPool_; From patchwork Thu Apr 18 10:47:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1034 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9EBE760DC6 for ; Thu, 18 Apr 2019 12:46:31 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C5B2A1C0007; Thu, 18 Apr 2019 10:46:30 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:03 +0200 Message-Id: <20190418104715.22622-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 02/14] libcamera: camera: Pass the stream set to allocate/freeBuffers() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:31 -0000 Pipeline handlers might need to perform allocation of internal buffers, setup operations, or simple sanity check before going into the per-stream buffer allocation. As of now, PipelineHandler::allocateBuffers() is called once for each active stream, leaving no space for stream-independent configuration. Change this by providing to the pipeline handlers the full set of active streams, and ask them to loop over them to perform per-streams memory allocations and freeing. Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 15 ++++++--------- src/libcamera/include/pipeline_handler.h | 6 ++++-- src/libcamera/pipeline/ipu3/ipu3.cpp | 13 +++++++++---- src/libcamera/pipeline/uvcvideo.cpp | 13 +++++++++---- src/libcamera/pipeline/vimc.cpp | 13 +++++++++---- src/libcamera/pipeline_handler.cpp | 11 ++++++----- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index bdf14b31d8ee..21caa24b90b5 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -647,13 +647,11 @@ int Camera::allocateBuffers() return -EINVAL; } - for (Stream *stream : activeStreams_) { - int ret = pipe_->allocateBuffers(this, stream); - if (ret) { - LOG(Camera, Error) << "Failed to allocate buffers"; - freeBuffers(); - return ret; - } + int ret = pipe_->allocateBuffers(this, activeStreams_); + if (ret) { + LOG(Camera, Error) << "Failed to allocate buffers"; + freeBuffers(); + return ret; } state_ = CameraPrepared; @@ -683,12 +681,11 @@ int Camera::freeBuffers() * by the V4L2 device that has allocated them. */ stream->bufferPool().destroyBuffers(); - pipe_->freeBuffers(this, stream); } state_ = CameraConfigured; - return 0; + return pipe_->freeBuffers(this, activeStreams_); } /** diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index 33b820e706cc..a0862ebf35df 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -58,8 +58,10 @@ public: streamConfiguration(Camera *camera, const std::vector &usages) = 0; virtual int configureStreams(Camera *camera, const CameraConfiguration &config) = 0; - virtual int allocateBuffers(Camera *camera, Stream *stream) = 0; - virtual int freeBuffers(Camera *camera, Stream *stream) = 0; + virtual int allocateBuffers(Camera *camera, + const std::set &streams) = 0; + virtual int freeBuffers(Camera *camera, + const std::set &streams) = 0; virtual int start(Camera *camera) = 0; virtual void stop(Camera *camera); diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ca09da753b90..f96e8763bce9 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -145,8 +145,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -305,9 +307,11 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return 0; } -int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerIPU3::allocateBuffers(Camera *camera, + const std::set &streams) { IPU3CameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; int ret; @@ -346,7 +350,8 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream) return 0; } -int PipelineHandlerIPU3::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerIPU3::freeBuffers(Camera *camera, + const std::set &streams) { IPU3CameraData *data = cameraData(camera); diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index cd472cfadd86..b8f634d88b46 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -32,8 +32,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -127,9 +129,11 @@ int PipelineHandlerUVC::configureStreams(Camera *camera, return 0; } -int PipelineHandlerUVC::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerUVC::allocateBuffers(Camera *camera, + const std::set &streams) { UVCCameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); LOG(UVC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; @@ -137,7 +141,8 @@ int PipelineHandlerUVC::allocateBuffers(Camera *camera, Stream *stream) return data->video_->exportBuffers(&stream->bufferPool()); } -int PipelineHandlerUVC::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerUVC::freeBuffers(Camera *camera, + const std::set &streams) { UVCCameraData *data = cameraData(camera); return data->video_->releaseBuffers(); diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index c8bbe2a19847..22449e47bc2d 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -32,8 +32,10 @@ public: int configureStreams(Camera *camera, const CameraConfiguration &config) override; - int allocateBuffers(Camera *camera, Stream *stream) override; - int freeBuffers(Camera *camera, Stream *stream) override; + int allocateBuffers(Camera *camera, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) override; int start(Camera *camera) override; void stop(Camera *camera) override; @@ -127,9 +129,11 @@ int PipelineHandlerVimc::configureStreams(Camera *camera, return 0; } -int PipelineHandlerVimc::allocateBuffers(Camera *camera, Stream *stream) +int PipelineHandlerVimc::allocateBuffers(Camera *camera, + const std::set &streams) { VimcCameraData *data = cameraData(camera); + Stream *stream = *streams.begin(); const StreamConfiguration &cfg = stream->configuration(); LOG(VIMC, Debug) << "Requesting " << cfg.bufferCount << " buffers"; @@ -137,7 +141,8 @@ int PipelineHandlerVimc::allocateBuffers(Camera *camera, Stream *stream) return data->video_->exportBuffers(&stream->bufferPool()); } -int PipelineHandlerVimc::freeBuffers(Camera *camera, Stream *stream) +int PipelineHandlerVimc::freeBuffers(Camera *camera, + const std::set &streams) { VimcCameraData *data = cameraData(camera); return data->video_->releaseBuffers(); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 43550c0e0210..911d08448e69 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -193,10 +193,11 @@ PipelineHandler::~PipelineHandler() * \fn PipelineHandler::allocateBuffers() * \brief Allocate buffers for a stream * \param[in] camera The camera the \a stream belongs to - * \param[in] stream The stream to allocate buffers for + * \param[in] streams The set of streams to allocate buffers for * - * This method allocates buffers internally in the pipeline handler and - * associates them with the stream's buffer pool. + * This method allocates buffers internally in the pipeline handler for each + * stream in the \a streams buffer set, and associates them with the stream's + * buffer pool. * * The intended caller of this method is the Camera class. * @@ -207,9 +208,9 @@ PipelineHandler::~PipelineHandler() * \fn PipelineHandler::freeBuffers() * \brief Free all buffers associated with a stream * \param[in] camera The camera the \a stream belongs to - * \param[in] stream The stream to free buffers from + * \param[in] streams The set of streams to free buffers from * - * After a capture session has been stopped all buffers associated with the + * After a capture session has been stopped all buffers associated with each * stream shall be freed. * * The intended caller of this method is the Camera class. From patchwork Thu Apr 18 10:47:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1035 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 424F960DC0 for ; Thu, 18 Apr 2019 12:46:32 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C48381C0004; Thu, 18 Apr 2019 10:46:31 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:04 +0200 Message-Id: <20190418104715.22622-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 03/14] libcamera: camera: Don't call freeBuffer() on allocateBuffer() error X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:32 -0000 Do not assume the freeBuffer() function can handle allocateBuffer() method failures, as error handling and clean up should be performed by allocateBuffer() method itself. Perform clean-up on allocations failures in the IPU3 pipeline handler, now that freeBuffers() is not called anymore. Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 1 - src/libcamera/pipeline/ipu3/ipu3.cpp | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 21caa24b90b5..2d0a80664214 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -650,7 +650,6 @@ int Camera::allocateBuffers() int ret = pipe_->allocateBuffers(this, activeStreams_); if (ret) { LOG(Camera, Error) << "Failed to allocate buffers"; - freeBuffers(); return ret; } diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index f96e8763bce9..6e093fc22259 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -314,6 +314,7 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, Stream *stream = *streams.begin(); CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; + unsigned int bufferCount; int ret; /* Share buffers between CIO2 output and ImgU input. */ @@ -323,31 +324,39 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, ret = imgu->importBuffers(pool); if (ret) - return ret; + goto error_free_cio2; /* Export ImgU output buffers to the stream's pool. */ ret = imgu->exportBuffers(&imgu->output_, &stream->bufferPool()); if (ret) - return ret; + goto error_free_imgu; /* * Reserve memory in viewfinder and stat output devices. Use the * same number of buffers as the ones requested for the output * stream. */ - unsigned int bufferCount = stream->bufferPool().count(); + bufferCount = stream->bufferPool().count(); imgu->viewfinder_.pool->createBuffers(bufferCount); ret = imgu->exportBuffers(&imgu->viewfinder_, imgu->viewfinder_.pool); if (ret) - return ret; + goto error_free_imgu; imgu->stat_.pool->createBuffers(bufferCount); ret = imgu->exportBuffers(&imgu->stat_, imgu->stat_.pool); if (ret) - return ret; + goto error_free_imgu; return 0; + +error_free_imgu: + imgu->freeBuffers(); + +error_free_cio2: + cio2->freeBuffers(); + + return ret; } int PipelineHandlerIPU3::freeBuffers(Camera *camera, From patchwork Thu Apr 18 10:47:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1036 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D2DB360DC0 for ; Thu, 18 Apr 2019 12:46:32 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 68EE01C0004; Thu, 18 Apr 2019 10:46:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:05 +0200 Message-Id: <20190418104715.22622-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 04/14] libcamera: v4l2_device: Propagate releaseBuffers() error X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:34 -0000 The error code returned by requestBuffers(0) was not propagated to the caller. Fix it. Signed-off-by: Jacopo Mondi --- src/libcamera/v4l2_device.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 4cc4a6d656b1..d394632dad4c 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -737,10 +737,9 @@ int V4L2Device::releaseBuffers() { LOG(V4L2, Debug) << "Releasing bufferPool"; - requestBuffers(0); bufferPool_ = nullptr; - return 0; + return requestBuffers(0); } /** From patchwork Thu Apr 18 10:47:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1037 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CB75460DC6 for ; Thu, 18 Apr 2019 12:46:33 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 047D91C0005; Thu, 18 Apr 2019 10:46:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:06 +0200 Message-Id: <20190418104715.22622-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 05/14] libcamera: request: Add hasPendingBuffers() method X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:34 -0000 Add method to verify if a request has pending buffers yet to be completed. Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- include/libcamera/request.h | 2 ++ src/libcamera/request.cpp | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 0dbd425115e8..0188bcab8383 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -37,6 +37,8 @@ public: Status status() const { return status_; } + bool hasPendingBuffers() const { return !pending_.empty(); } + private: friend class Camera; friend class PipelineHandler; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index e0e77e972411..e5c25d2c6988 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -106,6 +106,14 @@ Buffer *Request::findBuffer(Stream *stream) const * \return The request completion status */ +/** + * \fn Request::hasPendingBuffers() + * \brief Check if a request has buffers yet to be completed + * + * \return True if the request has buffers pending for completion, false + * otherwise + */ + /** * \brief Prepare the resources for the completion handler */ @@ -127,7 +135,7 @@ int Request::prepare() */ void Request::complete(Status status) { - ASSERT(pending_.empty()); + ASSERT(!hasPendingBuffers()); status_ = status; } @@ -149,7 +157,7 @@ bool Request::completeBuffer(Buffer *buffer) int ret = pending_.erase(buffer); ASSERT(ret == 1); - return pending_.empty(); + return !hasPendingBuffers(); } } /* namespace libcamera */ From patchwork Thu Apr 18 10:47:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1038 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6C01A60DC6 for ; Thu, 18 Apr 2019 12:46:34 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id F3E4A1C0007; Thu, 18 Apr 2019 10:46:33 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:07 +0200 Message-Id: <20190418104715.22622-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 06/14] libcamera: camera: Validate Request before queueing it X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:34 -0000 Extend the Request::prepare() operation to validate the request before preparing it. Return an error if the request is invalid, which for now is limited to ensuring that the request contains at least one buffer. Signed-off-by: Jacopo Mondi --- src/libcamera/camera.cpp | 11 ++++++++--- src/libcamera/request.cpp | 12 +++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 2d0a80664214..75a21008070b 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -713,9 +713,14 @@ Request *Camera::createRequest() * \brief Queue a request to the camera * \param[in] request The request to queue to the camera * - * This method queues a \a request allocated with createRequest() to the camera - * for capture. Once the request has been queued, the camera will notify its - * completion through the \ref requestCompleted signal. + * This method queues a \a request to the camera for capture. + * + * After allocating the request with createRequest(), the application shall + * fill it with at least one capture buffer before queuing it. Requests that + * contain no buffers are invalid and are rejected without being queued. + * + * Once the request has been queued, the camera will notify its completion + * through the \ref requestCompleted signal. * * Ownership of the request is transferred to the camera. It will be deleted * automatically after it completes. diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index e5c25d2c6988..502048683245 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -115,7 +115,12 @@ Buffer *Request::findBuffer(Stream *stream) const */ /** - * \brief Prepare the resources for the completion handler + * \brief Validate the request and prepare it for the completion handler + * + * Requests that contain no buffers are invalid and are rejected. + * + * \return 0 on success or a negative error code otherwise + * \retval -EINVAL The request is invalid */ int Request::prepare() { @@ -124,6 +129,11 @@ int Request::prepare() pending_.insert(buffer); } + if (!hasPendingBuffers()) { + LOG(Request, Error) << "Invalid request due to missing buffers"; + return -EINVAL; + } + return 0; } From patchwork Thu Apr 18 10:47:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1039 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 65BBE60DD5 for ; Thu, 18 Apr 2019 12:46:35 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 9437B1C0004; Thu, 18 Apr 2019 10:46:34 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:08 +0200 Message-Id: <20190418104715.22622-8-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 07/14] libcamera: request: Expose the Stream to Buffers map X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:36 -0000 Add to the Request class a method to access the map of Stream to Buffer. With the introduction of multiple stream support, pipeline handler should be able to access the map of streams at request queueing time. Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- include/libcamera/request.h | 1 + src/libcamera/request.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 0188bcab8383..58de6f00a554 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -32,6 +32,7 @@ public: Request(const Request &) = delete; Request &operator=(const Request &) = delete; + const std::map &buffers() const { return bufferMap_; } int setBuffers(const std::map &streamMap); Buffer *findBuffer(Stream *stream) const; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 502048683245..c429d1fb2f8a 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -51,6 +51,16 @@ Request::Request(Camera *camera) { } +/** + * \fn Request::buffers() + * \brief Retrieve the request's streams to buffers map + * + * Return a reference to the map that associates each Stream part of the + * request to the Buffer the Stream output should be directed to. + * + * \return The map of Stream to Buffer + */ + /** * \brief Set the streams to capture with associated buffers * \param[in] streamMap The map of streams to buffers From patchwork Thu Apr 18 10:47:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1040 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 055FA60DC8 for ; Thu, 18 Apr 2019 12:46:36 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 8E5D61C0007; Thu, 18 Apr 2019 10:46:35 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:09 +0200 Message-Id: <20190418104715.22622-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 08/14] libcamera: buffer: Store Request reference in Buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:37 -0000 Add to the Buffer class methods to set and retrieve a reference to the Request instance the buffer is part of. As buffers might outlive the Request they are associated with, the reference is only temporary valid during the buffer completion interval (from when the buffer gets queued to Camera for processing, until it gets marked as completed). Signed-off-by: Jacopo Mondi --- include/libcamera/buffer.h | 6 ++++++ src/libcamera/buffer.cpp | 25 ++++++++++++++++++++++++- src/libcamera/request.cpp | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index 0c844d126a27..8f9b42e39339 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -13,6 +13,7 @@ namespace libcamera { class BufferPool; +class Request; class Plane final { @@ -52,14 +53,18 @@ public: unsigned int sequence() const { return sequence_; } Status status() const { return status_; } std::vector &planes() { return planes_; } + Request *request() const { return request_; } private: friend class BufferPool; friend class PipelineHandler; + friend class Request; friend class V4L2Device; void cancel(); + void setRequest(Request *request) { request_ = request; } + unsigned int index_; unsigned int bytesused_; uint64_t timestamp_; @@ -67,6 +72,7 @@ private: Status status_; std::vector planes_; + Request *request_; }; class BufferPool final diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp index e2d1cf04411e..8261ca41d62e 100644 --- a/src/libcamera/buffer.cpp +++ b/src/libcamera/buffer.cpp @@ -196,7 +196,7 @@ void *Plane::mem() */ Buffer::Buffer() - : index_(-1) + : index_(-1), request_(nullptr) { } @@ -248,6 +248,22 @@ Buffer::Buffer() * \return The buffer status */ +/** + * \fn Buffer::request() + * \brief Retrieve the request this buffer belongs to + * + * The intended callers of this method are buffer completion handlers that + * needs to associate a buffer to the request it belongs to. + * + * A Buffer is associated to a request by Request::prepare() and the + * association is valid until the buffer completes. The returned request + * pointer is valid only during that interval. + * + * \return The Request the Buffer belongs to, or nullptr if the buffer is + * either completed or not associated with a request + * \sa Buffer::setRequest() + */ + /** * \brief Mark a buffer as cancel by setting its status to BufferCancelled */ @@ -259,6 +275,13 @@ void Buffer::cancel() status_ = BufferCancelled; } +/** + * \fn Buffer::setRequest() + * \brief Set the request this buffer belongs to + * + * The intended callers are Request::prepare() and Request::completeBuffer(). + */ + /** * \class BufferPool * \brief A pool of buffers diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index c429d1fb2f8a..855da7c245e9 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -136,6 +136,7 @@ int Request::prepare() { for (auto const &pair : bufferMap_) { Buffer *buffer = pair.second; + buffer->setRequest(this); pending_.insert(buffer); } @@ -177,6 +178,8 @@ bool Request::completeBuffer(Buffer *buffer) int ret = pending_.erase(buffer); ASSERT(ret == 1); + buffer->setRequest(nullptr); + return !hasPendingBuffers(); } From patchwork Thu Apr 18 10:47:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1041 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A685D60DCC for ; Thu, 18 Apr 2019 12:46:36 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 2D0961C0007; Thu, 18 Apr 2019 10:46:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:10 +0200 Message-Id: <20190418104715.22622-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 09/14] libcamera: ipu3: Create camera with 2 streams X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:37 -0000 Sub-class the Stream class with an IPU3-specific implementation and create each IPU3 camera with two streams: 'output' and 'viewfinder' which represents the video stream from main and secondary ImgU output respectively. Re-work stream configuration to handle the two video streams 'output' and 'viewfinder' separately. As the IPU3 driver requires viewfinder and stat video nodes to be started not to stall ImgU processing, configure 'output', 'viewfinder' and 'stat' regardless of the user-requested active streams. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 208 +++++++++++++++++++-------- 1 file changed, 145 insertions(+), 63 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 6e093fc22259..b1e289919d4e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -61,7 +61,7 @@ public: } int init(MediaDevice *media, unsigned int index); - int configureInput(const StreamConfiguration &config, + int configureInput(const Size &config, V4L2DeviceFormat *inputFormat); int configureOutput(ImgUOutput *output, const StreamConfiguration &config); @@ -111,7 +111,7 @@ public: } int init(const MediaDevice *media, unsigned int index); - int configure(const StreamConfiguration &config, + int configure(const Size &config, V4L2DeviceFormat *outputFormat); BufferPool *exportBuffers(); @@ -133,6 +133,20 @@ public: BufferPool pool_; }; +class IPU3Stream : public Stream +{ +public: + IPU3Stream() + : active_(false), device_(nullptr), cfg_(nullptr) + { + } + + bool active_; + std::string name_; + ImgUDevice::ImgUOutput *device_; + const StreamConfiguration *cfg_; +}; + class PipelineHandlerIPU3 : public PipelineHandler { public: @@ -173,7 +187,8 @@ private: CIO2Device cio2_; ImgUDevice *imgu_; - Stream stream_; + IPU3Stream outStream_; + IPU3Stream vfStream_; }; static constexpr unsigned int IPU3_BUFFER_COUNT = 4; @@ -212,7 +227,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, { CameraConfiguration configs; IPU3CameraData *data = cameraData(camera); - StreamConfiguration *config = &configs[&data->stream_]; + StreamConfiguration config = {}; /* * FIXME: Soraka: the maximum resolution reported by both sensors @@ -222,15 +237,24 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera, * * \todo Clarify ImgU alignement requirements. */ - config->width = 2560; - config->height = 1920; - config->pixelFormat = V4L2_PIX_FMT_NV12; - config->bufferCount = IPU3_BUFFER_COUNT; + config.width = 2560; + config.height = 1920; + config.pixelFormat = V4L2_PIX_FMT_NV12; + config.bufferCount = IPU3_BUFFER_COUNT; + + configs[&data->outStream_] = config; + LOG(IPU3, Debug) + << "Stream '" << data->outStream_.name_ << "' set to " + << config.width << "x" << config.height << "-0x" + << std::hex << std::setfill('0') << std::setw(8) + << config.pixelFormat; + configs[&data->vfStream_] = config; LOG(IPU3, Debug) - << "Stream format set to " << config->width << "x" - << config->height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << config->pixelFormat; + << "Stream '" << data->vfStream_.name_ << "' set to " + << config.width << "x" << config.height << "-0x" + << std::hex << std::setfill('0') << std::setw(8) + << config.pixelFormat; return configs; } @@ -239,35 +263,58 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, const CameraConfiguration &config) { IPU3CameraData *data = cameraData(camera); - const StreamConfiguration &cfg = config[&data->stream_]; + IPU3Stream *outStream = &data->outStream_; + IPU3Stream *vfStream = &data->vfStream_; CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; + Size sensorSize = {}; int ret; - LOG(IPU3, Info) - << "Requested image format " << cfg.width << "x" - << cfg.height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << cfg.pixelFormat << " on camera '" - << camera->name() << "'"; + outStream->active_ = false; + vfStream->active_ = false; + for (Stream *s : config) { + IPU3Stream *stream = static_cast(s); + const StreamConfiguration &cfg = config[stream]; - /* - * Verify that the requested size respects the IPU3 alignement - * requirements (the image width shall be a multiple of 8 pixels and - * its height a multiple of 4 pixels) and the camera maximum sizes. - * - * \todo: consider the BDS scaling factor requirements: - * "the downscaling factor must be an integer value multiple of 1/32" - */ - if (cfg.width % 8 || cfg.height % 4) { - LOG(IPU3, Error) << "Invalid stream size: bad alignment"; - return -EINVAL; - } + /* + * Verify that the requested size respects the IPU3 alignment + * requirements (the image width shall be a multiple of 8 + * pixels and its height a multiple of 4 pixels) and the camera + * maximum sizes. + * + * \todo: Consider the BDS scaling factor requirements: "the + * downscaling factor must be an integer value multiple of 1/32" + */ + if (cfg.width % 8 || cfg.height % 4) { + LOG(IPU3, Error) + << "Invalid stream size: bad alignment"; + return -EINVAL; + } - if (cfg.width > cio2->maxSize_.width || - cfg.height > cio2->maxSize_.height) { - LOG(IPU3, Error) - << "Invalid stream size: larger than sensor resolution"; - return -EINVAL; + if (cfg.width > cio2->maxSize_.width || + cfg.height > cio2->maxSize_.height) { + LOG(IPU3, Error) + << "Invalid stream size: larger than sensor resolution"; + return -EINVAL; + } + + LOG(IPU3, Info) + << "Stream '" << stream->name_ << "' " + << cfg.width << "x" << cfg.height << "-0x" + << std::hex << std::setw(8) << cfg.pixelFormat + << " on camera'" << camera->name() << "'"; + + /* + * Collect the maximum width and height: IPU3 can downscale + * only. + */ + if (cfg.width > sensorSize.width) + sensorSize.width = cfg.width; + if (cfg.height > sensorSize.height) + sensorSize.height = cfg.height; + + stream->active_ = true; + stream->cfg_ = &cfg; } /* @@ -283,24 +330,51 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, * adjusted format to be propagated to the ImgU output devices. */ V4L2DeviceFormat cio2Format = {}; - ret = cio2->configure(cfg, &cio2Format); + ret = cio2->configure(sensorSize, &cio2Format); if (ret) return ret; - ret = imgu->configureInput(cfg, &cio2Format); + ret = imgu->configureInput(sensorSize, &cio2Format); if (ret) return ret; - /* Apply the format to the ImgU output, viewfinder and stat. */ - ret = imgu->configureOutput(&imgu->output_, cfg); - if (ret) - return ret; + /* Apply the format to the configured streams output devices. */ + for (Stream *s : config) { + IPU3Stream *stream = static_cast(s); - ret = imgu->configureOutput(&imgu->viewfinder_, cfg); - if (ret) - return ret; + ret = imgu->configureOutput(stream->device_, *stream->cfg_); + if (ret) + return ret; + } + + /* + * As we need to set format also on the non-active streams, use + * the configuration of the active one for that purpose (there should + * be at least one active stream in the configuration request). + */ + if (!outStream->active_) { + ret = imgu->configureOutput(outStream->device_, + *vfStream->cfg_); + if (ret) + return ret; + } - ret = imgu->configureOutput(&imgu->stat_, cfg); + if (!vfStream->active_) { + ret = imgu->configureOutput(vfStream->device_, + *outStream->cfg_); + if (ret) + return ret; + } + + /* + * Apply the largest available format to the stat node. + * \todo Revise this when we'll actually use the stat node. + */ + StreamConfiguration statConfig = {}; + statConfig.width = cio2Format.width; + statConfig.height = cio2Format.height; + + ret = imgu->configureOutput(&imgu->stat_, statConfig); if (ret) return ret; @@ -418,7 +492,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); V4L2Device *output = data->imgu_->output_.dev; - Stream *stream = &data->stream_; + IPU3Stream *stream = &data->outStream_; /* Queue a buffer to the ImgU output for capture. */ Buffer *buffer = request->findBuffer(stream); @@ -569,7 +643,10 @@ int PipelineHandlerIPU3::registerCameras() for (unsigned int id = 0; id < 4 && numCameras < 2; ++id) { std::unique_ptr data = utils::make_unique(this); - std::set streams{ &data->stream_ }; + std::set streams = { + &data->outStream_, + &data->vfStream_, + }; CIO2Device *cio2 = &data->cio2_; ret = cio2->init(cio2MediaDev_.get(), id); @@ -577,11 +654,16 @@ int PipelineHandlerIPU3::registerCameras() continue; /** - * \todo Dynamically assign ImgU devices; as of now, limit - * support to two cameras only, and assign imgu0 to the first - * one and imgu1 to the second. + * \todo Dynamically assign ImgU and output devices to each + * stream and camera; as of now, limit support to two cameras + * only, and assign imgu0 to the first one and imgu1 to the + * second. */ data->imgu_ = numCameras ? &imgu1_ : &imgu0_; + data->outStream_.device_ = &data->imgu_->output_; + data->outStream_.name_ = "output"; + data->vfStream_.device_ = &data->imgu_->viewfinder_; + data->vfStream_.name_ = "viewfinder"; /* * Connect video devices' 'bufferReady' signals to their @@ -598,7 +680,7 @@ int PipelineHandlerIPU3::registerCameras() data->imgu_->output_.dev->bufferReady.connect(data.get(), &IPU3CameraData::imguOutputBufferReady); - /* Create and register the Camera instance. */ + /* Initialize and register the Camera and its streams. */ std::string cameraName = cio2->sensor_->entityName() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, @@ -732,12 +814,12 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) /** * \brief Configure the ImgU unit input - * \param[in] config The requested stream configuration + * \param[in] size The ImgU input frame size * \param[in] inputFormat The format to be applied to ImgU input * * \return 0 on success or a negative error code otherwise */ -int ImgUDevice::configureInput(const StreamConfiguration &config, +int ImgUDevice::configureInput(const Size &size, V4L2DeviceFormat *inputFormat) { /* Configure the ImgU input video device with the requested sizes. */ @@ -775,8 +857,8 @@ int ImgUDevice::configureInput(const StreamConfiguration &config, << rect.toString(); V4L2SubdeviceFormat imguFormat = {}; - imguFormat.width = config.width; - imguFormat.height = config.height; + imguFormat.width = size.width; + imguFormat.height = size.height; imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; ret = imgu_->setFormat(PAD_INPUT, &imguFormat); @@ -1098,15 +1180,15 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) /** * \brief Configure the CIO2 unit - * \param[in] config The requested configuration + * \param[in] size The requested CIO2 output frame size * \param[out] outputFormat The CIO2 unit output image format * * \return 0 on success or a negative error code otherwise */ -int CIO2Device::configure(const StreamConfiguration &config, +int CIO2Device::configure(const Size &size, V4L2DeviceFormat *outputFormat) { - unsigned int imageSize = config.width * config.height; + unsigned int imageSize = size.width * size.height; V4L2SubdeviceFormat sensorFormat = {}; unsigned int best = ~0; int ret; @@ -1116,7 +1198,7 @@ int CIO2Device::configure(const StreamConfiguration &config, if (mediaBusToFormat(it.first) < 0) continue; - for (const SizeRange &size : it.second) { + for (const SizeRange &range : it.second) { /* * Only select formats bigger than the requested sizes * as the IPU3 cannot up-scale. @@ -1125,19 +1207,19 @@ int CIO2Device::configure(const StreamConfiguration &config, * as possible. This will need to be revisited when * implementing the scaling policy. */ - if (size.maxWidth < config.width || - size.maxHeight < config.height) + if (range.maxWidth < size.width || + range.maxHeight < size.height) continue; - unsigned int diff = size.maxWidth * size.maxHeight + unsigned int diff = range.maxWidth * range.maxHeight - imageSize; if (diff >= best) continue; best = diff; - sensorFormat.width = size.maxWidth; - sensorFormat.height = size.maxHeight; + sensorFormat.width = range.maxWidth; + sensorFormat.height = range.maxHeight; sensorFormat.mbus_code = it.first; } } From patchwork Thu Apr 18 10:47:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1042 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 75DE660DC8 for ; Thu, 18 Apr 2019 12:46:37 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id D1CDC1C0002; Thu, 18 Apr 2019 10:46:36 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:11 +0200 Message-Id: <20190418104715.22622-11-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 10/14] libcamera: ipu3: Add multiple stream memory management X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:37 -0000 Perform allocation and setup of memory sharing between the CIO2 output and the ImgU input and allocate memory for each active stream. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 64 +++++++++++++++++++++------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b1e289919d4e..9837637b800b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -91,6 +91,7 @@ public: BufferPool vfPool_; BufferPool statPool_; + BufferPool outPool_; }; class CIO2Device @@ -381,11 +382,20 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return 0; } +/** + * \todo Clarify if 'viewfinder' and 'stat' nodes have to be set up and + * started even if not in use. As of now, if not properly configured and + * enabled, the ImgU processing pipeline stalls. + * + * In order to be able to start the 'viewfinder' and 'stat' nodes, we need + * memory to be reserved. + */ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, const std::set &streams) { IPU3CameraData *data = cameraData(camera); - Stream *stream = *streams.begin(); + IPU3Stream *outStream = &data->outStream_; + IPU3Stream *vfStream = &data->vfStream_; CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; unsigned int bufferCount; @@ -400,28 +410,49 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera, if (ret) goto error_free_cio2; - /* Export ImgU output buffers to the stream's pool. */ - ret = imgu->exportBuffers(&imgu->output_, &stream->bufferPool()); - if (ret) - goto error_free_imgu; - /* - * Reserve memory in viewfinder and stat output devices. Use the - * same number of buffers as the ones requested for the output - * stream. + * Use for the stat's internal pool the same number of buffer as + * for the input pool. + * \todo To be revised when we'll actually use the stat node. */ - bufferCount = stream->bufferPool().count(); - - imgu->viewfinder_.pool->createBuffers(bufferCount); - ret = imgu->exportBuffers(&imgu->viewfinder_, imgu->viewfinder_.pool); - if (ret) - goto error_free_imgu; - + bufferCount = pool->count(); imgu->stat_.pool->createBuffers(bufferCount); ret = imgu->exportBuffers(&imgu->stat_, imgu->stat_.pool); if (ret) goto error_free_imgu; + /* Allocate buffers for each active stream. */ + for (Stream *s : streams) { + IPU3Stream *stream = static_cast(s); + ImgUDevice::ImgUOutput *dev = stream->device_; + + ret = imgu->exportBuffers(dev, &stream->bufferPool()); + if (ret) + goto error_free_imgu; + } + + /* + * Allocate buffers also on non-active outputs; use the same number + * of buffers as the active ones. + */ + if (!outStream->active_) { + bufferCount = vfStream->bufferPool().count(); + outStream->device_->pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(outStream->device_, + outStream->device_->pool); + if (ret) + goto error_free_imgu; + } + + if (!vfStream->active_) { + bufferCount = outStream->bufferPool().count(); + vfStream->device_->pool->createBuffers(bufferCount); + ret = imgu->exportBuffers(vfStream->device_, + vfStream->device_->pool); + if (ret) + goto error_free_imgu; + } + return 0; error_free_imgu: @@ -789,6 +820,7 @@ int ImgUDevice::init(MediaDevice *media, unsigned int index) output_.pad = PAD_OUTPUT; output_.name = "output"; + output_.pool = &outPool_; viewfinder_.dev = V4L2Device::fromEntityName(media, name_ + " viewfinder"); From patchwork Thu Apr 18 10:47:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1043 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 190D160DC6 for ; Thu, 18 Apr 2019 12:46:38 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 9E6111C0007; Thu, 18 Apr 2019 10:46:37 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:12 +0200 Message-Id: <20190418104715.22622-12-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 11/14] libcamera: ipu3: Queue requests for multiple streams X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:38 -0000 Add support for queueing requests for multiple streams in the IPU3 pipeline handler class. The output video node should be queued with buffers even if not part of the requested streams. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9837637b800b..ee490a488cf7 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -521,25 +521,20 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request) { - IPU3CameraData *data = cameraData(camera); - V4L2Device *output = data->imgu_->output_.dev; - IPU3Stream *stream = &data->outStream_; + int ret = 0; - /* Queue a buffer to the ImgU output for capture. */ - Buffer *buffer = request->findBuffer(stream); - if (!buffer) { - LOG(IPU3, Error) - << "Attempt to queue request with invalid stream"; - return -ENOENT; - } + for (auto it : request->buffers()) { + IPU3Stream *stream = static_cast(it.first); + Buffer *buffer = it.second; - int ret = output->queueBuffer(buffer); - if (ret < 0) - return ret; + int status = stream->device_->dev->queueBuffer(buffer); + if (status < 0) + ret = status; + } PipelineHandler::queueRequest(camera, request); - return 0; + return ret; } bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) From patchwork Thu Apr 18 10:47:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1044 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B971F60DD8 for ; Thu, 18 Apr 2019 12:46:38 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 45DC51C0002; Thu, 18 Apr 2019 10:46:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:13 +0200 Message-Id: <20190418104715.22622-13-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 12/14] libcamera: ipu3: Connect viewfinder's BufferReady signal X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:39 -0000 The viewfinder and main output require identical logic for buffer and request completion. Rename the IPU3CameraData::imguOutputBufferReady() slot to IPU3CameraData::imguCaptureBufferReady() to reflect this, and connect the viewfinder bufferReady signal to the slot. Update the slot logic to ignore internal buffers that are not part of the request, and to complete the request only when the last buffer completes. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 32 +++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ee490a488cf7..71b36ecf6cd9 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -705,6 +705,8 @@ int PipelineHandlerIPU3::registerCameras() &IPU3CameraData::imguInputBufferReady); data->imgu_->output_.dev->bufferReady.connect(data.get(), &IPU3CameraData::imguOutputBufferReady); + data->imgu_->viewfinder_.dev->bufferReady.connect(data.get(), + &IPU3CameraData::imguOutputBufferReady); /* Initialize and register the Camera and its streams. */ std::string cameraName = cio2->sensor_->entityName() + " " @@ -750,10 +752,34 @@ void PipelineHandlerIPU3::IPU3CameraData::imguInputBufferReady(Buffer *buffer) */ void PipelineHandlerIPU3::IPU3CameraData::imguOutputBufferReady(Buffer *buffer) { - Request *request = queuedRequests_.front(); + Request *request = buffer->request(); + if (!request) + /* Completed buffers not part of a request are ignored. */ + return; + + if (!pipe_->completeBuffer(camera_, request, buffer)) + /* Request not completed yet, return here. */ + return; + + /* + * Complete requests in queuing order: if some other request is + * pending, post-pone completion. + */ + Request *front = queuedRequests_.front(); + if (front != request) + return; - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); + /* + * Complete the current request, and all the other pending ones, + * in queuing order. + */ + while (1) { + if (front->hasPendingBuffers()) + break; + + pipe_->completeRequest(camera_, front); + front = queuedRequests_.front(); + } } /** From patchwork Thu Apr 18 10:47:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1045 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6F7DE60DC9 for ; Thu, 18 Apr 2019 12:46:39 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id E8C4E1C0004; Thu, 18 Apr 2019 10:46:38 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:14 +0200 Message-Id: <20190418104715.22622-14-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 13/14] libcamera: ipu3: Use roles in stream configuration X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:39 -0000 Use and inspect the stream roles provided by the application to streamConfiguration() to assign streams to their intended roles and return a default configuration associated with them. Support a limited number of usages, as the viewfinder stream can optionally be used for capturing still images, but the main output stream cannot be used as viewfinder or for video recording purposes. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 99 +++++++++++++++++++--------- 1 file changed, 69 insertions(+), 30 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 71b36ecf6cd9..daa66d23d5f3 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -226,38 +226,77 @@ CameraConfiguration PipelineHandlerIPU3::streamConfiguration(Camera *camera, const std::vector &usages) { - CameraConfiguration configs; IPU3CameraData *data = cameraData(camera); - StreamConfiguration config = {}; + CameraConfiguration cameraConfig; + std::set streams = { + &data->outStream_, + &data->vfStream_, + }; - /* - * FIXME: Soraka: the maximum resolution reported by both sensors - * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as - * default configurations but they're not correctly processed by the - * ImgU. Resolutions up tp 2560x1920 have been validated. - * - * \todo Clarify ImgU alignement requirements. - */ - config.width = 2560; - config.height = 1920; - config.pixelFormat = V4L2_PIX_FMT_NV12; - config.bufferCount = IPU3_BUFFER_COUNT; - - configs[&data->outStream_] = config; - LOG(IPU3, Debug) - << "Stream '" << data->outStream_.name_ << "' set to " - << config.width << "x" << config.height << "-0x" - << std::hex << std::setfill('0') << std::setw(8) - << config.pixelFormat; - - configs[&data->vfStream_] = config; - LOG(IPU3, Debug) - << "Stream '" << data->vfStream_.name_ << "' set to " - << config.width << "x" << config.height << "-0x" - << std::hex << std::setfill('0') << std::setw(8) - << config.pixelFormat; - - return configs; + for (const StreamUsage &usage : usages) { + std::vector::iterator found; + StreamUsage::Role role = usage.role(); + StreamConfiguration streamConfig = {}; + IPU3Stream *stream = nullptr; + + if (role == StreamUsage::Role::StillCapture) { + /* + * We can use the viewfinder stream in case the + * 'StillCapture' usage is required multiple times. + */ + if (streams.find(&data->outStream_) != streams.end()) + stream = &data->outStream_; + else if (streams.find(&data->vfStream_) != streams.end()) + stream = &data->vfStream_; + else + goto error; + + /* + * FIXME: Soraka: the maximum resolution reported by + * both sensors (2592x1944 for ov5670 and 4224x3136 for + * ov13858) are returned as default configurations but + * they're not correctly processed by the ImgU. + * Resolutions up tp 2560x1920 have been validated. + * + * \todo Clarify ImgU alignment requirements. + */ + streamConfig.width = 2560; + streamConfig.height = 1920; + } else if (role == StreamUsage::Role::Viewfinder || + role == StreamUsage::Role::VideoRecording) { + /* + * We can't use the 'output' stream for viewfinder or + * video capture usages. + */ + if (streams.find(&data->vfStream_) == streams.end()) + goto error; + + stream = &data->vfStream_; + + streamConfig.width = usage.size().width; + streamConfig.height = usage.size().height; + } + + streams.erase(stream); + + streamConfig.pixelFormat = V4L2_PIX_FMT_NV12; + streamConfig.bufferCount = IPU3_BUFFER_COUNT; + + cameraConfig[stream] = streamConfig; + + LOG(IPU3, Debug) + << "Stream '" << stream->name_ << "' format set to " + << streamConfig.width << "x" << streamConfig.height + << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << streamConfig.pixelFormat; + } + + return cameraConfig; + +error: + LOG(IPU3, Error) << "Requested stream roles not supported"; + + return CameraConfiguration{}; } int PipelineHandlerIPU3::configureStreams(Camera *camera, From patchwork Thu Apr 18 10:47:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1046 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1399760DC9 for ; Thu, 18 Apr 2019 12:46:40 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 94E7F1C0008; Thu, 18 Apr 2019 10:46:39 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 12:47:15 +0200 Message-Id: <20190418104715.22622-15-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418104715.22622-1-jacopo@jmondi.org> References: <20190418104715.22622-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 14/14] [HACK] still capture every 10 frames X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 10:46:40 -0000 Not for inclusion, just to demonstrate how an application could track its streams to their assigned usages. Signed-off-by: Jacopo Mondi --- src/cam/main.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 46aba728393c..fce694bf26d5 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -28,6 +28,11 @@ std::map streamInfo; EventLoop *loop; BufferWriter *writer; +unsigned int streamCount = 0; +unsigned int outBuf = 0; +std::map streamMap; +CameraConfiguration config; + enum { OptCamera = 'c', OptCapture = 'C', @@ -129,6 +134,11 @@ static int prepareCameraConfig(CameraConfiguration *config) return -EINVAL; } + /* Associate each stream returned by the Camera with its role. */ + unsigned int i = 0; + for (auto *stream : *config) + streamMap[stream] = roles[i++].role(); + /* Apply configuration explicitly requested. */ CameraConfiguration::iterator it = config->begin(); for (auto const &value : streamOptions) { @@ -158,6 +168,7 @@ static int prepareCameraConfig(CameraConfiguration *config) static void requestComplete(Request *request, const std::map &buffers) { + std::map map; static uint64_t now, last = 0; double fps = 0.0; @@ -196,13 +207,37 @@ static void requestComplete(Request *request, const std::map return; } - request->setBuffers(buffers); + /* Viewfinder in every request. */ + for (auto &b : buffers) { + Stream *s = b.first; + if (streamMap[s] != StreamUsage::Role::Viewfinder) + continue; + + map[s] = b.second; + } + + /* Still capture every ten requests. */ + streamCount++; + if (!(streamCount % 10)) { + streamCount = 0; + for (Stream *stream : config) { + if (streamMap[stream] != StreamUsage::Role::StillCapture) + continue; + + map[stream] = + &stream->bufferPool().buffers()[outBuf]; + outBuf = (outBuf + 1) % + stream->bufferPool().count(); + break; + } + } + + request->setBuffers(map); camera->queueRequest(request); } static int capture() { - CameraConfiguration config; int ret; ret = prepareCameraConfig(&config); @@ -246,8 +281,13 @@ static int capture() } std::map map; - for (Stream *stream : config) + for (Stream *stream : config) { + if (streamMap[stream] != StreamUsage::Role::Viewfinder) + continue; + + /* Only require the viewfinder to begin with. */ map[stream] = &stream->bufferPool().buffers()[i]; + } ret = request->setBuffers(map); if (ret < 0) {