[libcamera-devel,06/11] libcamera: v4l2_device: Implement stream{On, Off}

Message ID 20190203110102.5663-7-kieran.bingham@ideasonboard.com
State Superseded
Headers show
Series
  • libcamera: V4L2 Streams
Related show

Commit Message

Kieran Bingham Feb. 3, 2019, 11 a.m. UTC
Support starting and stopping a stream on a V4L2 device. This requires
having buffers queued, thus both queueBuffer() and dequeueBuffer() are
also added.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 src/libcamera/include/v4l2_device.h |   6 ++
 src/libcamera/v4l2_device.cpp       | 134 ++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+)

Patch

diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h
index f445f98f97a4..d3dad355be58 100644
--- a/src/libcamera/include/v4l2_device.h
+++ b/src/libcamera/include/v4l2_device.h
@@ -101,6 +101,12 @@  public:
 
 	BufferPool *requestBuffers(unsigned int qty = 8);
 
+	int queueBuffer(Buffer *frame);
+	Buffer *dequeueBuffer();
+
+	int streamOn();
+	int streamOff();
+
 private:
 	int getFormatSingleplane(V4L2DeviceFormat *fmt);
 	int setFormatSingleplane(V4L2DeviceFormat *fmt);
diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
index 728478a1ae8f..1fd289137b36 100644
--- a/src/libcamera/v4l2_device.cpp
+++ b/src/libcamera/v4l2_device.cpp
@@ -592,4 +592,138 @@  int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *fmt)
 	return 0;
 }
 
+/**
+ * \brief Queue a buffer into the device.
+ *
+ * For Capture devices the buffer will be operated on and can be dequeued later
+ * with active data.
+ *
+ * For Output devices the buffer should contain valid data and will be processed
+ * by the receiving device. The buffer will be available to dequeue when it is
+ * no longer in use by the Output device.
+ *
+ * \return 0 if the operation completes or a negative error number otherwise
+ */
+int V4L2Device::queueBuffer(Buffer *frame)
+{
+	struct v4l2_buffer buf = {};
+	struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
+	int ret;
+
+	buf.index = frame->index();
+	buf.type = bufferType_;
+	buf.memory = memoryType_;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
+		buf.length = frame->planes().size();
+		buf.m.planes = planes;
+	}
+
+	LOG(V4L2, Debug) << "Queueing buffer idx: " << buf.index;
+
+	ret = ioctl(fd_, VIDIOC_QBUF, &buf);
+	if (ret < 0) {
+		ret = -errno;
+		LOG(V4L2, Error)
+			<< "Failed to queue buffer: " << strerror(-ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * \brief dequeue a buffer from the device
+ *
+ * For Capture devices the buffer will be contain valid data and can be used for
+ * further processing. The buffer should be re-queued when it is no longer in
+ * use.
+ *
+ * For Output devices the buffer has been processed by the hardware and can now
+ * be freely re-used.
+ *
+ * \return A Buffer pointer if the operation completes or a nullptr otherwise
+ */
+Buffer *V4L2Device::dequeueBuffer()
+{
+	struct v4l2_buffer buf = {};
+	struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
+	int ret;
+
+	buf.type = bufferType_;
+	buf.memory = memoryType_;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
+		buf.length = VIDEO_MAX_PLANES;
+		buf.m.planes = planes;
+	}
+
+	ret = ioctl(fd_, VIDIOC_DQBUF, &buf);
+	if (ret < 0) {
+		ret = -errno;
+		LOG(V4L2, Error)
+			<< "Failed to dequeue buffer: " << strerror(-ret);
+		return nullptr;
+	}
+
+	if (buf.index >= bufferPool_->buffers().size()) {
+		LOG(V4L2, Error) << "Invalid buffer index dequeued";
+		return nullptr;
+	}
+
+	return bufferPool_->buffers()[buf.index];
+}
+
+/**
+ * \brief Request that the V4L2Device commences streaming
+ *
+ * Prepares the device to start processing Buffers, and connects the completion
+ * handler to the bufferAvailable Slot.
+ *
+ * \return 0 if the operation completes or a negative error number otherwise
+ */
+int V4L2Device::streamOn()
+{
+	int ret;
+
+	if (caps_.isCapture()) {
+		for (Buffer *b : bufferPool_->buffers()) {
+			ret = queueBuffer(b);
+			if (ret)
+				return ret;
+		}
+	}
+
+	ret = ioctl(fd_, VIDIOC_STREAMON, &bufferType_);
+	if (ret < 0) {
+		ret = -errno;
+		LOG(V4L2, Error)
+			<< "Failed to start streaming: " << strerror(-ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Request that the V4L2Device stops streaming
+ *
+ * Asks the device to halt any current streaming operations.
+ *
+ * \return 0 if the operation completes or a negative error number otherwise
+ */
+int V4L2Device::streamOff()
+{
+	int ret;
+
+	ret = ioctl(fd_, VIDIOC_STREAMOFF, &bufferType_);
+	if (ret < 0) {
+		LOG(V4L2, Error)
+			<< "Failed to stop streaming: " << strerror(errno);
+		return ret;
+	}
+
+	return 0;
+}
+
 } /* namespace libcamera */