[libcamera-devel,19/27] libcamera: camera: Extend the interface to support capture

Message ID 20190206060818.13907-20-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • Capture frames throught requests
Related show

Commit Message

Laurent Pinchart Feb. 6, 2019, 6:08 a.m. UTC
From: Niklas Söderlund <niklas.soderlund@ragnatech.se>

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 <niklas.soderlund@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 include/libcamera/camera.h |  10 +++
 src/libcamera/camera.cpp   | 141 +++++++++++++++++++++++++++++++++++++
 src/libcamera/request.cpp  |  13 ++--
 3 files changed, 159 insertions(+), 5 deletions(-)

Patch

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<Stream *> &streams);
 	int configureStreams(std::map<Stream *, StreamConfiguration> &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 <libcamera/camera.h>
+#include <libcamera/request.h>
 #include <libcamera/stream.h>
 
 #include "log.h"
@@ -264,11 +265,151 @@  int Camera::configureStreams(std::map<Stream *, StreamConfiguration> &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<Stream *, Buffer *> buffers(std::move(bufferMap_));
-		camera_->requestCompleted.emit(this, buffers);
-	}
+	if (!pending_.empty())
+		return;
+
+	std::map<Stream *, Buffer *> buffers(std::move(bufferMap_));
+	camera_->requestCompleted.emit(this, buffers);
+	delete this;
 }
 
 } /* namespace libcamera */