@@ -57,6 +57,7 @@
*/
#include <errno.h>
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@@ -79,6 +80,7 @@
#define V4L2_STREAM_TOUCHED 0x2000
#define V4L2_USE_READ_FOR_READ 0x4000
#define V4L2_SUPPORTS_TIMEPERFRAME 0x8000
+#define V4L2_CONVERT2MPLANE 0x00010000
#define V4L2_MMAP_OFFSET_MAGIC 0xABCDEF00u
@@ -93,6 +95,165 @@ static struct v4l2_dev_info devices[V4L2_MAX_DEVICES] = {
};
static int devices_used;
+static int v4l2_get_index(int fd);
+
+#define SYS_DO_IOCTL(fd, cmd, arg) \
+ syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+
+int v4l2_ioctl_mp(int fd, unsigned long cmd, void *arg)
+{
+ int ret;
+ int index = v4l2_get_index(fd);
+
+ /* skipping if no mplane convertion is needed */
+ if (index == -1 || !(devices[index].flags & V4L2_CONVERT2MPLANE))
+ return SYS_DO_IOCTL(fd, cmd, arg);
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP: {
+ struct v4l2_capability *cap = arg;
+ ret = SYS_DO_IOCTL(fd, cmd, cap);
+ if (ret)
+ return ret;
+ if (cap->capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
+ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE;
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT: {
+ /* convert single planar structs to mplane structs */
+ struct v4l2_format fmt = {0};
+ struct v4l2_format *old = arg;
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ fmt.fmt.pix_mp.width = old->fmt.pix.width;
+ fmt.fmt.pix_mp.height = old->fmt.pix.height;
+ fmt.fmt.pix_mp.pixelformat = old->fmt.pix.pixelformat;
+ fmt.fmt.pix_mp.field = old->fmt.pix.field;
+ fmt.fmt.pix_mp.colorspace = old->fmt.pix.colorspace;
+ fmt.fmt.pix_mp.num_planes = 1;
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline = old->fmt.pix.bytesperline;
+ fmt.fmt.pix_mp.plane_fmt[0].sizeimage = old->fmt.pix.sizeimage;
+
+ ret = SYS_DO_IOCTL(fd, cmd, &fmt);
+ if (ret)
+ return ret;
+
+ old->fmt.pix.width = fmt.fmt.pix_mp.width;
+ old->fmt.pix.height = fmt.fmt.pix_mp.height;
+ old->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+ old->fmt.pix.field = fmt.fmt.pix_mp.field;
+ old->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+ old->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ old->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ return 0;
+ }
+ case VIDIOC_G_FMT: {
+ struct v4l2_format fmt = { 0 };
+ struct v4l2_format *old = arg;
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, &fmt);
+ if (ret)
+ return ret;
+ /* cannot return multiplane format to singleplane app */
+ if (fmt.fmt.pix_mp.num_planes > 1) {
+ errno = -EBUSY;
+ return -1;
+ }
+ old->fmt.pix.width = fmt.fmt.pix_mp.width;
+ old->fmt.pix.height = fmt.fmt.pix_mp.height;
+ old->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat;
+ old->fmt.pix.field = fmt.fmt.pix_mp.field;
+ old->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace;
+ old->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline;
+ old->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ return 0;
+ }
+ case VIDIOC_ENUM_FMT: {
+ struct v4l2_fmtdesc *fmtdesc = arg;
+
+ fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, fmtdesc);
+ fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return ret;
+ }
+ case VIDIOC_S_PARM:
+ case VIDIOC_G_PARM: {
+ struct v4l2_streamparm *parm = arg;
+
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, parm);
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return ret;
+ }
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF: {
+ int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+ return SYS_DO_IOCTL(fd, cmd, &type);
+ }
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cropcap = arg;
+
+ cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, cropcap);
+ cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return ret;
+ }
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, crop);
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return ret;
+ }
+ case VIDIOC_REQBUFS: {
+ struct v4l2_requestbuffers *rq = arg;
+
+ rq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = SYS_DO_IOCTL(fd, cmd, rq);
+ rq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return ret;
+ }
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF:
+ case VIDIOC_QUERYBUF: {
+ struct v4l2_buffer buf;
+ struct v4l2_buffer *old = arg;
+ struct v4l2_plane plane = { 0 };
+
+ memcpy(&buf, old, sizeof buf);
+ memcpy(&plane.m, &old->m, sizeof old->m);
+ plane.length = old->length;
+ plane.bytesused = old->bytesused;
+
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ buf.m.planes = &plane;
+ buf.length = 1;
+
+ ret = SYS_DO_IOCTL(fd, cmd, &buf);
+ if (ret)
+ return ret;
+
+ memcpy(old, &buf, sizeof buf);
+ old->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ memcpy(&old->m, &plane.m, sizeof plane.m);
+ old->length = plane.length;
+ old->bytesused = plane.bytesused;
+ return 0;
+ }
+
+ } /* switch brace */
+
+ /* handling not mplane ioctl */
+ return SYS_DO_IOCTL(fd, cmd, arg);
+}
static int v4l2_request_read_buffers(int index)
{
@@ -586,7 +747,7 @@ int v4l2_fd_open(int fd, int v4l2_flags)
}
/* check that this is an v4l2 device */
- if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
+ if (SYS_DO_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
int saved_err = errno;
V4L2_LOG_ERR("getting capabilities: %s\n", strerror(errno));
@@ -595,35 +756,21 @@ int v4l2_fd_open(int fd, int v4l2_flags)
}
/* we only add functionality for video capture devices */
- if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
- !(cap.capabilities & (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE)))
+ if (!(cap.capabilities &
+ (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
return fd;
- /* Get current cam format */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (SYS_IOCTL(fd, VIDIOC_G_FMT, &fmt)) {
- int saved_err = errno;
-
- V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno));
- errno = saved_err;
- return -1;
- }
-
- /* Check for framerate setting support */
- parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (SYS_IOCTL(fd, VIDIOC_G_PARM, &parm))
- parm.type = 0;
-
- /* init libv4lconvert */
- convert = v4lconvert_create(fd);
- if (!convert)
- return -1;
+ /* we only add functionality for video streaming and read/write devices */
+ if (!(cap.capabilities & (V4L2_CAP_STREAMING | V4L2_CAP_READWRITE)))
+ return fd;
/* So we have a v4l2 capture device, register it in our devices array */
pthread_mutex_lock(&v4l2_open_mutex);
for (index = 0; index < V4L2_MAX_DEVICES; index++)
if (devices[index].fd == -1) {
devices[index].fd = fd;
+ if (index >= devices_used)
+ devices_used = index + 1;
break;
}
pthread_mutex_unlock(&v4l2_open_mutex);
@@ -636,6 +783,31 @@ int v4l2_fd_open(int fd, int v4l2_flags)
}
devices[index].flags = v4l2_flags;
+ /* enabling conversion for driver that supports only multiplanar api */
+ if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
+ !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+ devices[index].flags |= V4L2_CONVERT2MPLANE;
+
+ /* Get current cam format */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (SYS_IOCTL(fd, VIDIOC_G_FMT, &fmt)) {
+ int saved_err = errno;
+
+ V4L2_LOG_ERR("getting pixformat: %s\n", strerror(errno));
+ errno = saved_err;
+ goto fail;
+ }
+
+ /* Check for framerate setting support */
+ parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (SYS_IOCTL(fd, VIDIOC_G_PARM, &parm))
+ parm.type = 0;
+
+ /* init libv4lconvert */
+ convert = v4lconvert_create(fd);
+ if (!convert)
+ goto fail;
+
if (cap.capabilities & V4L2_CAP_READWRITE)
devices[index].flags |= V4L2_SUPPORTS_READ;
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
@@ -677,9 +849,6 @@ int v4l2_fd_open(int fd, int v4l2_flags)
devices[index].readbuf = NULL;
devices[index].readbuf_size = 0;
- if (index >= devices_used)
- devices_used = index + 1;
-
/* Note we always tell v4lconvert to optimize src fmt selection for
our default fps, the only exception is the app explictly selecting
a framerate using the S_PARM ioctl after a S_FMT */
@@ -689,6 +858,14 @@ int v4l2_fd_open(int fd, int v4l2_flags)
V4L2_LOG("open: %d\n", fd);
return fd;
+
+fail:
+ /* unregister device */
+ pthread_mutex_lock(&v4l2_open_mutex);
+ devices[index].fd = -1;
+ pthread_mutex_unlock(&v4l2_open_mutex);
+
+ return -1;
}
/* Is this an fd for which we are emulating v4l1 ? */
@@ -72,12 +72,13 @@ typedef off_t __off_t;
#ifndef CONFIG_SYS_WRAPPER
+int v4l2_ioctl_mp(int fd, unsigned long cmd, void *arg) __attribute__ ((visibility("default")));
+
#define SYS_OPEN(file, oflag, mode) \
syscall(SYS_open, (const char *)(file), (int)(oflag), (mode_t)(mode))
#define SYS_CLOSE(fd) \
syscall(SYS_close, (int)(fd))
-#define SYS_IOCTL(fd, cmd, arg) \
- syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg))
+#define SYS_IOCTL(fd, cmd, arg) v4l2_ioctl_mp(fd, cmd, arg)
#define SYS_READ(fd, buf, len) \
syscall(SYS_read, (int)(fd), (void *)(buf), (size_t)(len));
#define SYS_WRITE(fd, buf, len) \