[PATCH] Add (incomplete) decoder for Video4Linux ioctls

William Manley will at williammanley.net
Tue Mar 4 17:41:27 UTC 2014


---
 Makefile.am |   1 +
 defs.h      |   1 +
 ioctl.c     |   2 +
 v4l2.c      | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 533 insertions(+)
 create mode 100644 v4l2.c

diff --git a/Makefile.am b/Makefile.am
index 03d310b..c510463 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,7 @@ strace_SOURCES =	\
 	term.c		\
 	time.c		\
 	util.c		\
+	v4l2.c		\
 	vsprintf.c
 
 noinst_HEADERS = defs.h
diff --git a/defs.h b/defs.h
index f457d30..1f80ea1 100644
--- a/defs.h
+++ b/defs.h
@@ -707,6 +707,7 @@ extern int mtd_ioctl(struct tcb *, long, long);
 extern int ubi_ioctl(struct tcb *, long, long);
 extern int loop_ioctl(struct tcb *, long, long);
 extern int ptp_ioctl(struct tcb *, long, long);
+extern int v4l2_ioctl(struct tcb *, unsigned long, long);
 
 extern int tv_nz(struct timeval *);
 extern int tv_cmp(struct timeval *, struct timeval *);
diff --git a/ioctl.c b/ioctl.c
index 3f6c410..451fe31 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -97,6 +97,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:
diff --git a/v4l2.c b/v4l2.c
new file mode 100644
index 0000000..1a8c436
--- /dev/null
+++ b/v4l2.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2014 William Manley <will at williammanley.net>
+ * 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 <sys/ioctl.h>
+#include <linux/videodev2.h>
+
+static const struct xlat device_capabilities_flags[] = {
+	XLAT(V4L2_CAP_VIDEO_CAPTURE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT),
+	XLAT(V4L2_CAP_VIDEO_OVERLAY),
+	XLAT(V4L2_CAP_VBI_CAPTURE),
+	XLAT(V4L2_CAP_VBI_OUTPUT),
+	XLAT(V4L2_CAP_SLICED_VBI_CAPTURE),
+	XLAT(V4L2_CAP_SLICED_VBI_OUTPUT),
+	XLAT(V4L2_CAP_RDS_CAPTURE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT_OVERLAY),
+	XLAT(V4L2_CAP_HW_FREQ_SEEK),
+	XLAT(V4L2_CAP_RDS_OUTPUT),
+	XLAT(V4L2_CAP_VIDEO_CAPTURE_MPLANE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT_MPLANE),
+	XLAT(V4L2_CAP_VIDEO_M2M),
+	XLAT(V4L2_CAP_VIDEO_M2M_MPLANE),
+	XLAT(V4L2_CAP_TUNER),
+	XLAT(V4L2_CAP_AUDIO),
+	XLAT(V4L2_CAP_RADIO),
+	XLAT(V4L2_CAP_MODULATOR),
+	XLAT(V4L2_CAP_READWRITE),
+	XLAT(V4L2_CAP_ASYNCIO),
+	XLAT(V4L2_CAP_STREAMING),
+	XLAT(V4L2_CAP_DEVICE_CAPS),
+	XLAT_END
+};
+
+static const struct xlat v4l2_formats[] = {
+	XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE),
+	XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ),
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT),
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ),
+	XLAT(V4L2_BUF_TYPE_VIDEO_OVERLAY),
+	XLAT(V4L2_BUF_TYPE_VBI_CAPTURE),
+	XLAT(V4L2_BUF_TYPE_VBI_OUTPUT),
+	XLAT(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE),
+	XLAT(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT),
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY),
+	XLAT_END
+};
+
+static const struct xlat v4l2_framesize_types[] = {
+	XLAT(V4L2_FRMSIZE_TYPE_DISCRETE),
+	XLAT(V4L2_FRMSIZE_TYPE_CONTINUOUS),
+	XLAT(V4L2_FRMSIZE_TYPE_STEPWISE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_frameinterval_types[] = {
+	XLAT(V4L2_FRMIVAL_TYPE_DISCRETE),
+	XLAT(V4L2_FRMIVAL_TYPE_CONTINUOUS),
+	XLAT(V4L2_FRMIVAL_TYPE_STEPWISE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_fields[] = {
+	XLAT(V4L2_FIELD_ANY),
+	XLAT(V4L2_FIELD_NONE),
+	XLAT(V4L2_FIELD_TOP),
+	XLAT(V4L2_FIELD_BOTTOM),
+	XLAT(V4L2_FIELD_INTERLACED),
+	XLAT(V4L2_FIELD_SEQ_TB),
+	XLAT(V4L2_FIELD_SEQ_BT),
+	XLAT(V4L2_FIELD_ALTERNATE),
+	XLAT(V4L2_FIELD_INTERLACED_TB),
+	XLAT(V4L2_FIELD_INTERLACED_BT),
+	XLAT_END
+};
+
+static const struct xlat v4l2_colorspaces[] = {
+	XLAT(V4L2_COLORSPACE_SMPTE170M),
+	XLAT(V4L2_COLORSPACE_SMPTE240M),
+	XLAT(V4L2_COLORSPACE_REC709),
+	XLAT(V4L2_COLORSPACE_BT878),
+	XLAT(V4L2_COLORSPACE_470_SYSTEM_M),
+	XLAT(V4L2_COLORSPACE_470_SYSTEM_BG),
+	XLAT(V4L2_COLORSPACE_JPEG),
+	XLAT(V4L2_COLORSPACE_SRGB),
+	XLAT_END
+};
+
+static const struct xlat v4l2_format_description_flags[] = {
+	XLAT(V4L2_FMT_FLAG_COMPRESSED),
+	XLAT(V4L2_FMT_FLAG_EMULATED),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_ids[] = {
+	XLAT(V4L2_CID_BRIGHTNESS),
+	XLAT(V4L2_CID_CONTRAST),
+	XLAT(V4L2_CID_SATURATION),
+	XLAT(V4L2_CID_HUE),
+	XLAT(V4L2_CID_AUDIO_VOLUME),
+	XLAT(V4L2_CID_AUDIO_BALANCE),
+	XLAT(V4L2_CID_AUDIO_BASS),
+	XLAT(V4L2_CID_AUDIO_TREBLE),
+	XLAT(V4L2_CID_AUDIO_MUTE),
+	XLAT(V4L2_CID_AUDIO_LOUDNESS),
+	XLAT(V4L2_CID_BLACK_LEVEL),
+	XLAT(V4L2_CID_AUTO_WHITE_BALANCE),
+	XLAT(V4L2_CID_DO_WHITE_BALANCE),
+	XLAT(V4L2_CID_RED_BALANCE),
+	XLAT(V4L2_CID_BLUE_BALANCE),
+	XLAT(V4L2_CID_GAMMA),
+	XLAT(V4L2_CID_WHITENESS),
+	XLAT(V4L2_CID_EXPOSURE),
+	XLAT(V4L2_CID_AUTOGAIN),
+	XLAT(V4L2_CID_GAIN),
+	XLAT(V4L2_CID_HFLIP),
+	XLAT(V4L2_CID_VFLIP),
+	XLAT(V4L2_CID_POWER_LINE_FREQUENCY),
+	XLAT(V4L2_CID_HUE_AUTO),
+	XLAT(V4L2_CID_WHITE_BALANCE_TEMPERATURE),
+	XLAT(V4L2_CID_SHARPNESS),
+	XLAT(V4L2_CID_BACKLIGHT_COMPENSATION),
+	XLAT(V4L2_CID_CHROMA_AGC),
+	XLAT(V4L2_CID_CHROMA_GAIN),
+	XLAT(V4L2_CID_COLOR_KILLER),
+	XLAT(V4L2_CID_COLORFX),
+	XLAT(V4L2_CID_COLORFX_CBCR),
+	XLAT(V4L2_CID_AUTOBRIGHTNESS),
+	XLAT(V4L2_CID_ROTATE),
+	XLAT(V4L2_CID_BG_COLOR),
+	XLAT(V4L2_CID_ILLUMINATORS_1),
+	XLAT(V4L2_CID_ILLUMINATORS_2),
+	XLAT(V4L2_CID_MIN_BUFFERS_FOR_CAPTURE),
+	XLAT(V4L2_CID_MIN_BUFFERS_FOR_OUTPUT),
+	XLAT(V4L2_CID_ALPHA_COMPONENT),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_types[] = {
+	XLAT(V4L2_CTRL_TYPE_INTEGER),
+	XLAT(V4L2_CTRL_TYPE_BOOLEAN),
+	XLAT(V4L2_CTRL_TYPE_MENU),
+	XLAT(V4L2_CTRL_TYPE_INTEGER_MENU),
+	XLAT(V4L2_CTRL_TYPE_BITMASK),
+	XLAT(V4L2_CTRL_TYPE_BUTTON),
+	XLAT(V4L2_CTRL_TYPE_INTEGER64),
+	XLAT(V4L2_CTRL_TYPE_STRING),
+	XLAT(V4L2_CTRL_TYPE_CTRL_CLASS),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_flags[] = {
+	XLAT(V4L2_CTRL_FLAG_DISABLED),
+	XLAT(V4L2_CTRL_FLAG_GRABBED),
+	XLAT(V4L2_CTRL_FLAG_READ_ONLY),
+	XLAT(V4L2_CTRL_FLAG_UPDATE),
+	XLAT(V4L2_CTRL_FLAG_INACTIVE),
+	XLAT(V4L2_CTRL_FLAG_SLIDER),
+	XLAT(V4L2_CTRL_FLAG_WRITE_ONLY),
+	XLAT(V4L2_CTRL_FLAG_VOLATILE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_classes[] = {
+	XLAT(V4L2_CTRL_CLASS_USER),
+	XLAT(V4L2_CTRL_CLASS_MPEG),
+	XLAT(V4L2_CTRL_CLASS_CAMERA),
+	XLAT(V4L2_CTRL_CLASS_FM_TX),
+	XLAT(V4L2_CTRL_CLASS_FLASH),
+	XLAT(V4L2_CTRL_CLASS_JPEG),
+	XLAT(V4L2_CTRL_CLASS_IMAGE_SOURCE),
+	XLAT(V4L2_CTRL_CLASS_IMAGE_PROC),
+	XLAT(V4L2_CTRL_CLASS_FM_RX),
+	XLAT_END
+};
+
+#define PRINTF_FOURCC "%c%c%c%c"
+#define FOURCC(x) (char) (x), (char) (x>>8), (char) (x>>16), (char) (x>>24)
+
+#define PRINTF_FRACT "%u/%u"
+#define FRACT(x) ((x).numerator), ((x).denominator)
+
+#define PRINTF_RECT "{left=%i, top=%i, width=%i, height=%i}"
+#define RECT(x) (x).left, (x).top, (x).width, (x).height
+
+static void print_v4l2_format(const struct v4l2_format* fmt)
+{
+	tprintf("type=");
+	printxval(v4l2_formats, fmt->type, "V4L2_BUF_TYPE_???");
+	tprintf(", fmt={");
+	switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			tprintf("pix={width=%u, height=%u, pixelformat=" PRINTF_FOURCC ", "
+			        "field=", fmt->fmt.pix.width, fmt->fmt.pix.height,
+			        FOURCC(fmt->fmt.pix.pixelformat));
+			printxval(v4l2_fields, fmt->fmt.pix.field, "V4L2_FIELD_???");
+			tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
+			        fmt->fmt.pix.bytesperline, fmt->fmt.pix.sizeimage);
+			printxval(v4l2_colorspaces, fmt->fmt.pix.colorspace,
+			          "V4L2_COLORSPACE_???");
+			tprintf("}");
+			break;
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+		{
+			int i;
+			tprintf("pix={width=%u, height=%u, pixelformat=" PRINTF_FOURCC ", "
+			        "field=", fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height,
+			        FOURCC(fmt->fmt.pix_mp.pixelformat));
+			printxval(v4l2_fields, fmt->fmt.pix_mp.field, "V4L2_FIELD_???");
+
+			tprintf(", colorspace=");
+			printxval(v4l2_colorspaces, fmt->fmt.pix_mp.colorspace,
+			          "V4L2_COLORSPACE_???");
+
+			tprintf("plane_fmt=[");
+			for (i=0; i<fmt->fmt.pix_mp.num_planes; i++) {
+				if (i>0)
+					tprintf(", ");
+				tprintf("{sizeimage=%u, bytesperline=%u}",
+				        fmt->fmt.pix_mp.plane_fmt[i].sizeimage,
+				        fmt->fmt.pix_mp.plane_fmt[i].bytesperline);
+			}
+			tprintf("], num_planes=%u", (unsigned) fmt->fmt.pix_mp.num_planes);
+			break;
+		}
+
+		/* TODO: Complete this switch statement */
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+			tprintf("win={???}");
+			break;
+
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+		case V4L2_BUF_TYPE_VBI_OUTPUT:
+			tprintf("vbi={???}");
+			break;
+
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			tprintf("sliced={???}");
+			break;
+		default:
+			tprintf("???");
+			break;
+	}
+	tprintf("}");
+}
+
+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(device_capabilities_flags, caps.capabilities,
+			           "V4L2_CAP_???");
+			tprintf(", device_caps=");
+			printflags(device_capabilities_flags, caps.device_caps,
+			           "V4L2_CAP_???");
+			tprintf(")");
+			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=" PRINTF_FOURCC, s.index,
+			        FOURCC(s.pixel_format));
+
+			if (syserror(tcp))
+				return 1;
+
+			tprintf(", 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;
+			}
+			tprintf(")");
+			return 1;
+		}
+
+		case VIDIOC_G_FMT:
+		{
+			struct v4l2_format f;
+			if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &f) < 0)
+				return 0;
+
+			tprintf(", ");
+			print_v4l2_format(&f);
+			return 1;
+		}
+
+		case VIDIOC_TRY_FMT:
+		case VIDIOC_S_FMT:
+		{
+			/* TODO: work out how strace deals with inout arguments and
+			   implement */
+			return 0;
+		}
+
+		case VIDIOC_ENUM_FMT:
+		{
+			struct v4l2_fmtdesc f;
+
+			if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &f) < 0)
+				return 0;
+
+			tprintf(", index=%u, type=", f.index);
+			printxval(v4l2_formats, f.type, "V4L2_BUF_TYPE_???");
+			tprintf(", flags=");
+			printflags(v4l2_format_description_flags, f.flags,
+			           "V4L2_FMT_FLAG_???");
+			tprintf(", description=\"%s\", pixelformat=" PRINTF_FOURCC,
+			        f.description, FOURCC(f.pixelformat));
+			return 1;
+		}
+
+		case VIDIOC_G_PARM:
+		{
+			struct v4l2_streamparm s;
+
+			if (entering(tcp) || umove(tcp, arg, &s) < 0)
+				return 0;
+
+			tprintf(", type=");
+			printxval(v4l2_formats, s.type, "V4L2_BUF_TYPE_???");
+
+			if (syserror(tcp))
+				return 1;
+
+			/* TODO: Decode struct v4l2_captureparm/v4l2_outputparm */
+			tprintf(", parm={???}");
+			return 1;
+		}
+
+		case VIDIOC_S_PARM:
+		{
+			struct v4l2_streamparm s;
+
+			if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &s) < 0)
+				return 0;
+
+			tprintf(", type=");
+			printxval(v4l2_formats, s.type, "V4L2_BUF_TYPE_???");
+			/* TODO: Decode struct v4l2_captureparm/v4l2_outputparm */
+			tprintf(", parm={???}");
+			return 1;
+		}
+
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl c;
+			if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &c) < 0)
+				return 0;
+
+			tprintf(", ");
+			printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+			tprintf(", 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_???");
+			return 1;
+		}
+
+		case VIDIOC_G_CTRL:
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control c;
+			if (entering(tcp) || umove(tcp, arg, &c) < 0)
+				return 0;
+
+			tprintf(", id=");
+			printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+
+			if (syserror(tcp) && code == VIDIOC_G_CTRL)
+				return 1;
+
+			tprintf(", value=%i", c.value);
+			return 1;
+		}
+
+		case VIDIOC_S_EXT_CTRLS:
+		case VIDIOC_TRY_EXT_CTRLS:
+		case VIDIOC_G_EXT_CTRLS:
+		{
+			struct v4l2_ext_controls c;
+			unsigned n;
+
+			if (entering(tcp) || umove(tcp, arg, &c) < 0)
+				return 0;
+
+			tprintf(", ctrl_class=");
+			printxval(v4l2_control_classes, c.ctrl_class,
+			          "V4L2_CTRL_CLASS_???");
+			tprintf(", count=%u, error_idx=%u, controls=[", c.count,
+			        c.error_idx);
+
+			for (n=0; n<c.count; ++n) {
+				struct v4l2_ext_control ctrl;
+				if (n > 0)
+					tprintf(", ");
+				umove(tcp, (long) (c.controls + n), &ctrl);
+				tprintf("{id=");
+				printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
+				tprintf(", size=%u", ctrl.size);
+				if (ctrl.size > 0) {
+					tprintf(", string=");
+					printstr(tcp, (long) ctrl.string, ctrl.size);
+				}
+				else {
+					tprintf(", value=%i, value64=%lli", ctrl.value,
+					        ctrl.value64);
+				}
+				tprintf("}");
+			}
+			return 1;
+		}
+
+		case VIDIOC_G_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=" PRINTF_FOURCC ", width=%u, "
+			        "height=%u", f.index, FOURCC(f.pixel_format), f.width,
+			        f.height);
+			if (syserror(tcp))
+				return 1;
+			tprintf(", type=");
+			printxval(v4l2_frameinterval_types, f.type,
+			          "V4L2_FRMIVAL_TYPE_???");
+			switch (f.type)
+			{
+				case V4L2_FRMIVAL_TYPE_DISCRETE:
+					tprintf(", discrete=" PRINTF_FRACT, FRACT(f.discrete));
+					break;
+				case V4L2_FRMIVAL_TYPE_STEPWISE:
+					tprintf(", stepwise={min=" PRINTF_FRACT ", max="
+					        PRINTF_FRACT ", step=" PRINTF_FRACT "}",
+					        FRACT(f.stepwise.min), FRACT(f.stepwise.max),
+					        FRACT(f.stepwise.step));
+					break;
+			}
+			return 1;
+		}
+
+		case VIDIOC_CROPCAP:
+		{
+			struct v4l2_cropcap c;
+			if (entering(tcp) || umove(tcp, arg, &c) < 0)
+				return 0;
+
+			tprintf(", type=");
+			printxval(v4l2_formats, c.type, "V4L2_BUF_TYPE_???");
+			if (syserror(tcp))
+				return 1;
+			tprintf(", bounds=" PRINTF_RECT ", defrect=" PRINTF_RECT ", "
+			        "pixelaspect=" PRINTF_FRACT, RECT(c.bounds),
+			        RECT(c.defrect), FRACT(c.pixelaspect));
+			return 1;
+		}
+
+		default: /* decode on exit */
+			return 0;
+	}
+}
-- 
1.9.0





More information about the Strace-devel mailing list