[PATCH v6] v4l2.c: a decoder for Video4Linux video-input ioctls args

Philippe De Muyter phdm at macqel.be
Fri Oct 10 11:15:23 UTC 2014


* v4l2.c, xlat/v4l2_*.in: new files.
* configure.ac: check for availabilty of v4l2 enum constants.
* ioctl.c, defs.h, Makefile.am: hook v4l2.o:v4l2_ioctl into strace.
* NEWS: spread the news :)

Introduce v4l2.c, a decoder for the arguments of the video-input subset of the
v4l2 ioctl's.
This is a combination of
- previous work by Peter Zotov <whitequark at whitequark.org>, found at
  https://gist.githubusercontent.com/whitequark/1263207/raw/strace-4.6-v4l2-ioctls.patch
- previous work by William Manley <will at williammanley.net>, found at
  http://marc.info/?l=strace&m=139395588520675&w=2
- forward port, additions and fixes by Philippe De Muyter <phdm at macqel.be>

As v4l2 is a moving target, I have made v4l2.c compilable with ancient linux
kernels by testing the availability of some macros.  It as been succesfully
compiled on linux 3.10, 3.1, 2.6.31 and 2.6.22, and succesfully used on
linux 3.10 with a camera device.

Signed-off-by: Philippe De Muyter <phdm at macqel.be>
Cc: Peter Zotov <whitequark at whitequark.org>
Cc: William Manley <will at williammanley.net>

---
v6:
- for VIDIOC_DQBUF, print 'index' when exiting, not when entering.
- fix compilation warnings reported by gcc -Wsign-compare
v5:
- add timestamp field in VIDIOC_DQBUF's arg decoding
- add braces around decoding of VIDIOC_QUERYCTRL's arg
v4:
- fix thinko in VIDIOC_G_FMT decoding
- add symbolic names for some deprecated (but used) V4L2_CID_* constants
- add VIDIOC_S_INPUT support

 Makefile.am                            |   1 +
 configure.ac                           |  57 ++++
 defs.h                                 |   1 +
 ioctl.c                                |   3 +
 v4l2.c                                 | 592 +++++++++++++++++++++++++++++++++
 xlat/v4l2_buf_flags.in                 |   8 +
 xlat/v4l2_buf_types.in                 |  10 +
 xlat/v4l2_capture_modes.in             |   1 +
 xlat/v4l2_colorspaces.in               |   8 +
 xlat/v4l2_control_classes.in           |   9 +
 xlat/v4l2_control_flags.in             |   8 +
 xlat/v4l2_control_ids.in               |  77 +++++
 xlat/v4l2_control_types.in             |   9 +
 xlat/v4l2_device_capabilities_flags.in |  23 ++
 xlat/v4l2_fields.in                    |  10 +
 xlat/v4l2_format_description_flags.in  |   2 +
 xlat/v4l2_frameinterval_types.in       |   3 +
 xlat/v4l2_framesize_types.in           |   3 +
 xlat/v4l2_input_types.in               |   2 +
 xlat/v4l2_memories.in                  |   2 +
 xlat/v4l2_streaming_capabilities.in    |   1 +
 21 files changed, 830 insertions(+)
 create mode 100644 v4l2.c
 create mode 100644 xlat/v4l2_buf_flags.in
 create mode 100644 xlat/v4l2_buf_types.in
 create mode 100644 xlat/v4l2_capture_modes.in
 create mode 100644 xlat/v4l2_colorspaces.in
 create mode 100644 xlat/v4l2_control_classes.in
 create mode 100644 xlat/v4l2_control_flags.in
 create mode 100644 xlat/v4l2_control_ids.in
 create mode 100644 xlat/v4l2_control_types.in
 create mode 100644 xlat/v4l2_device_capabilities_flags.in
 create mode 100644 xlat/v4l2_fields.in
 create mode 100644 xlat/v4l2_format_description_flags.in
 create mode 100644 xlat/v4l2_frameinterval_types.in
 create mode 100644 xlat/v4l2_framesize_types.in
 create mode 100644 xlat/v4l2_input_types.in
 create mode 100644 xlat/v4l2_memories.in
 create mode 100644 xlat/v4l2_streaming_capabilities.in

diff --git a/Makefile.am b/Makefile.am
index 703f4da..2477e99 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -56,6 +56,7 @@ strace_SOURCES =	\
 	term.c		\
 	time.c		\
 	util.c		\
+	v4l2.c		\
 	vsprintf.c
 
 if USE_LIBUNWIND
diff --git a/configure.ac b/configure.ac
index 9caa835..54e9941 100644
--- a/configure.ac
+++ b/configure.ac
@@ -627,6 +627,63 @@ AC_CHECK_DECLS(m4_normalize([
 [#include <sys/types.h>
 #include <linux/sysctl.h>])
 
+AC_CHECK_DECLS(m4_normalize([
+	V4L2_FIELD_ANY,
+	V4L2_FIELD_NONE,
+	V4L2_FIELD_TOP,
+	V4L2_FIELD_BOTTOM,
+	V4L2_FIELD_INTERLACED,
+	V4L2_FIELD_SEQ_TB,
+	V4L2_FIELD_SEQ_BT,
+	V4L2_FIELD_ALTERNATE,
+	V4L2_FIELD_INTERLACED_TB,
+	V4L2_FIELD_INTERLACED_BT,
+	V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+	V4L2_BUF_TYPE_VIDEO_OVERLAY,
+	V4L2_BUF_TYPE_VBI_CAPTURE,
+	V4L2_BUF_TYPE_VBI_OUTPUT,
+	V4L2_BUF_TYPE_SLICED_VBI_CAPTURE,
+	V4L2_BUF_TYPE_SLICED_VBI_OUTPUT,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
+	V4L2_TUNER_RADIO,
+	V4L2_TUNER_ANALOG_TV,
+	V4L2_TUNER_DIGITAL_TV,
+	V4L2_MEMORY_MMAP,
+	V4L2_MEMORY_USERPTR,
+	V4L2_MEMORY_OVERLAY,
+	V4L2_MEMORY_DMABUF,
+	V4L2_COLORSPACE_SMPTE170M,
+	V4L2_COLORSPACE_SMPTE240M,
+	V4L2_COLORSPACE_REC709,
+	V4L2_COLORSPACE_BT878,
+	V4L2_COLORSPACE_470_SYSTEM_M,
+	V4L2_COLORSPACE_470_SYSTEM_BG,
+	V4L2_COLORSPACE_JPEG,
+	V4L2_COLORSPACE_SRGB,
+	V4L2_PRIORITY_UNSET,
+	V4L2_PRIORITY_BACKGROUND,
+	V4L2_PRIORITY_INTERACTIVE,
+	V4L2_PRIORITY_RECORD,
+	V4L2_FRMSIZE_TYPE_DISCRETE,
+	V4L2_FRMSIZE_TYPE_CONTINUOUS,
+	V4L2_FRMSIZE_TYPE_STEPWISE,
+	V4L2_FRMIVAL_TYPE_DISCRETE,
+	V4L2_FRMIVAL_TYPE_CONTINUOUS,
+	V4L2_FRMIVAL_TYPE_STEPWISE,
+	V4L2_CTRL_TYPE_INTEGER,
+	V4L2_CTRL_TYPE_BOOLEAN,
+	V4L2_CTRL_TYPE_MENU,
+	V4L2_CTRL_TYPE_BUTTON,
+	V4L2_CTRL_TYPE_INTEGER64,
+	V4L2_CTRL_TYPE_CTRL_CLASS,
+	V4L2_CTRL_TYPE_STRING,
+	V4L2_CTRL_TYPE_BITMASK,
+	V4L2_CTRL_TYPE_INTEGER_MENU
+]),,, [#include <linux/videodev2.h>])
+
 AC_CACHE_CHECK([for BLKGETSIZE64], [ac_cv_have_blkgetsize64],
 	[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
 #include <stdlib.h>
diff --git a/defs.h b/defs.h
index 5bfeb6b..bd683d3 100644
--- a/defs.h
+++ b/defs.h
@@ -721,6 +721,7 @@ extern int proc_ioctl(struct tcb *, int, int);
 extern int rtc_ioctl(struct tcb *, long, long);
 extern int scsi_ioctl(struct tcb *, long, long);
 extern int block_ioctl(struct tcb *, long, long);
+extern int v4l2_ioctl(struct tcb *, unsigned long, long);
 extern int mtd_ioctl(struct tcb *, long, long);
 extern int ubi_ioctl(struct tcb *, long, long);
 extern int loop_ioctl(struct tcb *, long, long);
diff --git a/ioctl.c b/ioctl.c
index b5b71ee..f5fa319 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -103,6 +103,8 @@ ioctl_decode(struct tcb *tcp, long code, long arg)
 	case 'o':
 	case 'O':
 		return ubi_ioctl(tcp, code, arg);
+	case 'V':
+		return v4l2_ioctl(tcp, code, arg);
 	case '=':
 		return ptp_ioctl(tcp, code, arg);
 	default:
@@ -155,6 +157,7 @@ ioctl_decode(struct tcb *tcp, long code, long arg)
  *   t	sys/ttycom.h			(possible overlap)
  *   v	sundev/vuid_event.h		*overlap*
  *   v	sys/vcmd.h			*overlap*
+ *   V	linux/videodev2.h
  *
  * End of Registry
  */
diff --git a/v4l2.c b/v4l2.c
new file mode 100644
index 0000000..69da173
--- /dev/null
+++ b/v4l2.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2014 Philippe De Muyter <phdm at macqel.be>
+ * Copyright (c) 2014 William Manley <will at williammanley.net>
+ * Copyright (c) 2011 Peter Zotov <whitequark at whitequark.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+/* some historical constants */
+#ifndef V4L2_CID_HCENTER
+#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
+#endif
+#ifndef V4L2_CID_VCENTER
+#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
+#endif
+#ifndef V4L2_CID_BAND_STOP_FILTER
+#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
+#endif
+
+#include "xlat/v4l2_device_capabilities_flags.h"
+#include "xlat/v4l2_buf_types.h"
+#include "xlat/v4l2_buf_flags.h"
+#include "xlat/v4l2_framesize_types.h"
+#include "xlat/v4l2_frameinterval_types.h"
+#include "xlat/v4l2_fields.h"
+#include "xlat/v4l2_colorspaces.h"
+#include "xlat/v4l2_format_description_flags.h"
+#include "xlat/v4l2_memories.h"
+#include "xlat/v4l2_control_ids.h"
+#include "xlat/v4l2_control_types.h"
+#include "xlat/v4l2_control_flags.h"
+#include "xlat/v4l2_control_classes.h"
+#include "xlat/v4l2_streaming_capabilities.h"
+#include "xlat/v4l2_capture_modes.h"
+#include "xlat/v4l2_input_types.h"
+
+#define FMT_FRACT "%u/%u"
+#define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
+
+#define FMT_RECT "{left=%i, top=%i, width=%i, height=%i}"
+#define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
+
+static void print_pixelformat(uint32_t fourcc)
+{
+#if WORDS_BIGENDIAN
+	fourcc = htole32(fourcc);
+#endif
+	tprintf("%.4s", (char*)&fourcc);
+}
+
+static void print_v4l2_format_fmt(const struct v4l2_format *f)
+{
+	tprints("fmt.");
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
+		const struct v4l2_pix_format *pix = &f->fmt.pix;
+
+		tprintf("pix={width=%u, height=%u, pixelformat=",
+			pix->width, pix->height);
+		print_pixelformat(pix->pixelformat);
+		tprints(", field=");
+		printxval(v4l2_fields, pix->field, "V4L2_FIELD_???");
+		tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
+			pix->bytesperline, pix->sizeimage);
+		printxval(v4l2_colorspaces, pix->colorspace,
+			  "V4L2_COLORSPACE_???");
+		tprints("}");
+		break;
+	}
+#if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
+		const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+		int i;
+
+		tprintf("pix_mp={width=%u, height=%u, pixelformat=",
+			pix_mp->width, pix_mp->height);
+		print_pixelformat(pix_mp->pixelformat);
+		tprints(", field=");
+		printxval(v4l2_fields, pix_mp->field, "V4L2_FIELD_???");
+		tprints(", colorspace=");
+		printxval(v4l2_colorspaces, pix_mp->colorspace,
+			  "V4L2_COLORSPACE_???");
+		tprints("plane_fmt=[");
+		for (i = 0; i < pix_mp->num_planes; i++) {
+			if (i > 0)
+				tprints(", ");
+			tprintf("{sizeimage=%u, bytesperline=%u}",
+				pix_mp->plane_fmt[i].sizeimage,
+				pix_mp->plane_fmt[i].bytesperline);
+		}
+		tprintf("], num_planes=%u}", (unsigned) pix_mp->num_planes);
+		break;
+	}
+#endif
+
+	/* TODO: Complete this switch statement */
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+		tprints("win={???}");
+		break;
+
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+		tprints("vbi={???}");
+		break;
+
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		tprints("sliced={???}");
+		break;
+
+	default:
+		tprints("???");
+		break;
+	}
+}
+
+int
+v4l2_ioctl(struct tcb *tcp, unsigned long code, long arg)
+{
+	if (!verbose(tcp))
+		return 0;
+
+	switch (code) {
+	case VIDIOC_QUERYCAP: /* decode on exit */ {
+		struct v4l2_capability caps;
+
+		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &caps) < 0)
+			return 0;
+		tprintf(", {driver=\"%s\", card=\"%s\", bus_info=\"%s\", "
+			"version=%u.%u.%u, capabilities=", caps.driver, caps.card,
+			caps.bus_info, (caps.version >> 16) & 0xFF,
+			(caps.version >> 8) & 0xFF, caps.version & 0xFF);
+		printflags(v4l2_device_capabilities_flags, caps.capabilities,
+			   "V4L2_CAP_???");
+#ifdef V4L2_CAP_DEVICE_CAPS
+		tprints(", device_caps=");
+		printflags(v4l2_device_capabilities_flags, caps.device_caps,
+			   "V4L2_CAP_???");
+#endif
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FRAMESIZES: /* decode on exit */ {
+		struct v4l2_frmsizeenum s;
+
+		if (entering(tcp) || umove(tcp, arg, &s) < 0)
+			return 0;
+		tprintf(", {index=%u, pixel_format=", s.index);
+		print_pixelformat(s.pixel_format);
+
+		if (!syserror(tcp)) {
+			tprints(", type=");
+			printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
+			switch (s.type) {
+			case V4L2_FRMSIZE_TYPE_DISCRETE:
+				tprintf(", discrete={width=%u, height=%u}",
+					s.discrete.width, s.discrete.height);
+				break;
+			case V4L2_FRMSIZE_TYPE_STEPWISE:
+				tprintf(", stepwise={min_width=%u, max_width=%u, "
+					"step_width=%u, min_height=%u, max_height=%u, "
+					"step_height=%u}",
+					s.stepwise.min_width, s.stepwise.max_width,
+					s.stepwise.step_width, s.stepwise.min_height,
+					s.stepwise.max_height, s.stepwise.step_height);
+				break;
+			}
+		}
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_G_FMT:
+	case VIDIOC_S_FMT:
+	case VIDIOC_TRY_FMT: {
+		struct v4l2_format f;
+
+		if (umove(tcp, arg, &f) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprints(", {type=");
+			printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
+		}
+		if ((entering(tcp) && code != VIDIOC_G_FMT)
+		|| (exiting(tcp) && !syserror(tcp))) {
+			tprints(exiting(tcp) && code != VIDIOC_G_FMT ? " => " : ", ");
+			print_v4l2_format_fmt(&f);
+		}
+		if (exiting(tcp))
+			tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FMT: {
+		struct v4l2_fmtdesc f;
+
+		if (entering(tcp) || umove(tcp, arg, &f) < 0)
+			return 0;
+
+		tprintf(", {index=%u", f.index);
+		if (!syserror(tcp)) {
+			tprints(", type=");
+			printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
+			tprints(", flags=");
+			printflags(v4l2_format_description_flags, f.flags,
+				   "V4L2_FMT_FLAG_???");
+			tprintf(", description=\"%s\", pixelformat=",
+				f.description);
+			print_pixelformat(f.pixelformat);
+		}
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_G_PARM:
+	case VIDIOC_S_PARM: {
+		struct v4l2_streamparm s;
+
+		if (entering(tcp) && code == VIDIOC_G_PARM)
+			return 1;
+		if (exiting(tcp) && syserror(tcp))
+			return code == VIDIOC_S_PARM;
+		if (umove(tcp, arg, &s) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprints(", {type=");
+			printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
+		}
+
+		tprints(exiting(tcp) && code == VIDIOC_S_PARM ? " => {" : ", {");
+		if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			struct v4l2_captureparm *cap = &s.parm.capture;
+
+			tprints("capability=");
+			printflags(v4l2_streaming_capabilities,
+				   cap->capability, "V4L2_CAP_???");
+
+			tprints(", capturemode=");
+			printflags(v4l2_capture_modes,
+				   cap->capturemode, "V4L2_MODE_???");
+
+			tprintf(", timeperframe=" FMT_FRACT,
+				ARGS_FRACT(cap->timeperframe));
+
+			tprintf(", extendedmode=%u, readbuffers=%u",
+				cap->extendedmode,
+				cap->readbuffers);
+		} else
+			tprints("...");
+		tprints("}");
+		if (exiting(tcp))
+			tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_QUERYCTRL: {
+		struct v4l2_queryctrl c;
+
+		if (umove(tcp, arg, &c) < 0)
+			return 0;
+		/* 'id' field must be printed :
+		* on enter
+		* on exit if !syserror(tcp) && V4L2_CTRL_FLAG_NEXT_CTRL was set
+		*/
+		if (entering(tcp)
+		|| (exiting(tcp) && tcp->auxstr && !syserror(tcp))) {
+			tprints(exiting(tcp) ? " => " : ", {id=");
+			tcp->auxstr = (char*)(c.id & V4L2_CTRL_FLAG_NEXT_CTRL);
+			if (tcp->auxstr) {
+				tprints("V4L2_CTRL_FLAG_NEXT_CTRL|");
+				c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
+			}
+			printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+		}
+		if (exiting(tcp)) {
+			if (!syserror(tcp)) {
+				tprints(", type=");
+				printxval(v4l2_control_types, c.type,
+					  "V4L2_CTRL_TYPE_???");
+				tprintf(", name=\"%s\", minimum=%i, maximum=%i, step=%i, "
+					"default_value=%i, flags=",
+					c.name, c.minimum, c.maximum,
+					c.step, c.default_value);
+				printflags(v4l2_control_flags, c.flags,
+					   "V4L2_CTRL_FLAG_???");
+			}
+			tprints("}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL: {
+		struct v4l2_control c;
+
+		if (entering(tcp) || umove(tcp, arg, &c) < 0)
+			return 0;
+		tprints(", {id=");
+		printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+		if (!syserror(tcp) || code != VIDIOC_G_CTRL)
+			tprintf(", value=%i", c.value);
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS: {
+		struct v4l2_ext_controls c;
+		unsigned n;
+		bool must_print_values;
+
+		if (umove(tcp, arg, &c) < 0)
+			return 0;
+		if (entering(tcp) && code == VIDIOC_G_EXT_CTRLS)
+			return 0;
+		if (exiting(tcp) && syserror(tcp) && code != VIDIOC_G_EXT_CTRLS)
+			return 0;
+		if ((entering(tcp) && code != VIDIOC_G_EXT_CTRLS)
+		|| (exiting(tcp) && !syserror(tcp)))
+			must_print_values = 1;
+		else
+			must_print_values = 0;
+		tprints(code != VIDIOC_G_EXT_CTRLS && exiting(tcp) ? " => " : ", ");
+		tprints("{ctrl_class=");
+		printxval(v4l2_control_classes, c.ctrl_class,
+			  "V4L2_CTRL_CLASS_???");
+		tprintf(", count=%u", c.count);
+		if (exiting(tcp) && syserror(tcp))
+			tprintf(", error_idx=%u", c.error_idx);
+		tprints(", controls=[");
+		for (n = 0; n < c.count; ++n) {
+			struct v4l2_ext_control ctrl;
+
+			if (n > 0)
+				tprints(", ");
+			if (umove(tcp, (long) (c.controls + n), &ctrl) < 0)
+				break;
+			if (abbrev(tcp) && n == 2) {
+				tprints("...");
+				break;
+			}
+			tprints("{id=");
+			printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
+#if HAVE_DECL_V4L2_CTRL_TYPE_STRING
+			tprintf(", size=%u", ctrl.size);
+			if (ctrl.size > 0) {
+				if (must_print_values) {
+					tprints(", string=");
+					printstr(tcp, (long) ctrl.string, ctrl.size);
+				}
+			} else
+#endif
+			{
+				if (must_print_values) {
+					tprintf(", value=%i, value64=%lli", ctrl.value,
+						ctrl.value64);
+				}
+			}
+			tprints("}");
+		}
+		tprints("]}");
+		return 1;
+	}
+
+	case VIDIOC_ENUMSTD: {
+		struct v4l2_standard s;
+
+		if (umove(tcp, arg, &s) < 0)
+			return 0;
+		if (entering(tcp))
+			tprintf(", {index=%i", s.index);
+		else {
+			if (!syserror(tcp)) {
+				tprintf(", name=\"%s\"", s.name);
+				tprintf(", frameperiod=" FMT_FRACT, ARGS_FRACT(s.frameperiod));
+				tprintf(", framelines=%i", s.framelines);
+			}
+			tprints("}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD: {
+		v4l2_std_id s;
+
+		if (code == VIDIOC_G_STD && exiting(tcp) && syserror(tcp))
+			return 0;
+		if (umove(tcp, arg, &s) < 0)
+			return 0;
+		if ((code == VIDIOC_S_STD) == entering(tcp))
+			tprintf(", std=%#llx", s);
+		return 1;
+	}
+
+	case VIDIOC_ENUMINPUT: {
+		struct v4l2_input i;
+
+		if (entering(tcp) || umove(tcp, arg, &i) < 0)
+			return 0;
+		tprintf(", {index=%i", i.index);
+		if (!syserror(tcp)) {
+			tprintf(", name=\"%s\", type=", i.name);
+			printxval(v4l2_input_types, i.type,
+				  "V4L2_INPUT_TYPE_???");
+		}
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_G_INPUT:
+	case VIDIOC_S_INPUT: {
+		int index;
+
+		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &index) < 0)
+			return 0;
+
+		tprintf(", index=%i", index);
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FRAMEINTERVALS: {
+		struct v4l2_frmivalenum f;
+
+		if (entering(tcp) || umove(tcp, arg, &f) < 0)
+			return 0;
+		tprintf(", {index=%i, pixel_format=", f.index);
+		print_pixelformat(f.pixel_format);
+		tprintf(", width=%u, height=%u", f.width, f.height);
+		if (!syserror(tcp)) {
+			tprints(", type=");
+			printxval(v4l2_frameinterval_types, f.type,
+				  "V4L2_FRMIVAL_TYPE_???");
+			switch (f.type) {
+			case V4L2_FRMIVAL_TYPE_DISCRETE:
+				tprintf(", discrete=" FMT_FRACT,
+					ARGS_FRACT(f.discrete));
+				break;
+			case V4L2_FRMIVAL_TYPE_STEPWISE:
+			case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+				tprintf(", stepwise={min=" FMT_FRACT ", max="
+					FMT_FRACT ", step=" FMT_FRACT "}",
+					ARGS_FRACT(f.stepwise.min),
+					ARGS_FRACT(f.stepwise.max),
+					ARGS_FRACT(f.stepwise.step));
+				break;
+			}
+		}
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_CROPCAP: {
+		struct v4l2_cropcap c;
+
+		if (entering(tcp) || umove(tcp, arg, &c) < 0)
+			return 0;
+		tprints(", type=");
+		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
+		if (syserror(tcp))
+			return 1;
+		tprintf(", bounds=" FMT_RECT ", defrect=" FMT_RECT ", "
+			"pixelaspect=" FMT_FRACT, ARGS_RECT(c.bounds),
+			ARGS_RECT(c.defrect), ARGS_FRACT(c.pixelaspect));
+		return 1;
+	}
+
+	case VIDIOC_G_FBUF:
+	case VIDIOC_S_FBUF: {
+		struct v4l2_framebuffer b;
+
+		if (entering(tcp) || umove(tcp, arg, &b) < 0)
+			return 0;
+		if (syserror(tcp) && code == VIDIOC_G_FBUF)
+			return 0;
+		tprintf(", {capability=%x", b.capability);
+		tprintf(", flags=%x", b.flags);
+		tprintf(", base=%p", b.base);
+		tprints("}");
+		return 1;
+	}
+
+	case VIDIOC_REQBUFS: {
+		struct v4l2_requestbuffers reqbufs;
+
+		if (umove(tcp, arg, &reqbufs) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprintf(", {count=%u, type=", reqbufs.count);
+			printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
+			tprints(", memory=");
+			printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
+			tprints("}");
+			return 1;
+		} else if (syserror(tcp))
+			return 1;
+		else {
+			static char outstr[32];
+
+			sprintf(outstr, "{count=%u}", reqbufs.count);
+			tcp->auxstr = outstr;
+			return 1 + RVAL_STR;
+		}
+	}
+
+	case VIDIOC_QUERYBUF:
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF: {
+		struct v4l2_buffer b;
+
+		if (umove(tcp, arg, &b) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprints(", {type=");
+			printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
+			if (code != VIDIOC_DQBUF)
+				tprintf(", index=%u", b.index);
+		} else {
+			if (!syserror(tcp)) {
+				if (code == VIDIOC_DQBUF)
+					tprintf(", index=%u", b.index);
+				tprints(", memory=");
+				printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
+
+				if (b.memory == V4L2_MEMORY_MMAP) {
+					tprintf(", m.offset=%#x", b.m.offset);
+				} else if (b.memory == V4L2_MEMORY_USERPTR) {
+					tprintf(", m.userptr=%#lx", b.m.userptr);
+				}
+
+				tprintf(", length=%u, bytesused=%u, flags=",
+					b.length, b.bytesused);
+				printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
+				if (code == VIDIOC_DQBUF)
+					tprintf(", timestamp = {%lu.%06lu}",
+						b.timestamp.tv_sec,
+						b.timestamp.tv_usec);
+				tprints(", ...");
+			}
+			tprints("}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF: {
+		int type;
+
+		if (umove(tcp, arg, &type) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprints(", ");
+			printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
+		}
+		return 1;
+	}
+
+	default: /* decode on exit */
+		return 0;
+	}
+}
diff --git a/xlat/v4l2_buf_flags.in b/xlat/v4l2_buf_flags.in
new file mode 100644
index 0000000..ba7e86e
--- /dev/null
+++ b/xlat/v4l2_buf_flags.in
@@ -0,0 +1,8 @@
+V4L2_BUF_FLAG_MAPPED
+V4L2_BUF_FLAG_QUEUED
+V4L2_BUF_FLAG_DONE
+V4L2_BUF_FLAG_KEYFRAME
+V4L2_BUF_FLAG_PFRAME
+V4L2_BUF_FLAG_BFRAME
+V4L2_BUF_FLAG_TIMECODE
+V4L2_BUF_FLAG_INPUT
diff --git a/xlat/v4l2_buf_types.in b/xlat/v4l2_buf_types.in
new file mode 100644
index 0000000..431cb59
--- /dev/null
+++ b/xlat/v4l2_buf_types.in
@@ -0,0 +1,10 @@
+V4L2_BUF_TYPE_VIDEO_CAPTURE
+V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+V4L2_BUF_TYPE_VIDEO_OUTPUT
+V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+V4L2_BUF_TYPE_VIDEO_OVERLAY
+V4L2_BUF_TYPE_VBI_CAPTURE
+V4L2_BUF_TYPE_VBI_OUTPUT
+V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
+V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
+V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
diff --git a/xlat/v4l2_capture_modes.in b/xlat/v4l2_capture_modes.in
new file mode 100644
index 0000000..4730764
--- /dev/null
+++ b/xlat/v4l2_capture_modes.in
@@ -0,0 +1 @@
+V4L2_MODE_HIGHQUALITY
diff --git a/xlat/v4l2_colorspaces.in b/xlat/v4l2_colorspaces.in
new file mode 100644
index 0000000..961e71c
--- /dev/null
+++ b/xlat/v4l2_colorspaces.in
@@ -0,0 +1,8 @@
+V4L2_COLORSPACE_SMPTE170M
+V4L2_COLORSPACE_SMPTE240M
+V4L2_COLORSPACE_REC709
+V4L2_COLORSPACE_BT878
+V4L2_COLORSPACE_470_SYSTEM_M
+V4L2_COLORSPACE_470_SYSTEM_BG
+V4L2_COLORSPACE_JPEG
+V4L2_COLORSPACE_SRGB
diff --git a/xlat/v4l2_control_classes.in b/xlat/v4l2_control_classes.in
new file mode 100644
index 0000000..5666a06
--- /dev/null
+++ b/xlat/v4l2_control_classes.in
@@ -0,0 +1,9 @@
+V4L2_CTRL_CLASS_USER
+V4L2_CTRL_CLASS_MPEG
+V4L2_CTRL_CLASS_CAMERA
+V4L2_CTRL_CLASS_FM_TX
+V4L2_CTRL_CLASS_FLASH
+V4L2_CTRL_CLASS_JPEG
+V4L2_CTRL_CLASS_IMAGE_SOURCE
+V4L2_CTRL_CLASS_IMAGE_PROC
+V4L2_CTRL_CLASS_FM_RX
diff --git a/xlat/v4l2_control_flags.in b/xlat/v4l2_control_flags.in
new file mode 100644
index 0000000..18654de
--- /dev/null
+++ b/xlat/v4l2_control_flags.in
@@ -0,0 +1,8 @@
+V4L2_CTRL_FLAG_DISABLED
+V4L2_CTRL_FLAG_GRABBED
+V4L2_CTRL_FLAG_READ_ONLY
+V4L2_CTRL_FLAG_UPDATE
+V4L2_CTRL_FLAG_INACTIVE
+V4L2_CTRL_FLAG_SLIDER
+V4L2_CTRL_FLAG_WRITE_ONLY
+V4L2_CTRL_FLAG_VOLATILE
diff --git a/xlat/v4l2_control_ids.in b/xlat/v4l2_control_ids.in
new file mode 100644
index 0000000..3dee933
--- /dev/null
+++ b/xlat/v4l2_control_ids.in
@@ -0,0 +1,77 @@
+0
+V4L2_CID_BRIGHTNESS
+V4L2_CID_CONTRAST
+V4L2_CID_SATURATION
+V4L2_CID_HUE
+V4L2_CID_AUDIO_VOLUME
+V4L2_CID_AUDIO_BALANCE
+V4L2_CID_AUDIO_BASS
+V4L2_CID_AUDIO_TREBLE
+V4L2_CID_AUDIO_MUTE
+V4L2_CID_AUDIO_LOUDNESS
+V4L2_CID_BLACK_LEVEL
+V4L2_CID_AUTO_WHITE_BALANCE
+V4L2_CID_DO_WHITE_BALANCE
+V4L2_CID_RED_BALANCE
+V4L2_CID_BLUE_BALANCE
+V4L2_CID_GAMMA
+V4L2_CID_WHITENESS
+V4L2_CID_EXPOSURE
+V4L2_CID_AUTOGAIN
+V4L2_CID_GAIN
+V4L2_CID_HFLIP
+V4L2_CID_VFLIP
+V4L2_CID_HCENTER
+V4L2_CID_VCENTER
+V4L2_CID_POWER_LINE_FREQUENCY
+V4L2_CID_HUE_AUTO
+V4L2_CID_WHITE_BALANCE_TEMPERATURE
+V4L2_CID_SHARPNESS
+V4L2_CID_BACKLIGHT_COMPENSATION
+V4L2_CID_CHROMA_AGC
+V4L2_CID_CHROMA_GAIN
+V4L2_CID_COLOR_KILLER
+V4L2_CID_COLORFX
+V4L2_CID_COLORFX_CBCR
+V4L2_CID_AUTOBRIGHTNESS
+V4L2_CID_BAND_STOP_FILTER
+V4L2_CID_ROTATE
+V4L2_CID_BG_COLOR
+V4L2_CID_ILLUMINATORS_1
+V4L2_CID_ILLUMINATORS_2
+V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+V4L2_CID_MIN_BUFFERS_FOR_OUTPUT
+V4L2_CID_ALPHA_COMPONENT
+/*  Camera class control IDs */
+V4L2_CID_EXPOSURE_AUTO
+V4L2_CID_EXPOSURE_ABSOLUTE
+V4L2_CID_EXPOSURE_AUTO_PRIORITY
+V4L2_CID_PAN_RELATIVE
+V4L2_CID_TILT_RELATIVE
+V4L2_CID_PAN_RESET
+V4L2_CID_TILT_RESET
+V4L2_CID_PAN_ABSOLUTE
+V4L2_CID_TILT_ABSOLUTE
+V4L2_CID_FOCUS_ABSOLUTE
+V4L2_CID_FOCUS_RELATIVE
+V4L2_CID_FOCUS_AUTO
+V4L2_CID_ZOOM_ABSOLUTE
+V4L2_CID_ZOOM_RELATIVE
+V4L2_CID_ZOOM_CONTINUOUS
+V4L2_CID_PRIVACY
+V4L2_CID_IRIS_ABSOLUTE
+V4L2_CID_IRIS_RELATIVE
+V4L2_CID_AUTO_EXPOSURE_BIAS
+V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE
+V4L2_CID_WIDE_DYNAMIC_RANGE
+V4L2_CID_IMAGE_STABILIZATION
+V4L2_CID_ISO_SENSITIVITY
+V4L2_CID_ISO_SENSITIVITY_AUTO
+V4L2_CID_EXPOSURE_METERING
+V4L2_CID_SCENE_MODE
+V4L2_CID_3A_LOCK
+V4L2_CID_AUTO_FOCUS_START
+V4L2_CID_AUTO_FOCUS_STOP
+V4L2_CID_AUTO_FOCUS_STATUS
+V4L2_CID_AUTO_FOCUS_RANGE
+V4L2_CID_PRIVATE_BASE
diff --git a/xlat/v4l2_control_types.in b/xlat/v4l2_control_types.in
new file mode 100644
index 0000000..26c587e
--- /dev/null
+++ b/xlat/v4l2_control_types.in
@@ -0,0 +1,9 @@
+V4L2_CTRL_TYPE_INTEGER
+V4L2_CTRL_TYPE_BOOLEAN
+V4L2_CTRL_TYPE_MENU
+V4L2_CTRL_TYPE_INTEGER_MENU
+V4L2_CTRL_TYPE_BITMASK
+V4L2_CTRL_TYPE_BUTTON
+V4L2_CTRL_TYPE_INTEGER64
+V4L2_CTRL_TYPE_STRING
+V4L2_CTRL_TYPE_CTRL_CLASS
diff --git a/xlat/v4l2_device_capabilities_flags.in b/xlat/v4l2_device_capabilities_flags.in
new file mode 100644
index 0000000..6e8502e
--- /dev/null
+++ b/xlat/v4l2_device_capabilities_flags.in
@@ -0,0 +1,23 @@
+V4L2_CAP_VIDEO_CAPTURE
+V4L2_CAP_VIDEO_OUTPUT
+V4L2_CAP_VIDEO_OVERLAY
+V4L2_CAP_VBI_CAPTURE
+V4L2_CAP_VBI_OUTPUT
+V4L2_CAP_SLICED_VBI_CAPTURE
+V4L2_CAP_SLICED_VBI_OUTPUT
+V4L2_CAP_RDS_CAPTURE
+V4L2_CAP_VIDEO_OUTPUT_OVERLAY
+V4L2_CAP_HW_FREQ_SEEK
+V4L2_CAP_RDS_OUTPUT
+V4L2_CAP_VIDEO_CAPTURE_MPLANE
+V4L2_CAP_VIDEO_OUTPUT_MPLANE
+V4L2_CAP_VIDEO_M2M
+V4L2_CAP_VIDEO_M2M_MPLANE
+V4L2_CAP_TUNER
+V4L2_CAP_AUDIO
+V4L2_CAP_RADIO
+V4L2_CAP_MODULATOR
+V4L2_CAP_READWRITE
+V4L2_CAP_ASYNCIO
+V4L2_CAP_STREAMING
+V4L2_CAP_DEVICE_CAPS
diff --git a/xlat/v4l2_fields.in b/xlat/v4l2_fields.in
new file mode 100644
index 0000000..60d00e1
--- /dev/null
+++ b/xlat/v4l2_fields.in
@@ -0,0 +1,10 @@
+V4L2_FIELD_ANY
+V4L2_FIELD_NONE
+V4L2_FIELD_TOP
+V4L2_FIELD_BOTTOM
+V4L2_FIELD_INTERLACED
+V4L2_FIELD_SEQ_TB
+V4L2_FIELD_SEQ_BT
+V4L2_FIELD_ALTERNATE
+V4L2_FIELD_INTERLACED_TB
+V4L2_FIELD_INTERLACED_BT
diff --git a/xlat/v4l2_format_description_flags.in b/xlat/v4l2_format_description_flags.in
new file mode 100644
index 0000000..ed5a3d3
--- /dev/null
+++ b/xlat/v4l2_format_description_flags.in
@@ -0,0 +1,2 @@
+V4L2_FMT_FLAG_COMPRESSED
+V4L2_FMT_FLAG_EMULATED
diff --git a/xlat/v4l2_frameinterval_types.in b/xlat/v4l2_frameinterval_types.in
new file mode 100644
index 0000000..30d46d6
--- /dev/null
+++ b/xlat/v4l2_frameinterval_types.in
@@ -0,0 +1,3 @@
+V4L2_FRMIVAL_TYPE_DISCRETE
+V4L2_FRMIVAL_TYPE_CONTINUOUS
+V4L2_FRMIVAL_TYPE_STEPWISE
diff --git a/xlat/v4l2_framesize_types.in b/xlat/v4l2_framesize_types.in
new file mode 100644
index 0000000..5eb2b83
--- /dev/null
+++ b/xlat/v4l2_framesize_types.in
@@ -0,0 +1,3 @@
+V4L2_FRMSIZE_TYPE_DISCRETE
+V4L2_FRMSIZE_TYPE_CONTINUOUS
+V4L2_FRMSIZE_TYPE_STEPWISE
diff --git a/xlat/v4l2_input_types.in b/xlat/v4l2_input_types.in
new file mode 100644
index 0000000..e05a5fe
--- /dev/null
+++ b/xlat/v4l2_input_types.in
@@ -0,0 +1,2 @@
+V4L2_INPUT_TYPE_TUNER
+V4L2_INPUT_TYPE_CAMERA
diff --git a/xlat/v4l2_memories.in b/xlat/v4l2_memories.in
new file mode 100644
index 0000000..e592d57
--- /dev/null
+++ b/xlat/v4l2_memories.in
@@ -0,0 +1,2 @@
+V4L2_MEMORY_MMAP
+V4L2_MEMORY_USERPTR
diff --git a/xlat/v4l2_streaming_capabilities.in b/xlat/v4l2_streaming_capabilities.in
new file mode 100644
index 0000000..1ae5e15
--- /dev/null
+++ b/xlat/v4l2_streaming_capabilities.in
@@ -0,0 +1 @@
+V4L2_CAP_TIMEPERFRAME
-- 
1.8.4.5





More information about the Strace-devel mailing list