From patchwork Wed Feb 6 06:08:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 534 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 240986103A for ; Wed, 6 Feb 2019 07:08:28 +0100 (CET) Received: from pendragon.ideasonboard.com (d51A4137F.access.telenet.be [81.164.19.127]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BECE041 for ; Wed, 6 Feb 2019 07:08:27 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1549433307; bh=/HHwNwFor12mfYEAbRtgdJcRixGtPiMri6J+aFj1QpY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QErC2OF+ARZp7G/gcboKiWhf9rBMF5JFFF/2KRGhQhW/9vCucb8TtNZXGA6snXHQE abwVnORJPU0HyRzO59tvsYD0BStcRRDSJgA5Ub0cA9rQ8aNcWm3eXTuiR1/E9K6ihX YLldUNdWx/6+p3K9iCaQpTXwmrBBg+rUn6wMT/Hk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 6 Feb 2019 08:08:10 +0200 Message-Id: <20190206060818.13907-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190206060818.13907-1-laurent.pinchart@ideasonboard.com> References: <20190206060818.13907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 19/27] libcamera: camera: Extend the interface to support capture 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: Wed, 06 Feb 2019 06:08:29 -0000 From: Niklas Söderlund In order to support capture, the camera needs methods to allocate and free buffers, to start and stop the capture and to queue requests. Define those interfaces in the Camera class and implement them to call the corresponding pipeline handler methods. Once a camera is started the pipeline handler of the camera will begin processing requests queued to the camera by the application until it gets stopped. Once a request is created it can be queued to the camera and the application will be notified asynchronously once the request is completed and be able to process all the buffers involved in the request. At this point the request objects don't support controls. This will be extended in the future. Signed-off-by: Niklas Söderlund Signed-off-by: Jacopo Mondi Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart --- include/libcamera/camera.h | 10 +++ src/libcamera/camera.cpp | 141 +++++++++++++++++++++++++++++++++++++ src/libcamera/request.cpp | 13 ++-- 3 files changed, 159 insertions(+), 5 deletions(-) diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index 1c0ee07c2a22..bf70255a6a5e 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -18,6 +18,7 @@ namespace libcamera { class Buffer; class PipelineHandler; +class Request; class Stream; class StreamConfiguration; @@ -44,6 +45,15 @@ public: streamConfiguration(std::vector &streams); int configureStreams(std::map &config); + int allocateBuffers(); + void freeBuffers(); + + Request *createRequest(); + int queueRequest(Request *request); + + int start(); + int stop(); + private: Camera(PipelineHandler *pipe, const std::string &name); ~Camera(); diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 3f7b805b09a2..1acb399c80a6 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include "log.h" @@ -264,11 +265,151 @@ int Camera::configureStreams(std::map &config) stream->configuration_ = cfg; activeStreams_.push_back(stream); + + /* + * Allocate buffer objects in the pool. + * Memory will be allocated and assigned later. + */ + stream->bufferPool().createBuffers(cfg.bufferCount); } return 0; } +/** + * \brief Allocate buffers for all configured streams + * \return 0 on success or a negative error code otherwise + */ +int Camera::allocateBuffers() +{ + int ret; + + ret = exclusiveAccess(); + if (ret) + return ret; + + if (activeStreams_.empty()) { + LOG(Camera, Error) + << "Can't allocate buffers without streams"; + return -EINVAL; + } + + for (Stream *stream : activeStreams_) { + ret = pipe_->allocateBuffers(this, stream); + if (ret) { + LOG(Camera, Error) << "Failed to allocate buffers"; + freeBuffers(); + return ret; + } + } + + return 0; +} + +/** + * \brief Release all buffers from allocated pools in each stream + */ +void Camera::freeBuffers() +{ + for (Stream *stream : activeStreams_) { + if (!stream->bufferPool().count()) + continue; + + pipe_->freeBuffers(this, stream); + stream->bufferPool().destroyBuffers(); + } +} + +/** + * \brief Create a request object for the camera + * + * This method creates an empty request for the application to fill with + * buffers and paramaters, and queue for capture. + * + * The ownership of the returned request is passed to the caller, which is + * responsible for either queueing the request or deleting it. + * + * \return A pointer to the newly created request, or nullptr on error + */ +Request *Camera::createRequest() +{ + if (exclusiveAccess()) + return nullptr; + + return new Request(this); +} + +/** + * \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. + * + * Ownership of the request is transferred to the camera. It will be deleted + * automatically after it completes. + * + * \return 0 on success or a negative error code on error + */ +int Camera::queueRequest(Request *request) +{ + int ret; + + ret = exclusiveAccess(); + if (ret) + return ret; + + ret = request->prepare(); + if (ret) { + LOG(Camera, Error) << "Failed to prepare request"; + return ret; + } + + return pipe_->queueRequest(this, request); +} + +/** + * \brief Start capture from camera + * + * Start the camera capture session. Once the camera is started the application + * can queue requests to the camera to process and return to the application + * until the capture session is terminated with \a stop(). + * + * \return 0 on success or a negative error code on error + */ +int Camera::start() +{ + int ret = exclusiveAccess(); + if (ret) + return ret; + + LOG(Camera, Debug) << "Starting capture"; + + return pipe_->start(this); +} + +/** + * \brief Stop capture from camera + * + * This method stops capturing and processing requests immediately. All pending + * requests are cancelled and complete synchronously in an error state. + * + * \return 0 on success or a negative error code on error + */ +int Camera::stop() +{ + int ret = exclusiveAccess(); + if (ret) + return ret; + + LOG(Camera, Debug) << "Stopping capture"; + + pipe_->stop(this); + + return 0; +} + int Camera::exclusiveAccess() { if (disconnected_) diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 922682a32188..d76db24de0e2 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -104,7 +104,8 @@ int Request::prepare() * data. * * The request completes when all the buffers it contains are ready to be - * presented to the application. + * presented to the application. It then emits the Camera::requestCompleted + * signal and is automatically deleted. */ void Request::bufferCompleted(Buffer *buffer) { @@ -113,10 +114,12 @@ void Request::bufferCompleted(Buffer *buffer) int ret = pending_.erase(buffer); ASSERT(ret == 1); - if (pending_.empty()) { - std::map buffers(std::move(bufferMap_)); - camera_->requestCompleted.emit(this, buffers); - } + if (!pending_.empty()) + return; + + std::map buffers(std::move(bufferMap_)); + camera_->requestCompleted.emit(this, buffers); + delete this; } } /* namespace libcamera */