This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/v4l-utils.git tree:
Subject: Add a libv4l plugin for mplane handling Author: Mauro Carvalho Chehab <[email protected]> Date: Sat Nov 24 09:57:57 2012 -0200 Devices with only mplane buffer types require some special conversion, in order to be able to be used by standard applications. Add a libv4l plugin to handle it. Signed-off-by: Mauro Carvalho Chehab <[email protected]> configure.ac | 2 + lib/Makefile.am | 4 +- lib/libv4l-mplane/Makefile.am | 12 + lib/libv4l-mplane/libv4l-mplane.c | 366 +++++++++++++++++++++++++++++++++ lib/libv4l-mplane/libv4l-mplane.pc.in | 11 + 5 files changed, 393 insertions(+), 2 deletions(-) --- http://git.linuxtv.org/v4l-utils.git?a=commitdiff;h=ced1be346fe4f61c864cba9d81f66089d4e32a56 diff --git a/configure.ac b/configure.ac index afe9201..f10d9b9 100644 --- a/configure.ac +++ b/configure.ac @@ -16,6 +16,7 @@ AC_CONFIG_FILES([Makefile lib/libv4l1/Makefile lib/libdvbv5/Makefile lib/libv4l2rds/Makefile + lib/libv4l-mplane/Makefile utils/Makefile utils/libv4l2util/Makefile @@ -42,6 +43,7 @@ AC_CONFIG_FILES([Makefile lib/libv4l2/libv4l2.pc lib/libdvbv5/libdvbv5.pc lib/libv4l2rds/libv4l2rds.pc + lib/libv4l-mplane/libv4l-mplane.pc ]) AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-bzip2 -Wno-portability]) # 1.10 is needed for target_LIBTOOLFLAGS diff --git a/lib/Makefile.am b/lib/Makefile.am index 1bbf5c0..40fba50 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -3,5 +3,5 @@ SUBDIRS = \ libv4l2 \ libv4l1 \ libdvbv5 \ - libv4l2rds - + libv4l2rds \ + libv4l-mplane diff --git a/lib/libv4l-mplane/Makefile.am b/lib/libv4l-mplane/Makefile.am new file mode 100644 index 0000000..8ef118d --- /dev/null +++ b/lib/libv4l-mplane/Makefile.am @@ -0,0 +1,12 @@ +libdir = @libv4l2plugindir@ + +if WITH_LIBV4L +lib_LTLIBRARIES = libv4l-mplane.la +pkgconfig_DATA = libv4l-mplane.pc +else +noinst_LTLIBRARIES = libv4l-mplane.la +endif + +libv4l_mplane_la_SOURCES = libv4l-mplane.c +libv4l_mplane_la_CPPFLAGS = -fvisibility=hidden $(ENFORCE_LIBV4L_STATIC) -std=c99 +libv4l_mplane_la_LDFLAGS = -version-info 0 -lpthread $(ENFORCE_LIBV4L_STATIC) diff --git a/lib/libv4l-mplane/libv4l-mplane.c b/lib/libv4l-mplane/libv4l-mplane.c new file mode 100644 index 0000000..3bba1d9 --- /dev/null +++ b/lib/libv4l-mplane/libv4l-mplane.c @@ -0,0 +1,366 @@ +/* + * (C) 2012 Mauro Carvalho Chehab <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + */ + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include <linux/videodev2.h> + +#include "libv4l-plugin.h" + +#define SYS_IOCTL(fd, cmd, arg) \ + syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), (void *)(arg)) + + +#if __GNUC__ >= 4 +#define PLUGIN_PUBLIC __attribute__ ((visibility("default"))) +#else +#define PLUGIN_PUBLIC +#endif + +struct mplane_plugin { + union { + struct { + unsigned int mplane_capture : 1; + unsigned int mplane_output : 1; + }; + unsigned int mplane; + }; +}; + +#define SIMPLE_CONVERT_IOCTL(fd, cmd, arg, __struc) ({ \ + int __ret; \ + struct __struc *req = arg; \ + uint32_t type = req->type; \ + req->type = convert_type(type); \ + __ret = SYS_IOCTL(fd, cmd, arg); \ + req->type = type; \ + __ret; \ + }) + +static void *plugin_init(int fd) +{ + struct v4l2_capability cap; + int ret; + struct mplane_plugin plugin, *ret_plugin; + + memset(&plugin, 0, sizeof(plugin)); + + /* Check if device needs mplane plugin */ + memset(&cap, 0, sizeof(cap)); + ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap); + if (ret) { + perror("Failed to query video capabilities"); + return NULL; + } + + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) + plugin.mplane_capture = 1; + + if (!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) && + (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)) + plugin.mplane_output = 1; + + /* Device doesn't need it. return NULL to disable the plugin */ + if (!plugin.mplane) + return NULL; + + /* Allocate and initialize private data */ + ret_plugin = calloc(1, sizeof(*ret_plugin)); + if (!ret_plugin) { + perror("Couldn't allocate memory for plugin"); + return NULL; + } + *ret_plugin = plugin; + + printf("Using mplane plugin for %s%s\n", + plugin.mplane_capture ? "capture " : "", + plugin.mplane_output ? "output " : ""); + + return ret_plugin; +} + +static void plugin_close(void *dev_ops_priv) { + if (dev_ops_priv == NULL) + return; + + free(dev_ops_priv); +} + +static int querycap_ioctl(int fd, unsigned long int cmd, + struct v4l2_capability *arg) +{ + struct v4l2_capability *cap = arg; + int ret; + + ret = SYS_IOCTL(fd, cmd, cap); + if (ret) + return ret; + + /* Report mplane as normal caps */ + if (cap->capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) + cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE; + + if (cap->capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) + cap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; + + /* + * Don't report mplane caps, as this will be handled via + * this plugin + */ + cap->capabilities &= ~(V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE); + + return 0; +} + +static int convert_type(int type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + default: + return type; + } +} + +static int try_set_fmt_ioctl(int fd, unsigned long int cmd, + struct v4l2_format *arg) +{ + struct v4l2_format fmt = { 0 }; + struct v4l2_format *org = arg; + int ret; + + switch (arg->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + break; + default: + return SYS_IOCTL(fd, cmd, &fmt); + } + + fmt.fmt.pix_mp.width = org->fmt.pix.width; + fmt.fmt.pix_mp.height = org->fmt.pix.height; + fmt.fmt.pix_mp.pixelformat = org->fmt.pix.pixelformat; + fmt.fmt.pix_mp.field = org->fmt.pix.field; + fmt.fmt.pix_mp.colorspace = org->fmt.pix.colorspace; + fmt.fmt.pix_mp.num_planes = 1; + fmt.fmt.pix_mp.plane_fmt[0].bytesperline = org->fmt.pix.bytesperline; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = org->fmt.pix.sizeimage; + + ret = SYS_IOCTL(fd, cmd, &fmt); + if (ret) + return ret; + + org->fmt.pix.width = fmt.fmt.pix_mp.width; + org->fmt.pix.height = fmt.fmt.pix_mp.height; + org->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat; + org->fmt.pix.field = fmt.fmt.pix_mp.field; + org->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace; + org->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline; + org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + return 0; +} + +static int create_bufs_ioctl(int fd, unsigned long int cmd, + struct v4l2_create_buffers *arg) +{ + struct v4l2_format fmt = { 0 }; + struct v4l2_format *org = &arg->format; + int ret; + + switch (arg->format.type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + break; + default: + return SYS_IOCTL(fd, cmd, &fmt); + } + + fmt.fmt.pix_mp.width = org->fmt.pix.width; + fmt.fmt.pix_mp.height = org->fmt.pix.height; + fmt.fmt.pix_mp.pixelformat = org->fmt.pix.pixelformat; + fmt.fmt.pix_mp.field = org->fmt.pix.field; + fmt.fmt.pix_mp.colorspace = org->fmt.pix.colorspace; + fmt.fmt.pix_mp.num_planes = 1; + fmt.fmt.pix_mp.plane_fmt[0].bytesperline = org->fmt.pix.bytesperline; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = org->fmt.pix.sizeimage; + + ret = SYS_IOCTL(fd, cmd, &arg); + if (ret) + return ret; + + org->fmt.pix.width = fmt.fmt.pix_mp.width; + org->fmt.pix.height = fmt.fmt.pix_mp.height; + org->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat; + org->fmt.pix.field = fmt.fmt.pix_mp.field; + org->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace; + org->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline; + org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + return 0; +} + +static int get_fmt_ioctl(int fd, unsigned long int cmd, struct v4l2_format *arg) +{ + struct v4l2_format fmt = { 0 }; + struct v4l2_format *org = arg; + int ret; + + switch (arg->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + break; + default: + return SYS_IOCTL(fd, cmd, &fmt); + } + + ret = SYS_IOCTL(fd, cmd, &fmt); + if (ret) + return ret; + + org->fmt.pix.width = fmt.fmt.pix_mp.width; + org->fmt.pix.height = fmt.fmt.pix_mp.height; + org->fmt.pix.pixelformat = fmt.fmt.pix_mp.pixelformat; + org->fmt.pix.field = fmt.fmt.pix_mp.field; + org->fmt.pix.colorspace = fmt.fmt.pix_mp.colorspace; + org->fmt.pix.bytesperline = fmt.fmt.pix_mp.plane_fmt[0].bytesperline; + org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + + /* + * If the device doesn't support just one plane, there's + * nothing we can do, except return an error condition. + */ + if (fmt.fmt.pix_mp.num_planes > 1) { + errno = -EINVAL; + return -1; + } + + return ret; +} + +static int buf_ioctl(int fd, unsigned long int cmd, struct v4l2_buffer *arg) +{ + struct v4l2_buffer buf = *arg; + struct v4l2_plane plane = { 0 }; + int ret; + + buf.type = convert_type(arg->type); + + if (buf.type == arg->type) + return SYS_IOCTL(fd, cmd, &buf); + + memcpy(&plane.m, &arg->m, sizeof(plane.m)); + plane.length = arg->length; + plane.bytesused = arg->bytesused; + + buf.m.planes = &plane; + buf.length = 1; + + ret = SYS_IOCTL(fd, cmd, &buf); + + arg->length = plane.length; + arg->bytesused = plane.bytesused; + + return ret; +} + +static int plugin_ioctl(void *dev_ops_priv, int fd, + unsigned long int cmd, void *arg) +{ + struct mplane_plugin *plugin = dev_ops_priv; + switch (cmd) { + case VIDIOC_QUERYCAP: + return querycap_ioctl(fd, cmd, arg); + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + return try_set_fmt_ioctl(fd, cmd, arg); + case VIDIOC_G_FMT: + return get_fmt_ioctl(fd, cmd, arg); + case VIDIOC_ENUM_FMT: + return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_fmtdesc); + case VIDIOC_S_PARM: + case VIDIOC_G_PARM: + return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_streamparm); + case VIDIOC_CROPCAP: + return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_cropcap); + case VIDIOC_S_CROP: + case VIDIOC_G_CROP: + return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_crop); + case VIDIOC_QBUF: + case VIDIOC_DQBUF: + case VIDIOC_QUERYBUF: + case VIDIOC_PREPARE_BUF: + return buf_ioctl(fd, cmd, arg); + case VIDIOC_CREATE_BUFS: + return create_bufs_ioctl(fd, cmd, arg); + case VIDIOC_REQBUFS: + return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_requestbuffers); + case VIDIOC_STREAMON: + case VIDIOC_STREAMOFF: + { + int type, ret; + + /* + * If the device has both capture and output, weird things + * could happen. For now, let's not consider this case. If this + * is ever happens in practice, the logic should be changed to + * track reqbufs, in order to identify what's required. + */ + if (plugin->mplane_capture) { + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ret = SYS_IOCTL(fd, cmd, &type); + } else if (plugin->mplane_output) { + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ret = SYS_IOCTL(fd, cmd, &type); + } else { + ret = -1; + errno = EINVAL; + } + + return ret; + } + /* CASE VIDIOC_EXPBUF: */ + default: + return SYS_IOCTL(fd, cmd, arg); + } +} + +PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = { + .init = &plugin_init, + .close = &plugin_close, + .ioctl = &plugin_ioctl, +}; diff --git a/lib/libv4l-mplane/libv4l-mplane.pc.in b/lib/libv4l-mplane/libv4l-mplane.pc.in new file mode 100644 index 0000000..c41bbad --- /dev/null +++ b/lib/libv4l-mplane/libv4l-mplane.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libv4l2plugindir@ + +Name: libv4l-mplane +Description: libv4l plugin for multiplane handling +Version: @PACKAGE_VERSION@ +Libs: -L${libv4l2plugindir} -lv4l-mplane +Libs.private: -lpthread +Cflags: -I${includedir} _______________________________________________ linuxtv-commits mailing list [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits
