@@ -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);
@@ -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 */
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(+)