[libcamera-devel] [PATCH 09/10] libcamera: pipeline: simple: Move bufferReady handler to SimpleCameraData

Laurent Pinchart laurent.pinchart at ideasonboard.com
Fri Aug 6 00:24:35 CEST 2021


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 <laurent.pinchart at ideasonboard.com>
---
 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<const MediaEntity *, EntityData> 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<unsigned int, FrameBuffer *> &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<unsigned int, FrameBuffer *> &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 */
-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list