[FFmpeg-devel] [PATCH] v4l2: allow to set device controls.
Giorgio Vazzana
mywing81 at gmail.com
Fri Apr 26 09:49:19 CEST 2013
2013/4/25 Nicolas George <nicolas.george at normalesup.org>:
> Address trac ticket #2305.
>
> Somme trickery is necessary to support gcc < 4.6
> (used in Debian stable at the time of this commit)
> and older versions of the v4l2 API without proper
> version macros.
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> doc/indevs.texi | 4 ++
> libavdevice/v4l2.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 146 insertions(+)
>
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index 5e8d215..2a51a73 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 34e3d9c..553ea79 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; /**< Set by a private option. */
> };
>
> struct buff_data {
> @@ -707,6 +708,141 @@ 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 (v4l2_ioctl(s->fd, VIDIOC_QUERYCTRL, &qctrl) < 0)
> + 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:
> +#ifdef V4L2_CTRL_CLASS_FLASH /* hack V4L2_CTRL_TYPE_BITMASK is an enum,
> + V4L2_CTRL_CLASS_FLASH was added just after */
> + 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)
> +#if AV_GCC_VERSION_AT_LEAST(4,6)
> + extctrl.value64 = vall;
> +#else
> + /* gcc < 4.6 does not support unnamed structures declared in
> + headers in c99 mode, access the field hackishly, hoping
> + the layout does not change soon */
> + *(__s64 *)(&extctrl.reserved2 + 1) = vall;
> +#endif
> + else
> +#if AV_GCC_VERSION_AT_LEAST(4,6)
> + extctrl.value = vall;
> +#else
> + *(__s32 *)(&extctrl.reserved2 + 1) = vall;
> +#endif
> + break;
> + case V4L2_CTRL_TYPE_STRING:
> + extctrl.size = strlen(val) + 1;
> + extctrl.string = val;
I suppose the same trick should be used with extctrl.string, on Ubuntu
10.04 I still get:
$ 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:630: warning: ‘destruct’ is deprecated (declared at
./libavcodec/avcodec.h:1076)
libavdevice/v4l2.c: In function ‘set_controls’:
libavdevice/v4l2.c:817: error: ‘struct v4l2_ext_control’ has no member
named ‘string’
make: *** [libavdevice/v4l2.o] Errore 1
Giorgio Vazzana
More information about the ffmpeg-devel
mailing list