[FFmpeg-devel] [PATCH 2/2] v4l2: allow to set device controls.

Giorgio Vazzana mywing81 at gmail.com
Thu Mar 28 12:56:03 CET 2013


2013/3/27 Nicolas George <nicolas.george at normalesup.org>:
> Address trac ticket #2305.

Hi, thanks for working on this.

> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
>  doc/indevs.texi    |    4 ++
>  libavdevice/v4l2.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 132 insertions(+)
>
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index 63104e2..6c09979 100644
> --- a/doc/indevs.texi
> +++ b/doc/indevs.texi
> @@ -699,6 +699,10 @@ Force conversion from monotonic to absolute timestamps.
>  @end table
>
>  Default value is @code{default}.
> +
> + at item controls
> +Set device controls. The argument is a list of @code{@var{key}=@var{value}}
> +pairs separated by @code{:}.
>  @end table
>
>  @section vfwcap
> diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
> index 7a6388a..3c147c4 100644
> --- a/libavdevice/v4l2.c
> +++ b/libavdevice/v4l2.c
> @@ -121,6 +121,7 @@ struct video_data {
>      int list_format;    /**< Set by a private option. */
>      int list_standard;  /**< Set by a private option. */
>      char *framerate;    /**< Set by a private option. */

> +    char *controls;

nit: maybe use the same comment as above? "/**< Set by a private option. */"

>  };
>
>  struct buff_data {
> @@ -709,6 +710,127 @@ static void mmap_close(struct video_data *s)
>      av_free(s->buf_len);
>  }
>
> +static int add_control(struct v4l2_queryctrl **allctrls, unsigned *nb_ctrls,
> +                       struct v4l2_queryctrl *qctrl)
> +{
> +    char *name, *cur, *var;
> +
> +    (*nb_ctrls)++;
> +    if (!(*nb_ctrls & (*nb_ctrls - 1))) {
> +        *allctrls = av_realloc_f(*allctrls, sizeof(**allctrls),
> +                                 (*nb_ctrls << 1) - 1);
> +        if (!*allctrls)
> +            return AVERROR(ENOMEM);
> +    }
> +    (*allctrls)[*nb_ctrls - 1] = *qctrl;
> +    qctrl = &(*allctrls)[*nb_ctrls - 1];
> +
> +    /* "Control Name" -> "control_name", similar to name2var from v4l-utils */
> +    for (name = cur = var = qctrl->name; *cur; cur++) {
> +        unsigned c = *cur;
> +        if ((c | 0x20) - 'a' < 26 || c - '0' < 10) {
> +            *(var++) = av_tolower(*cur);
> +        } else {
> +            if (var > name && var[-1] != '_')
> +                *(var++) = '_';
> +        }
> +    }
> +    while (var > name && var[-1] == '_')
> +        var--;
> +    *var = 0;
> +
> +    return 0;
> +}
> +
> +static int set_controls(AVFormatContext *s1)
> +{
> +    struct video_data *s = s1->priv_data;
> +    struct v4l2_queryctrl qctrl, *allctrls = NULL;
> +    struct v4l2_ext_control extctrl;
> +    struct v4l2_ext_controls extctrls;
> +    unsigned nb_ctrls = 0, i;
> +    const char *opt = s->controls;
> +    char *ctrl, *val, *tail;
> +    long long vall;
> +    int ret;
> +
> +    memset(&qctrl, 0, sizeof(qctrl));
> +    qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
> +    while (1) {

> +        if (ioctl(s->fd, VIDIOC_QUERYCTRL, &qctrl) < 0)

"v4l2_ioctl" instead of "ioctl" to make libv4l2 happy :)

> +            break;
> +        if ((ret = add_control(&allctrls, &nb_ctrls, &qctrl)) < 0)
> +            goto fail;
> +        qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
> +    }
> +
> +    while (*opt) {
> +        ret = av_opt_get_key_value(&opt, "=", ":", 0, &ctrl, &val);
> +        if (ret < 0) {
> +            av_log(s1, AV_LOG_ERROR, "Error in controls string near '%s': %s\n",
> +                   opt, av_err2str(ret));
> +            goto fail;
> +        }
> +        for (i = 0; i < nb_ctrls; i++)
> +            if (!strcmp(ctrl, allctrls[i].name))
> +                break;
> +        if (i >= nb_ctrls) {
> +            av_log(s1, AV_LOG_ERROR, "Unknown control '%s'\n", ctrl);
> +            ret = AVERROR(EINVAL);
> +            goto fail;
> +        }
> +        av_log(s1, AV_LOG_VERBOSE, "Setting control %s to '%s'\n", ctrl, val);
> +        memset(&extctrl, 0, sizeof(extctrl));
> +        extctrl.id = allctrls[i].id;
> +        switch (allctrls[i].type) {
> +        case V4L2_CTRL_TYPE_INTEGER:
> +        case V4L2_CTRL_TYPE_BOOLEAN:
> +        case V4L2_CTRL_TYPE_MENU:
> +        case V4L2_CTRL_TYPE_BUTTON:

> +        case V4L2_CTRL_TYPE_BITMASK:

V4L2_CTRL_TYPE_BITMASK was added in linux 3.1, I get an error here on
2.6.32. Maybe add something like:

#ifdef V4L2_CTRL_TYPE_BITMASK
        case V4L2_CTRL_TYPE_BITMASK:
#endif

> +        case V4L2_CTRL_TYPE_INTEGER64:
> +            vall = strtoll(val, &tail, 0);
> +            if (*tail) {
> +                av_log(s1, AV_LOG_ERROR, "Invalid numeric value '%s'\n", val);
> +                ret = AVERROR(EINVAL);
> +                goto fail;
> +            }
> +            if (allctrls[i].type == V4L2_CTRL_TYPE_INTEGER64)
> +                extctrl.value64 = vall;
> +            else
> +                extctrl.value   = vall;
> +            break;
> +        case V4L2_CTRL_TYPE_STRING:
> +            extctrl.size = strlen(val) + 1;
> +            extctrl.string = val;
> +            break;
> +        default:
> +            av_log(s1, AV_LOG_ERROR, "Unknown type for control '%s'\n", ctrl);
> +            ret = AVERROR(EIO);
> +            goto fail;
> +        }
> +        memset(&extctrls, 0, sizeof(extctrls));
> +        extctrls.ctrl_class = 0;
> +        extctrls.count      = 1;
> +        extctrls.controls   = &extctrl;

> +        if (ioctl(s->fd, VIDIOC_S_EXT_CTRLS, &extctrls) < 0) {

"v4l2_ioctl" instead of "ioctl".

> +            ret = AVERROR(errno);
> +            av_log(s1, AV_LOG_ERROR, "Error setting control %s to '%s': %s\n",
> +                   ctrl, val, av_err2str(ret));
> +            goto fail;
> +        }
> +        av_freep(&ctrl);
> +        av_freep(&val);
> +        opt += !!*opt;
> +    }
> +
> +fail:
> +    av_freep(&ctrl);
> +    av_freep(&val);
> +    av_freep(&allctrls);
> +    return ret;
> +}
> +
>  static int v4l2_set_parameters(AVFormatContext *s1)
>  {
>      struct video_data *s = s1->priv_data;
> @@ -815,6 +937,10 @@ static int v4l2_set_parameters(AVFormatContext *s1)
>      s1->streams[0]->avg_frame_rate.den = tpf->numerator;
>      s1->streams[0]->r_frame_rate = s1->streams[0]->avg_frame_rate;
>
> +    if (s->controls)
> +        if ((ret = set_controls(s1)) < 0)
> +            return ret;
> +
>      return 0;
>  }
>
> @@ -1074,6 +1200,8 @@ static const AVOption options[] = {
>      { "abs",          "use absolute timestamps (wall clock)",                     OFFSET(ts_mode),      AV_OPT_TYPE_CONST,  {.i64 = V4L_TS_ABS      }, 0, 2, DEC, "timestamps" },
>      { "mono2abs",     "force conversion from monotonic to absolute timestamps",   OFFSET(ts_mode),      AV_OPT_TYPE_CONST,  {.i64 = V4L_TS_MONO2ABS }, 0, 2, DEC, "timestamps" },
>
> +    { "controls",     "set device controls",                                      OFFSET(controls),     AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC },
> +
>      { NULL },
>  };
>
> --

The rest would LGTM, except that I cannot compile it:

holden at rye:~/src/ffmpeg$ uname -a
Linux rye 2.6.32-46-generic #105-Ubuntu SMP Fri Mar 1 00:04:17 UTC
2013 x86_64 GNU/Linux

holden at rye:~/src/ffmpeg$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

holden at rye:~/src/ffmpeg$ make V=0
gcc -I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64
-D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600
-DHAVE_AV_CONFIG_H -std=c99 -fomit-frame-pointer -pthread
-I/usr/local/include/opus -D_GNU_SOURCE=1 -D_REENTRANT
-I/usr/include/SDL -g -Wdeclaration-after-statement -Wall
-Wno-parentheses -Wno-switch -Wno-format-zero-length
-Wdisabled-optimization -Wpointer-arith -Wredundant-decls
-Wno-pointer-sign -Wwrite-strings -Wtype-limits -Wundef
-Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -O3
-fno-math-errno -fno-signed-zeros -fno-tree-vectorize
-Werror=implicit-function-declaration -Werror=missing-prototypes
-Werror=return-type -Werror=vla  -MMD -MF libavdevice/v4l2.d -MT
libavdevice/v4l2.o -c -o libavdevice/v4l2.o libavdevice/v4l2.c
libavdevice/v4l2.c: In function ‘mmap_read_frame’:
libavdevice/v4l2.c:632: warning: ‘destruct’ is deprecated (declared at
./libavcodec/avcodec.h:1064)
libavdevice/v4l2.c: In function ‘set_controls’:
libavdevice/v4l2.c:790: error: ‘V4L2_CTRL_TYPE_BITMASK’ undeclared
(first use in this function)
libavdevice/v4l2.c:790: error: (Each undeclared identifier is reported only once
libavdevice/v4l2.c:790: error: for each function it appears in.)
libavdevice/v4l2.c:799: error: ‘struct v4l2_ext_control’ has no member
named ‘value64’
libavdevice/v4l2.c:801: error: ‘struct v4l2_ext_control’ has no member
named ‘value’
libavdevice/v4l2.c:805: error: ‘struct v4l2_ext_control’ has no member
named ‘string’
make: *** [libavdevice/v4l2.o] Errore 1

I see we're using -std=c99, but I think anonymous unions are not
supported in c99?

holden at rye:~/tmp$ cat v4l2_control.c
#include <stdio.h>
#include <linux/videodev2.h>

int main()
{
	struct v4l2_ext_control ec;

	ec.id      = 0;
	ec.size    = 0;
	ec.value   = 0;
	ec.value64 = 0;
	ec.string  = NULL;

	return 0;
}

holden at rye:~/tmp$ gcc -Wall -std=c99 v4l2_control.c
v4l2_control.c: In function ‘main’:
v4l2_control.c:10: error: ‘struct v4l2_ext_control’ has no member named ‘value’
v4l2_control.c:11: error: ‘struct v4l2_ext_control’ has no member
named ‘value64’
v4l2_control.c:12: error: ‘struct v4l2_ext_control’ has no member named ‘string’

holden at rye:~/tmp$ gcc -Wall -std=gnu89 v4l2_control.c

Giorgio Vazzana


More information about the ffmpeg-devel mailing list