1 /*****************************************************************************
2 * controls.c : Video4Linux2 device controls for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2011 VLC authors and VideoLAN
6 * Authors: Benjamin Pracht <bigben at videolan dot org>
7 * Richard Hosking <richard at hovis dot net>
8 * Antoine Cellerier <dionoea at videolan d.t org>
9 * Dennis Lou <dlou99 at yahoo dot com>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
34 #include <sys/ioctl.h>
36 #include <vlc_common.h>
40 typedef struct vlc_v4l2_ctrl_name
44 } vlc_v4l2_ctrl_name_t
;
46 /* NOTE: must be sorted by ID */
47 static const vlc_v4l2_ctrl_name_t controls
[] =
49 { "brightness", V4L2_CID_BRIGHTNESS
},
50 { "contrast", V4L2_CID_CONTRAST
},
51 { "saturation", V4L2_CID_SATURATION
},
52 { "hue", V4L2_CID_HUE
},
53 { "audio-volume", V4L2_CID_AUDIO_VOLUME
},
54 { "audio-balance", V4L2_CID_AUDIO_BALANCE
},
55 { "audio-bass", V4L2_CID_AUDIO_BASS
},
56 { "audio-treble", V4L2_CID_AUDIO_TREBLE
},
57 { "audio-mute", V4L2_CID_AUDIO_MUTE
},
58 { "audio-loudness", V4L2_CID_AUDIO_LOUDNESS
},
59 { "auto-white-balance", V4L2_CID_AUTO_WHITE_BALANCE
},
60 { "do-white-balance", V4L2_CID_DO_WHITE_BALANCE
},
61 { "red-balance", V4L2_CID_RED_BALANCE
},
62 { "blue-balance", V4L2_CID_BLUE_BALANCE
},
63 { "gamma", V4L2_CID_GAMMA
},
64 { "autogain", V4L2_CID_AUTOGAIN
},
65 { "gain", V4L2_CID_GAIN
},
66 { "hflip", V4L2_CID_HFLIP
},
67 { "vflip", V4L2_CID_VFLIP
},
68 { "power-line-frequency", V4L2_CID_POWER_LINE_FREQUENCY
},
69 { "hue-auto", V4L2_CID_HUE_AUTO
},
70 { "white-balance-temperature", V4L2_CID_WHITE_BALANCE_TEMPERATURE
},
71 { "sharpness", V4L2_CID_SHARPNESS
},
72 { "backlight-compensation", V4L2_CID_BACKLIGHT_COMPENSATION
},
73 { "chroma-gain-auto", V4L2_CID_CHROMA_AGC
},
74 { "color-killer", V4L2_CID_COLOR_KILLER
},
75 { "color-effect", V4L2_CID_COLORFX
},
76 { "rotate", V4L2_CID_ROTATE
},
77 { "bg-color", V4L2_CID_BG_COLOR
}, // NOTE: output only
78 { "chroma-gain", V4L2_CID_CHROMA_GAIN
},
79 { "brightness-auto", V4L2_CID_AUTOBRIGHTNESS
},
80 { "band-stop-filter", V4L2_CID_BAND_STOP_FILTER
},
82 { "illuminators-1", V4L2_CID_ILLUMINATORS_1
}, // NOTE: don't care?
83 { "illuminators-2", V4L2_CID_ILLUMINATORS_2
},
84 #define CTRL_CID_KNOWN(cid) \
85 ((((uint32_t)cid) - V4L2_CID_BRIGHTNESS) \
86 <= (V4L2_CID_BAND_STOP_FILTER - V4L2_CID_BRIGHTNESS))
95 int32_t default_value
;
96 struct vlc_v4l2_ctrl
*next
;
99 static int ControlSet (const vlc_v4l2_ctrl_t
*c
, int_fast32_t value
)
101 struct v4l2_control ctrl
= {
105 if (v4l2_ioctl (c
->fd
, VIDIOC_S_CTRL
, &ctrl
) < 0)
110 static int ControlSet64 (const vlc_v4l2_ctrl_t
*c
, int64_t value
)
112 struct v4l2_ext_control ext_ctrl
= {
116 ext_ctrl
.value64
= value
;
117 struct v4l2_ext_controls ext_ctrls
= {
118 .ctrl_class
= V4L2_CTRL_ID2CLASS(c
->id
),
121 .controls
= &ext_ctrl
,
124 if (v4l2_ioctl (c
->fd
, VIDIOC_S_EXT_CTRLS
, &ext_ctrls
) < 0)
129 static int ControlSetStr (const vlc_v4l2_ctrl_t
*c
, const char *restrict value
)
131 struct v4l2_ext_control ext_ctrl
= {
133 .size
= strlen (value
) + 1,
135 ext_ctrl
.string
= (char *)value
;
136 struct v4l2_ext_controls ext_ctrls
= {
137 .ctrl_class
= V4L2_CTRL_ID2CLASS(c
->id
),
140 .controls
= &ext_ctrl
,
143 if (v4l2_ioctl (c
->fd
, VIDIOC_S_EXT_CTRLS
, &ext_ctrls
) < 0)
148 static int ControlSetCallback (vlc_object_t
*obj
, const char *var
,
149 vlc_value_t old
, vlc_value_t cur
, void *data
)
151 const vlc_v4l2_ctrl_t
*ctrl
= data
;
156 case V4L2_CTRL_TYPE_INTEGER
:
157 case V4L2_CTRL_TYPE_MENU
:
158 case V4L2_CTRL_TYPE_BITMASK
:
159 case V4L2_CTRL_TYPE_INTEGER_MENU
:
160 ret
= ControlSet (ctrl
, cur
.i_int
);
162 case V4L2_CTRL_TYPE_BOOLEAN
:
163 ret
= ControlSet (ctrl
, cur
.b_bool
);
165 case V4L2_CTRL_TYPE_BUTTON
:
166 ret
= ControlSet (ctrl
, 0);
168 case V4L2_CTRL_TYPE_INTEGER64
:
169 ret
= ControlSet64 (ctrl
, cur
.i_int
);
171 case V4L2_CTRL_TYPE_STRING
:
172 ret
= ControlSetStr (ctrl
, cur
.psz_string
);
175 vlc_assert_unreachable ();
180 msg_Err (obj
, "cannot set control %s: %s", var
, vlc_strerror_c(errno
));
187 static void ControlsReset (vlc_object_t
*obj
, vlc_v4l2_ctrl_t
*list
)
193 case V4L2_CTRL_TYPE_INTEGER
:
194 case V4L2_CTRL_TYPE_MENU
:
195 case V4L2_CTRL_TYPE_INTEGER_MENU
:
196 var_SetInteger (obj
, list
->name
, list
->default_value
);
198 case V4L2_CTRL_TYPE_BOOLEAN
:
199 var_SetBool (obj
, list
->name
, list
->default_value
);
207 static int ControlsResetCallback (vlc_object_t
*obj
, const char *var
,
208 vlc_value_t old
, vlc_value_t cur
, void *data
)
210 ControlsReset (obj
, data
);
211 (void) var
; (void) old
; (void) cur
;
215 static void ControlsSetFromString (vlc_object_t
*obj
,
216 const vlc_v4l2_ctrl_t
*list
)
218 char *buf
= var_InheritString (obj
, CFG_PREFIX
"set-ctrls");
226 char *end
= strchr (p
, '}');
230 while (p
!= NULL
&& *p
)
232 const char *name
, *value
;
234 p
+= strspn (p
, ", ");
236 end
= strchr (p
, ',');
239 p
= end
; /* next name/value pair */
241 end
= strchr (name
, '=');
244 /* TODO? support button controls that way? */
245 msg_Err (obj
, "syntax error in \"%s\": missing '='", name
);
251 for (const vlc_v4l2_ctrl_t
*c
= list
; c
!= NULL
; c
= c
->next
)
252 if (!strcasecmp (name
, c
->name
))
255 case V4L2_CTRL_TYPE_INTEGER
:
256 case V4L2_CTRL_TYPE_BOOLEAN
:
257 case V4L2_CTRL_TYPE_MENU
:
258 case V4L2_CTRL_TYPE_INTEGER_MENU
:
260 long val
= strtol (value
, &end
, 0);
263 msg_Err (obj
, "syntax error in \"%s\": "
264 " not an integer", value
);
271 case V4L2_CTRL_TYPE_INTEGER64
:
273 long long val
= strtoll (value
, &end
, 0);
276 msg_Err (obj
, "syntax error in \"%s\": "
277 " not an integer", value
);
280 ControlSet64 (c
, val
);
284 case V4L2_CTRL_TYPE_STRING
:
285 ControlSetStr (c
, value
);
288 case V4L2_CTRL_TYPE_BITMASK
:
290 unsigned long val
= strtoul (value
, &end
, 0);
293 msg_Err (obj
, "syntax error in \"%s\": "
294 " not an integer", value
);
302 msg_Err (obj
, "setting \"%s\" not supported", name
);
306 msg_Err (obj
, "control \"%s\" not available", name
);
311 static int cidcmp (const void *a
, const void *b
)
313 const uint32_t *id
= a
;
314 const vlc_v4l2_ctrl_name_t
*name
= b
;
316 return (int32_t)(*id
- name
->cid
);
320 * Creates a VLC-V4L2 control structure:
321 * In particular, determines a name suitable for a VLC object variable.
322 * \param query V4L2 control query structure [IN]
323 * \return NULL on error
325 static vlc_v4l2_ctrl_t
*ControlCreate (int fd
,
326 const struct v4l2_queryctrl
*query
)
328 vlc_v4l2_ctrl_t
*ctrl
= malloc (sizeof (*ctrl
));
329 if (unlikely(ctrl
== NULL
))
333 ctrl
->id
= query
->id
;
334 ctrl
->type
= query
->type
;
336 /* Search for a well-known control */
337 const vlc_v4l2_ctrl_name_t
*known
;
338 known
= bsearch (&query
->id
, controls
, sizeof (controls
) / sizeof (*known
),
339 sizeof (*known
), cidcmp
);
341 strcpy (ctrl
->name
, known
->name
);
343 /* Fallback to automatically-generated control name */
346 for (i
= 0; query
->name
[i
]; i
++)
348 unsigned char c
= query
->name
[i
];
349 if (c
== ' ' || c
== ',')
355 ctrl
->name
[i
] = '\0';
358 ctrl
->default_value
= query
->default_value
;
363 #define CTRL_FLAGS_IGNORE \
364 (V4L2_CTRL_FLAG_DISABLED /* not implemented at all */ \
365 |V4L2_CTRL_FLAG_READ_ONLY /* value is constant */ \
366 |V4L2_CTRL_FLAG_VOLATILE /* value is (variable but) read-only */)
368 static vlc_v4l2_ctrl_t
*ControlAddInteger (vlc_object_t
*obj
, int fd
,
369 const struct v4l2_queryctrl
*query
)
371 msg_Dbg (obj
, " integer %s (%08"PRIX32
")", query
->name
, query
->id
);
372 if (query
->flags
& CTRL_FLAGS_IGNORE
)
375 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
376 if (unlikely(c
== NULL
))
379 if (var_Create (obj
, c
->name
, VLC_VAR_INTEGER
| VLC_VAR_ISCOMMAND
))
386 struct v4l2_control ctrl
= { .id
= query
->id
};
388 if (v4l2_ioctl (fd
, VIDIOC_G_CTRL
, &ctrl
) >= 0)
390 msg_Dbg (obj
, " current: %3"PRId32
", default: %3"PRId32
,
391 ctrl
.value
, query
->default_value
);
392 val
.i_int
= ctrl
.value
;
393 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
395 var_Change (obj
, c
->name
, VLC_VAR_SETMINMAX
,
396 (vlc_value_t
){ .i_int
= query
->minimum
},
397 (vlc_value_t
){ .i_int
= query
->maximum
} );
398 if (query
->step
!= 1)
400 val
.i_int
= query
->step
;
401 var_Change(obj
, c
->name
, VLC_VAR_SETSTEP
, val
);
406 static vlc_v4l2_ctrl_t
*ControlAddBoolean (vlc_object_t
*obj
, int fd
,
407 const struct v4l2_queryctrl
*query
)
409 msg_Dbg (obj
, " boolean %s (%08"PRIX32
")", query
->name
, query
->id
);
410 if (query
->flags
& CTRL_FLAGS_IGNORE
)
413 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
414 if (unlikely(c
== NULL
))
417 if (var_Create (obj
, c
->name
, VLC_VAR_BOOL
| VLC_VAR_ISCOMMAND
))
424 struct v4l2_control ctrl
= { .id
= query
->id
};
426 if (v4l2_ioctl (fd
, VIDIOC_G_CTRL
, &ctrl
) >= 0)
428 msg_Dbg (obj
, " current: %s, default: %s",
429 ctrl
.value
? " true" : "false",
430 query
->default_value
? " true" : "false");
431 val
.b_bool
= ctrl
.value
;
432 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
437 static vlc_v4l2_ctrl_t
*ControlAddMenu (vlc_object_t
*obj
, int fd
,
438 const struct v4l2_queryctrl
*query
)
440 msg_Dbg (obj
, " menu %s (%08"PRIX32
")", query
->name
, query
->id
);
441 if (query
->flags
& CTRL_FLAGS_IGNORE
)
444 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
445 if (unlikely(c
== NULL
))
448 if (var_Create (obj
, c
->name
, VLC_VAR_INTEGER
| VLC_VAR_ISCOMMAND
))
455 struct v4l2_control ctrl
= { .id
= query
->id
};
457 if (v4l2_ioctl (fd
, VIDIOC_G_CTRL
, &ctrl
) >= 0)
459 msg_Dbg (obj
, " current: %"PRId32
", default: %"PRId32
,
460 ctrl
.value
, query
->default_value
);
461 val
.i_int
= ctrl
.value
;
462 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
464 var_Change (obj
, c
->name
, VLC_VAR_SETMINMAX
,
465 (vlc_value_t
){ .i_int
= query
->minimum
},
466 (vlc_value_t
){ .i_int
= query
->maximum
} );
468 /* Import menu choices */
469 for (uint_fast32_t idx
= query
->minimum
;
470 idx
<= (uint_fast32_t)query
->maximum
;
473 struct v4l2_querymenu menu
= { .id
= query
->id
, .index
= idx
};
475 if (v4l2_ioctl (fd
, VIDIOC_QUERYMENU
, &menu
) < 0)
477 msg_Dbg (obj
, " choice %"PRIu32
") %s", menu
.index
, menu
.name
);
479 val
.i_int
= menu
.index
;
480 var_Change(obj
, c
->name
, VLC_VAR_ADDCHOICE
, val
,
481 (const char *)menu
.name
);
486 static vlc_v4l2_ctrl_t
*ControlAddButton (vlc_object_t
*obj
, int fd
,
487 const struct v4l2_queryctrl
*query
)
489 msg_Dbg (obj
, " button %s (%08"PRIX32
")", query
->name
, query
->id
);
490 if (query
->flags
& CTRL_FLAGS_IGNORE
)
493 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
494 if (unlikely(c
== NULL
))
497 if (var_Create (obj
, c
->name
, VLC_VAR_VOID
| VLC_VAR_ISCOMMAND
))
505 static vlc_v4l2_ctrl_t
*ControlAddInteger64 (vlc_object_t
*obj
, int fd
,
506 const struct v4l2_queryctrl
*query
)
508 msg_Dbg (obj
, " 64-bits %s (%08"PRIX32
")", query
->name
, query
->id
);
509 if (query
->flags
& CTRL_FLAGS_IGNORE
)
512 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
513 if (unlikely(c
== NULL
))
516 if (var_Create (obj
, c
->name
, VLC_VAR_INTEGER
| VLC_VAR_ISCOMMAND
))
522 struct v4l2_ext_control ext_ctrl
= { .id
= c
->id
, .size
= 0, };
523 struct v4l2_ext_controls ext_ctrls
= {
524 .ctrl_class
= V4L2_CTRL_ID2CLASS(c
->id
),
527 .controls
= &ext_ctrl
,
530 if (v4l2_ioctl (c
->fd
, VIDIOC_G_EXT_CTRLS
, &ext_ctrls
) >= 0)
532 vlc_value_t val
= { .i_int
= ext_ctrl
.value64
};
534 msg_Dbg (obj
, " current: %"PRId64
, val
.i_int
);
535 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
541 static vlc_v4l2_ctrl_t
*ControlAddClass (vlc_object_t
*obj
, int fd
,
542 const struct v4l2_queryctrl
*query
)
544 msg_Dbg (obj
, "control class %s:", query
->name
);
549 static vlc_v4l2_ctrl_t
*ControlAddString (vlc_object_t
*obj
, int fd
,
550 const struct v4l2_queryctrl
*query
)
552 msg_Dbg (obj
, " string %s (%08"PRIX32
")", query
->name
, query
->id
);
553 if ((query
->flags
& CTRL_FLAGS_IGNORE
) || query
->maximum
> 65535)
556 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
557 if (unlikely(c
== NULL
))
560 if (var_Create (obj
, c
->name
, VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
))
566 /* Get current value */
567 char *buf
= malloc (query
->maximum
+ 1);
568 if (likely(buf
!= NULL
))
570 struct v4l2_ext_control ext_ctrl
= {
572 .size
= query
->maximum
+ 1,
574 ext_ctrl
.string
= buf
;
575 struct v4l2_ext_controls ext_ctrls
= {
576 .ctrl_class
= V4L2_CTRL_ID2CLASS(c
->id
),
579 .controls
= &ext_ctrl
,
582 if (v4l2_ioctl (c
->fd
, VIDIOC_G_EXT_CTRLS
, &ext_ctrls
) >= 0)
584 vlc_value_t val
= { .psz_string
= buf
};
586 msg_Dbg (obj
, " current: \"%s\"", buf
);
587 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
595 static vlc_v4l2_ctrl_t
*ControlAddBitMask (vlc_object_t
*obj
, int fd
,
596 const struct v4l2_queryctrl
*query
)
598 msg_Dbg (obj
, " bit mask %s (%08"PRIX32
")", query
->name
, query
->id
);
599 if (query
->flags
& CTRL_FLAGS_IGNORE
)
602 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
603 if (unlikely(c
== NULL
))
606 if (var_Create (obj
, c
->name
, VLC_VAR_INTEGER
| VLC_VAR_ISCOMMAND
))
613 struct v4l2_control ctrl
= { .id
= query
->id
};
615 if (v4l2_ioctl (fd
, VIDIOC_G_CTRL
, &ctrl
) >= 0)
617 msg_Dbg (obj
, " current: 0x%08"PRIX32
", default: 0x%08"PRIX32
,
618 ctrl
.value
, query
->default_value
);
619 val
.i_int
= ctrl
.value
;
620 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, val
);
622 var_Change (obj
, c
->name
, VLC_VAR_SETMINMAX
,
623 (vlc_value_t
){ .i_int
= 0 },
624 (vlc_value_t
){ .i_int
= (uint32_t)query
->maximum
} );
628 static vlc_v4l2_ctrl_t
*ControlAddIntMenu (vlc_object_t
*obj
, int fd
,
629 const struct v4l2_queryctrl
*query
)
631 msg_Dbg (obj
, " int menu %s (%08"PRIX32
")", query
->name
, query
->id
);
632 if (query
->flags
& CTRL_FLAGS_IGNORE
)
635 vlc_v4l2_ctrl_t
*c
= ControlCreate (fd
, query
);
636 if (unlikely(c
== NULL
))
639 if (var_Create (obj
, c
->name
, VLC_VAR_INTEGER
| VLC_VAR_ISCOMMAND
))
646 struct v4l2_control ctrl
= { .id
= query
->id
};
648 if (v4l2_ioctl (fd
, VIDIOC_G_CTRL
, &ctrl
) >= 0)
650 msg_Dbg (obj
, " current: %"PRId32
", default: %"PRId32
,
651 ctrl
.value
, query
->default_value
);
652 val
.i_int
= ctrl
.value
;
653 var_Change(obj
, c
->name
, VLC_VAR_SETVALUE
, &val
);
655 var_Change (obj
, c
->name
, VLC_VAR_SETMINMAX
,
656 (vlc_value_t
){ .i_int
= query
->minimum
},
657 (vlc_value_t
){ .i_int
= query
->maximum
} );
659 /* Import menu choices */
660 for (uint_fast32_t idx
= query
->minimum
;
661 idx
<= (uint_fast32_t)query
->maximum
;
664 struct v4l2_querymenu menu
= { .id
= query
->id
, .index
= idx
};
665 char name
[sizeof ("-9223372036854775808")];
667 if (v4l2_ioctl (fd
, VIDIOC_QUERYMENU
, &menu
) < 0)
669 msg_Dbg (obj
, " choice %"PRIu32
") %"PRId64
, menu
.index
,
670 (uint64_t)menu
.value
);
672 val
.i_int
= menu
.index
;
673 sprintf(name
, "%"PRId64
, (int64_t)menu
.value
);
674 var_Change(obj
, c
->name
, VLC_VAR_ADDCHOICE
, val
,
680 static vlc_v4l2_ctrl_t
*ControlAddUnknown (vlc_object_t
*obj
, int fd
,
681 const struct v4l2_queryctrl
*query
)
683 msg_Dbg (obj
, " unknown %s (%08"PRIX32
")", query
->name
, query
->id
);
684 msg_Warn (obj
, " unknown control type %u", (unsigned)query
->type
);
689 typedef vlc_v4l2_ctrl_t
*(*ctrl_type_cb
) (vlc_object_t
*, int,
690 const struct v4l2_queryctrl
*);
693 * Lists all user-class v4l2 controls, sets them to the user specified
694 * value and create the relevant variables to enable run-time changes.
696 vlc_v4l2_ctrl_t
*ControlsInit (vlc_object_t
*obj
, int fd
)
698 /* A list of controls that can be modified at run-time is stored in the
699 * "controls" variable. The V4L2 controls dialog can be built from this. */
700 var_Create (obj
, "controls", VLC_VAR_INTEGER
);
702 static const ctrl_type_cb handlers
[] =
704 [V4L2_CTRL_TYPE_INTEGER
] = ControlAddInteger
,
705 [V4L2_CTRL_TYPE_BOOLEAN
] = ControlAddBoolean
,
706 [V4L2_CTRL_TYPE_MENU
] = ControlAddMenu
,
707 [V4L2_CTRL_TYPE_BUTTON
] = ControlAddButton
,
708 [V4L2_CTRL_TYPE_INTEGER64
] = ControlAddInteger64
,
709 [V4L2_CTRL_TYPE_CTRL_CLASS
] = ControlAddClass
,
710 [V4L2_CTRL_TYPE_STRING
] = ControlAddString
,
711 [V4L2_CTRL_TYPE_BITMASK
] = ControlAddBitMask
,
712 [V4L2_CTRL_TYPE_INTEGER_MENU
] = ControlAddIntMenu
,
715 vlc_v4l2_ctrl_t
*list
= NULL
;
716 struct v4l2_queryctrl query
;
718 query
.id
= V4L2_CTRL_FLAG_NEXT_CTRL
;
719 while (v4l2_ioctl (fd
, VIDIOC_QUERYCTRL
, &query
) >= 0)
721 ctrl_type_cb handler
= NULL
;
722 if (query
.type
< (sizeof (handlers
) / sizeof (handlers
[0])))
723 handler
= handlers
[query
.type
];
725 handler
= ControlAddUnknown
;
727 vlc_v4l2_ctrl_t
*c
= handler (obj
, fd
, &query
);
732 var_AddCallback (obj
, c
->name
, ControlSetCallback
, c
);
733 var_Change(obj
, c
->name
, VLC_VAR_SETTEXT
,
734 (const char *)query
.name
);
735 val
.i_int
= query
.id
;
736 var_Change(obj
, "controls", VLC_VAR_ADDCHOICE
, val
,
737 (const char *)c
->name
);
742 query
.id
|= V4L2_CTRL_FLAG_NEXT_CTRL
;
745 /* Set well-known controls from VLC configuration */
746 for (vlc_v4l2_ctrl_t
*ctrl
= list
; ctrl
!= NULL
; ctrl
= ctrl
->next
)
748 if (!CTRL_CID_KNOWN (ctrl
->id
))
751 char varname
[sizeof (CFG_PREFIX
) + sizeof (ctrl
->name
) - 1];
752 sprintf (varname
, CFG_PREFIX
"%s", ctrl
->name
);
754 int64_t val
= var_InheritInteger (obj
, varname
);
756 continue; /* the VLC default value: "do not modify" */
757 ControlSet (ctrl
, val
); /* NOTE: all known are integers or booleans */
760 /* Set any control from the VLC configuration control string */
761 ControlsSetFromString (obj
, list
);
763 /* Add a control to reset all controls to their default values */
767 var_Create (obj
, "reset", VLC_VAR_VOID
| VLC_VAR_ISCOMMAND
);
768 var_Change(obj
, "reset", VLC_VAR_SETTEXT
, _("Reset defaults"));
771 var_Change(obj
, "controls", VLC_VAR_ADDCHOICE
, val
, "reset");
772 var_AddCallback (obj
, "reset", ControlsResetCallback
, list
);
774 if (var_InheritBool (obj
, CFG_PREFIX
"controls-reset"))
775 ControlsReset (obj
, list
);
780 void ControlsDeinit (vlc_object_t
*obj
, vlc_v4l2_ctrl_t
*list
)
782 var_DelCallback (obj
, "reset", ControlsResetCallback
, list
);
783 var_Destroy (obj
, "reset");
787 vlc_v4l2_ctrl_t
*next
= list
->next
;
789 var_DelCallback (obj
, list
->name
, ControlSetCallback
, list
);
790 var_Destroy (obj
, list
->name
);
795 var_Destroy (obj
, "controls");