[libcamera-devel,RFC,3/3] libcamera: Use VIDIOC_EXT_(D)QBUF for buffer handling
diff mbox series

Message ID 20210205131044.512128-4-helen.koike@collabora.com
State New
Headers show
Series
  • libcamera: Use extended fmt and buffer ioctls API
Related show

Commit Message

Helen Koike Feb. 5, 2021, 1:10 p.m. UTC
Use Ext API for buffer handling.
Allow memory buffers to be defined per color component.

Signed-off-by: Helen Koike <helen.koike@collabora.com>
---
 src/libcamera/v4l2_videodevice.cpp | 75 ++++++++++++------------------
 src/v4l2/v4l2_camera_proxy.cpp     | 20 ++++----
 2 files changed, 41 insertions(+), 54 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index fab3ba4c..0a724266 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -141,7 +141,7 @@  LOG_DECLARE_CATEGORY(V4L2)
  * \brief Hot cache of associations between V4L2 buffer indexes and FrameBuffer
  *
  * When importing buffers, V4L2 performs lazy mapping of dmabuf instances at
- * VIDIOC_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated
+ * VIDIOC_EXT_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated
  * with the V4L2 buffer, as identified by its index. If the same V4L2 buffer is
  * then reused and queued with different dmabufs, the old dmabufs will be
  * unmapped and the new ones mapped. To keep this process efficient, it is
@@ -1315,8 +1315,8 @@  int V4L2VideoDevice::releaseBuffers()
  */
 int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
 {
-	struct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};
-	struct v4l2_buffer buf = {};
+	V4L2DeviceFormat format;
+	struct v4l2_ext_buffer buf = {};
 	int ret;
 
 	ret = cache_->get(*buffer);
@@ -1328,46 +1328,46 @@  int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)
 	buf.memory = memoryType_;
 	buf.field = V4L2_FIELD_NONE;
 
-	bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
 	const std::vector<FrameBuffer::Plane> &planes = buffer->planes();
 
+	ret = getFormat(&format);
+	if (ret < 0)
+		return ret;
+
 	if (buf.memory == V4L2_MEMORY_DMABUF) {
-		if (multiPlanar) {
-			for (unsigned int p = 0; p < planes.size(); ++p)
-				v4l2Planes[p].m.fd = planes[p].fd.fd();
+		/*
+		 * If there is a single memory plane, fill color planes with
+		 * the same dmabuf fd but on a different offset
+		 */
+		if (planes.size() == 1) {
+			buf.planes[0].m.dmabuf_fd = planes[0].fd.fd();
+			for (unsigned int p = 1;
+			     p < format.planes.size() && format.planes[p].size; ++p) {
+				buf.planes[p].m.dmabuf_fd = planes[0].fd.fd();
+				buf.planes[p].offset = format.planes[p - 1].size;
+			}
 		} else {
-			buf.m.fd = planes[0].fd.fd();
+			for (unsigned int p = 0; p < planes.size(); ++p)
+				buf.planes[p].m.dmabuf_fd = planes[p].fd.fd();
 		}
 	}
 
-	if (multiPlanar) {
-		buf.length = planes.size();
-		buf.m.planes = v4l2Planes;
-	}
-
 	if (V4L2_TYPE_IS_OUTPUT(buf.type)) {
 		const FrameMetadata &metadata = buffer->metadata();
+		unsigned int nplane = 0;
 
-		if (multiPlanar) {
-			unsigned int nplane = 0;
-			for (const FrameMetadata::Plane &plane : metadata.planes) {
-				v4l2Planes[nplane].bytesused = plane.bytesused;
-				v4l2Planes[nplane].length = buffer->planes()[nplane].length;
-				nplane++;
-			}
-		} else {
-			if (metadata.planes.size())
-				buf.bytesused = metadata.planes[0].bytesused;
+		for (const FrameMetadata::Plane &plane : metadata.planes) {
+			buf.planes[nplane].bytesused = plane.bytesused;
+			nplane++;
 		}
 
 		buf.sequence = metadata.sequence;
-		buf.timestamp.tv_sec = metadata.timestamp / 1000000000;
-		buf.timestamp.tv_usec = (metadata.timestamp / 1000) % 1000000;
+		buf.timestamp = metadata.timestamp;
 	}
 
 	LOG(V4L2, Debug) << "Queueing buffer " << buf.index;
 
-	ret = ioctl(VIDIOC_QBUF, &buf);
+	ret = ioctl(VIDIOC_EXT_QBUF, &buf);
 	if (ret < 0) {
 		LOG(V4L2, Error)
 			<< "Failed to queue buffer " << buf.index << ": "
@@ -1413,21 +1413,13 @@  void V4L2VideoDevice::bufferAvailable([[maybe_unused]] EventNotifier *notifier)
  */
 FrameBuffer *V4L2VideoDevice::dequeueBuffer()
 {
-	struct v4l2_buffer buf = {};
-	struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
+	struct v4l2_ext_buffer buf = {};
 	int ret;
 
 	buf.type = bufferType_;
 	buf.memory = memoryType_;
 
-	bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
-
-	if (multiPlanar) {
-		buf.length = VIDEO_MAX_PLANES;
-		buf.m.planes = planes;
-	}
-
-	ret = ioctl(VIDIOC_DQBUF, &buf);
+	ret = ioctl(VIDIOC_EXT_DQBUF, &buf);
 	if (ret < 0) {
 		LOG(V4L2, Error)
 			<< "Failed to dequeue buffer: " << strerror(-ret);
@@ -1449,16 +1441,11 @@  FrameBuffer *V4L2VideoDevice::dequeueBuffer()
 				 ? FrameMetadata::FrameError
 				 : FrameMetadata::FrameSuccess;
 	buffer->metadata_.sequence = buf.sequence;
-	buffer->metadata_.timestamp = buf.timestamp.tv_sec * 1000000000ULL
-				    + buf.timestamp.tv_usec * 1000ULL;
+	buffer->metadata_.timestamp = buf.timestamp;
 
 	buffer->metadata_.planes.clear();
-	if (multiPlanar) {
-		for (unsigned int nplane = 0; nplane < buf.length; nplane++)
-			buffer->metadata_.planes.push_back({ planes[nplane].bytesused });
-	} else {
-		buffer->metadata_.planes.push_back({ buf.bytesused });
-	}
+	for (unsigned int nplane = 0; buf.planes[nplane].bytesused; nplane++)
+		buffer->metadata_.planes.push_back({ buf.planes[nplane].bytesused });
 
 	return buffer;
 }
diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index f8bfe595..32fed4b8 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -544,9 +544,9 @@  int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *a
 	return 0;
 }
 
-int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
+int V4L2CameraProxy::vidioc_ext_qbuf(V4L2CameraFile *file, struct v4l2_ext_buffer *arg)
 {
-	LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = "
+	LOG(V4L2Compat, Debug) << "Servicing vidioc_ext_qbuf, index = "
 			       << arg->index << " fd = " << file->efd();
 
 	if (arg->index >= bufferCount_)
@@ -574,8 +574,8 @@  int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
 	return ret;
 }
 
-int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg,
-				  MutexLocker *locker)
+int V4L2CameraProxy::vidioc_ext_dqbuf(V4L2CameraFile *file, struct v4l2_ext_buffer *arg,
+				      MutexLocker *locker)
 {
 	LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd();
 
@@ -683,8 +683,8 @@  const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
 	VIDIOC_S_INPUT,
 	VIDIOC_REQBUFS,
 	VIDIOC_QUERYBUF,
-	VIDIOC_QBUF,
-	VIDIOC_DQBUF,
+	VIDIOC_EXT_QBUF,
+	VIDIOC_EXT_DQBUF,
 	VIDIOC_STREAMON,
 	VIDIOC_STREAMOFF,
 };
@@ -749,11 +749,11 @@  int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar
 	case VIDIOC_QUERYBUF:
 		ret = vidioc_querybuf(file, static_cast<struct v4l2_buffer *>(arg));
 		break;
-	case VIDIOC_QBUF:
-		ret = vidioc_qbuf(file, static_cast<struct v4l2_buffer *>(arg));
+	case VIDIOC_EXT_QBUF:
+		ret = vidioc_ext_qbuf(file, static_cast<struct v4l2_ext_buffer *>(arg));
 		break;
-	case VIDIOC_DQBUF:
-		ret = vidioc_dqbuf(file, static_cast<struct v4l2_buffer *>(arg), &locker);
+	case VIDIOC_EXT_DQBUF:
+		ret = vidioc_ext_dqbuf(file, static_cast<struct v4l2_ext_buffer *>(arg), &locker);
 		break;
 	case VIDIOC_STREAMON:
 		ret = vidioc_streamon(file, static_cast<int *>(arg));