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

Dmitry V. Levin ldv at altlinux.org
Sat Nov 1 19:12:29 UTC 2014


Hi,

On Fri, Oct 10, 2014 at 01:15:23PM +0200, Philippe De Muyter wrote:
> * 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.

It's a good decoder, I'm almost ready to merge it, see my comments below.

> 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;

Shouldn't it be "unsigned int"?

> +
> +		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++) {

pix_mp->num_planes may exceed the size of pix_mp->plane_fmt array,
so an additional cap like
	i < ARRAY_SIZE(pix_mp->plane_fmt)
is required.

> +			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))) {

Please fix alignment here to
	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))) {

Please fix alignment here.

> +			tprints(exiting(tcp) ? " => " : ", {id=");
> +			tcp->auxstr = (char*)(c.id & V4L2_CTRL_FLAG_NEXT_CTRL);

This fails to compile with an error:
	cast to pointer from integer of different size [-Werror=int-to-pointer-cast]

> +			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;

Lets write it in full: unsigned int.

> +		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;

Since umove is more expensive, lets move it after cheaper checks.

> +		if ((entering(tcp) && code != VIDIOC_G_EXT_CTRLS)
> +		|| (exiting(tcp) && !syserror(tcp)))
> +			must_print_values = 1;
> +		else
> +			must_print_values = 0;

Since must_print_values is of type bool, please use boolean constants true and false.

> +		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;

Since umove is more expensive, lets move it after cheaper checks.

> +		tprintf(", {capability=%x", b.capability);
> +		tprintf(", flags=%x", b.flags);
> +		tprintf(", base=%p", b.base);
> +		tprints("}");

I think a single tprintf call would be better here.

> +		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];

static char outstr[sizeof("{count=}") + sizeof(int) * 3];

> +
> +			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
> [...]

-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20141101/43668a91/attachment.bin>


More information about the Strace-devel mailing list