add videoctl(1), a tool for displaying or setting parameters on video(4)
devices
This commit is contained in:
parent
d2662cfd92
commit
190912dcf9
|
@ -0,0 +1,8 @@
|
|||
# $NetBSD: Makefile,v 1.1 2010/12/26 10:37:14 jmcneill Exp $
|
||||
|
||||
PROG= videoctl
|
||||
SRCS= videoctl.c
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -0,0 +1,77 @@
|
|||
.\" $NetBSD: videoctl.1,v 1.1 2010/12/26 10:37:15 jmcneill Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
.\" ``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 FOUNDATION OR CONTRIBUTORS
|
||||
.\" 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.
|
||||
.\"
|
||||
.Dd December 26, 2010
|
||||
.Dt VIDEOCTL 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm videoctl
|
||||
.Nd control video device
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d Ar device
|
||||
.Fl a
|
||||
.Nm
|
||||
.Op Fl d Ar device
|
||||
.Ar name ...
|
||||
.Nm
|
||||
.Op Fl d Ar device
|
||||
.Fl w
|
||||
.Ar name=value ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
command displays or sets various video system driver variables. If a list of
|
||||
variables is present on the command line, then
|
||||
.Nm
|
||||
prints the current value of those variables for the specified device.
|
||||
If the
|
||||
.Fl a
|
||||
flag is specified, all variables for the device are printed.
|
||||
If the
|
||||
.Fl w
|
||||
flag is specified
|
||||
.Nm
|
||||
attempts to set the specified variables to the given values.
|
||||
The
|
||||
.Fl d
|
||||
flag can be used to specify an alternate video device. If
|
||||
.Fl d
|
||||
is not specified,
|
||||
.Pa /dev/video0
|
||||
is used.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /dev/video0 -compact
|
||||
.It Pa /dev/video0
|
||||
video device
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr video 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command first appeared in
|
||||
.Nx 6.0 .
|
|
@ -0,0 +1,627 @@
|
|||
/* $NetBSD: videoctl.c,v 1.1 2010/12/26 10:37:15 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``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 FOUNDATION OR CONTRIBUTORS
|
||||
* 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 <sys/cdefs.h>
|
||||
__COPYRIGHT("@(#) Copyright (c) 2010\
|
||||
Jared D. McNeill <jmcneill@invisible.ca>. All rights reserved.");
|
||||
__RCSID("$NetBSD: videoctl.c,v 1.1 2010/12/26 10:37:15 jmcneill Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/videoio.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
|
||||
static void usage(void);
|
||||
static void video_print(const char *);
|
||||
static void video_print_all(void);
|
||||
static bool video_print_caps(const char *);
|
||||
static bool video_print_formats(const char *);
|
||||
static bool video_print_inputs(const char *);
|
||||
static bool video_print_audios(const char *);
|
||||
static bool video_print_standards(const char *);
|
||||
static bool video_print_tuners(const char *);
|
||||
static bool video_print_ctrl(uint32_t);
|
||||
static void video_set(const char *);
|
||||
static bool video_set_ctrl(uint32_t, int32_t);
|
||||
static const char * video_cid2name(uint32_t);
|
||||
static uint32_t video_name2cid(const char *);
|
||||
|
||||
static const char *video_dev = NULL;
|
||||
static int video_fd = -1;
|
||||
static bool aflag = false;
|
||||
static bool wflag = false;
|
||||
|
||||
static const struct {
|
||||
uint32_t id;
|
||||
const char *name;
|
||||
} videoctl_cid_names[] = {
|
||||
{ V4L2_CID_BRIGHTNESS, "brightness" },
|
||||
{ V4L2_CID_CONTRAST, "contrast" },
|
||||
{ V4L2_CID_SATURATION, "saturation" },
|
||||
{ V4L2_CID_HUE, "hue" },
|
||||
{ V4L2_CID_AUDIO_VOLUME, "audio_volume" },
|
||||
{ V4L2_CID_AUDIO_BALANCE, "audio_balance" },
|
||||
{ V4L2_CID_AUDIO_BASS, "audio_bass" },
|
||||
{ V4L2_CID_AUDIO_TREBLE, "audio_treble" },
|
||||
{ V4L2_CID_AUDIO_MUTE, "audio_mute" },
|
||||
{ V4L2_CID_AUDIO_LOUDNESS, "audio_loudness" },
|
||||
{ V4L2_CID_BLACK_LEVEL, "black_level" },
|
||||
{ V4L2_CID_AUTO_WHITE_BALANCE, "auto_white_balance" },
|
||||
{ V4L2_CID_DO_WHITE_BALANCE, "do_white_balance" },
|
||||
{ V4L2_CID_RED_BALANCE, "red_balance" },
|
||||
{ V4L2_CID_BLUE_BALANCE, "blue_balance" },
|
||||
{ V4L2_CID_GAMMA, "gamma" },
|
||||
{ V4L2_CID_WHITENESS, "whiteness" },
|
||||
{ V4L2_CID_EXPOSURE, "exposure" },
|
||||
{ V4L2_CID_AUTOGAIN, "autogain" },
|
||||
{ V4L2_CID_GAIN, "gain" },
|
||||
{ V4L2_CID_HFLIP, "hflip" },
|
||||
{ V4L2_CID_VFLIP, "vflip" },
|
||||
{ V4L2_CID_HCENTER, "hcenter" },
|
||||
{ V4L2_CID_VCENTER, "vcenter" },
|
||||
{ V4L2_CID_POWER_LINE_FREQUENCY, "power_line_frequency" },
|
||||
{ V4L2_CID_HUE_AUTO, "hue_auto" },
|
||||
{ V4L2_CID_WHITE_BALANCE_TEMPERATURE, "white_balance_temperature" },
|
||||
{ V4L2_CID_SHARPNESS, "sharpness" },
|
||||
{ V4L2_CID_BACKLIGHT_COMPENSATION, "backlight_compensation" },
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
while ((ch = getopt(argc, argv, "ad:w")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
aflag = true;
|
||||
break;
|
||||
case 'd':
|
||||
video_dev = strdup(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
wflag = true;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (wflag && aflag)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
if (wflag && argc == 0)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
if (aflag && argc > 0)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
if (!wflag && !aflag && argc == 0)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
|
||||
if (video_dev == NULL)
|
||||
video_dev = _PATH_VIDEO0;
|
||||
|
||||
video_fd = open(video_dev, wflag ? O_RDWR : O_RDONLY);
|
||||
if (video_fd == -1)
|
||||
err(EXIT_FAILURE, "couldn't open '%s'", video_dev);
|
||||
|
||||
if (aflag) {
|
||||
video_print_all();
|
||||
} else if (wflag) {
|
||||
while (argc > 0) {
|
||||
video_set(argv[0]);
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
} else {
|
||||
while (argc > 0) {
|
||||
video_print(argv[0]);
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
}
|
||||
|
||||
close(video_fd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-d file] name ...\n", getprogname());
|
||||
fprintf(stderr, "usage: %s [-d file] -w name=value ...\n",
|
||||
getprogname());
|
||||
fprintf(stderr, "usage: %s [-d file] -a\n", getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
video_print_all(void)
|
||||
{
|
||||
video_print_caps(NULL);
|
||||
video_print_formats(NULL);
|
||||
video_print_inputs(NULL);
|
||||
video_print_audios(NULL);
|
||||
video_print_standards(NULL);
|
||||
video_print_tuners(NULL);
|
||||
video_print_ctrl(0);
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_caps(const char *name)
|
||||
{
|
||||
struct v4l2_capability cap;
|
||||
char capbuf[128];
|
||||
int error;
|
||||
bool found = false;
|
||||
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
|
||||
/* query capabilities */
|
||||
error = ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
|
||||
if (error == -1)
|
||||
err(EXIT_FAILURE, "VIDIOC_QUERYCAP failed");
|
||||
|
||||
if (!name || strcmp(name, "card") == 0) {
|
||||
printf("info.cap.card=%s\n", cap.card);
|
||||
found = true;
|
||||
}
|
||||
if (!name || strcmp(name, "driver") == 0) {
|
||||
printf("info.cap.driver=%s\n", cap.driver);
|
||||
found = true;
|
||||
}
|
||||
if (!name || strcmp(name, "bus_info") == 0) {
|
||||
printf("info.cap.bus_info=%s\n", cap.bus_info);
|
||||
found = true;
|
||||
}
|
||||
if (!name || strcmp(name, "version") == 0) {
|
||||
printf("info.cap.version=%u.%u.%u\n",
|
||||
(cap.version >> 16) & 0xff,
|
||||
(cap.version >> 8) & 0xff,
|
||||
cap.version & 0xff);
|
||||
found = true;
|
||||
}
|
||||
if (!name || strcmp(name, "capabilities") == 0) {
|
||||
snprintb(capbuf, sizeof(capbuf), V4L2_CAP_BITMASK,
|
||||
cap.capabilities);
|
||||
printf("info.cap.capabilities=%s\n", capbuf);
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_formats(const char *name)
|
||||
{
|
||||
struct v4l2_fmtdesc fmtdesc;
|
||||
int error;
|
||||
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (name == NULL) {
|
||||
/* enumerate formats */
|
||||
for (fmtdesc.index = 0; ; fmtdesc.index++) {
|
||||
error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
|
||||
if (error)
|
||||
break;
|
||||
printf("info.format.%u=%s\n", fmtdesc.index,
|
||||
fmtdesc.description);
|
||||
}
|
||||
} else {
|
||||
unsigned long n;
|
||||
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
|
||||
n = strtoul(name, NULL, 10);
|
||||
if (n == ULONG_MAX)
|
||||
return false;
|
||||
fmtdesc.index = n;
|
||||
error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
|
||||
if (error)
|
||||
return false;
|
||||
printf("info.format.%u=%s\n", fmtdesc.index,
|
||||
fmtdesc.description);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_inputs(const char *name)
|
||||
{
|
||||
struct v4l2_input input;
|
||||
int error;
|
||||
|
||||
if (name == NULL) {
|
||||
/* enumerate inputs */
|
||||
for (input.index = 0; ; input.index++) {
|
||||
error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
|
||||
if (error)
|
||||
break;
|
||||
printf("info.input.%u=%s\n", input.index, input.name);
|
||||
printf("info.input.%u.type=", input.index);
|
||||
switch (input.type) {
|
||||
case V4L2_INPUT_TYPE_TUNER:
|
||||
printf("tuner\n");
|
||||
break;
|
||||
case V4L2_INPUT_TYPE_CAMERA:
|
||||
printf("baseband\n");
|
||||
break;
|
||||
default:
|
||||
printf("unknown (%d)\n", input.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned long n;
|
||||
char *s;
|
||||
|
||||
n = strtoul(name, NULL, 10);
|
||||
if (n == ULONG_MAX)
|
||||
return false;
|
||||
input.index = n;
|
||||
error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
s = strtok(NULL, ".");
|
||||
if (s == NULL) {
|
||||
printf("info.input.%u=%s\n", input.index, input.name);
|
||||
} else if (strcmp(s, "type") == 0) {
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
printf("info.input.%u.type=", input.index);
|
||||
switch (input.type) {
|
||||
case V4L2_INPUT_TYPE_TUNER:
|
||||
printf("tuner\n");
|
||||
break;
|
||||
case V4L2_INPUT_TYPE_CAMERA:
|
||||
printf("baseband\n");
|
||||
break;
|
||||
default:
|
||||
printf("unknown (%d)\n", input.type);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_audios(const char *name)
|
||||
{
|
||||
struct v4l2_audio audio;
|
||||
int error;
|
||||
|
||||
if (name == NULL) {
|
||||
/* enumerate audio */
|
||||
for (audio.index = 0; ; audio.index++) {
|
||||
error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
|
||||
if (error)
|
||||
break;
|
||||
printf("info.audio.%u=%s\n", audio.index, audio.name);
|
||||
printf("info.audio.%u.stereo=%d\n", audio.index,
|
||||
audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
|
||||
printf("info.audio.%u.avl=%d\n", audio.index,
|
||||
audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
|
||||
}
|
||||
} else {
|
||||
unsigned long n;
|
||||
char *s;
|
||||
|
||||
n = strtoul(name, NULL, 10);
|
||||
if (n == ULONG_MAX)
|
||||
return false;
|
||||
audio.index = n;
|
||||
error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
s = strtok(NULL, ".");
|
||||
if (s == NULL) {
|
||||
printf("info.audio.%u=%s\n", audio.index, audio.name);
|
||||
} else if (strcmp(s, "stereo") == 0) {
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
printf("info.audio.%u.stereo=%d\n", audio.index,
|
||||
audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
|
||||
} else if (strcmp(s, "avl") == 0) {
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
printf("info.audio.%u.avl=%d\n", audio.index,
|
||||
audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_standards(const char *name)
|
||||
{
|
||||
struct v4l2_standard std;
|
||||
int error;
|
||||
|
||||
if (name == NULL) {
|
||||
/* enumerate standards */
|
||||
for (std.index = 0; ; std.index++) {
|
||||
error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
|
||||
if (error)
|
||||
break;
|
||||
printf("info.standard.%u=%s\n", std.index, std.name);
|
||||
}
|
||||
} else {
|
||||
unsigned long n;
|
||||
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
|
||||
n = strtoul(name, NULL, 10);
|
||||
if (n == ULONG_MAX)
|
||||
return false;
|
||||
std.index = n;
|
||||
error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
|
||||
if (error)
|
||||
return false;
|
||||
printf("info.standard.%u=%s\n", std.index, std.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_tuners(const char *name)
|
||||
{
|
||||
struct v4l2_tuner tuner;
|
||||
int error;
|
||||
|
||||
if (name == NULL) {
|
||||
/* enumerate tuners */
|
||||
for (tuner.index = 0; ; tuner.index++) {
|
||||
error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
|
||||
if (error)
|
||||
break;
|
||||
printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
|
||||
}
|
||||
} else {
|
||||
unsigned long n;
|
||||
|
||||
if (strtok(NULL, ".") != NULL)
|
||||
return false;
|
||||
|
||||
n = strtoul(name, NULL, 10);
|
||||
if (n == ULONG_MAX)
|
||||
return false;
|
||||
tuner.index = n;
|
||||
error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
|
||||
if (error)
|
||||
return false;
|
||||
printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
video_print(const char *name)
|
||||
{
|
||||
char *buf, *s, *s2 = NULL;
|
||||
bool found = false;
|
||||
|
||||
buf = strdup(name);
|
||||
s = strtok(buf, ".");
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
if (strcmp(s, "info") == 0) {
|
||||
s = strtok(NULL, ".");
|
||||
if (s)
|
||||
s2 = strtok(NULL, ".");
|
||||
if (s == NULL || strcmp(s, "cap") == 0) {
|
||||
found = video_print_caps(s2);
|
||||
}
|
||||
if (s == NULL || strcmp(s, "format") == 0) {
|
||||
found = video_print_formats(s2);
|
||||
}
|
||||
if (s == NULL || strcmp(s, "input") == 0) {
|
||||
found = video_print_inputs(s2);
|
||||
}
|
||||
if (s == NULL || strcmp(s, "audio") == 0) {
|
||||
found = video_print_audios(s2);
|
||||
}
|
||||
if (s == NULL || strcmp(s, "standard") == 0) {
|
||||
found = video_print_standards(s2);
|
||||
}
|
||||
if (s == NULL || strcmp(s, "tuner") == 0) {
|
||||
found = video_print_tuners(s2);
|
||||
}
|
||||
} else if (strcmp(s, "ctrl") == 0) {
|
||||
s = strtok(NULL, ".");
|
||||
if (s)
|
||||
s2 = strtok(NULL, ".");
|
||||
|
||||
if (s == NULL)
|
||||
found = video_print_ctrl(0);
|
||||
else if (s && !s2)
|
||||
found = video_print_ctrl(video_name2cid(s));
|
||||
}
|
||||
|
||||
free(buf);
|
||||
if (!found)
|
||||
fprintf(stderr, "%s: field %s does not exist\n",
|
||||
getprogname(), name);
|
||||
}
|
||||
|
||||
static bool
|
||||
video_print_ctrl(uint32_t ctrl_id)
|
||||
{
|
||||
struct v4l2_control ctrl;
|
||||
const char *ctrlname;
|
||||
bool found = false;
|
||||
int error;
|
||||
|
||||
for (ctrl.id = V4L2_CID_BASE; ctrl.id != V4L2_CID_LASTP1; ctrl.id++) {
|
||||
if (ctrl_id != 0 && ctrl_id != ctrl.id)
|
||||
continue;
|
||||
error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
|
||||
if (error)
|
||||
continue;
|
||||
ctrlname = video_cid2name(ctrl.id);
|
||||
if (ctrlname)
|
||||
printf("ctrl.%s=%d\n", ctrlname, ctrl.value);
|
||||
else
|
||||
printf("ctrl.%08x=%d\n", ctrl.id, ctrl.value);
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
video_set(const char *name)
|
||||
{
|
||||
char *buf, *key, *value;
|
||||
bool found = false;
|
||||
long n;
|
||||
|
||||
if (strchr(name, '=') == NULL) {
|
||||
fprintf(stderr, "%s: No '=' in %s\n", getprogname(), name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
buf = strdup(name);
|
||||
key = strtok(buf, "=");
|
||||
if (key == NULL)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
value = strtok(NULL, "");
|
||||
if (value == NULL)
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
|
||||
if (strncmp(key, "info.", strlen("info.")) == 0) {
|
||||
fprintf(stderr, "'info' subtree read-only\n");
|
||||
found = true;
|
||||
goto done;
|
||||
}
|
||||
if (strncmp(key, "ctrl.", strlen("ctrl.")) == 0) {
|
||||
char *ctrlname = key + strlen("ctrl.");
|
||||
uint32_t ctrl_id = video_name2cid(ctrlname);
|
||||
|
||||
n = strtol(value, NULL, 0);
|
||||
if (n == LONG_MIN || n == LONG_MAX)
|
||||
goto done;
|
||||
found = video_set_ctrl(ctrl_id, n);
|
||||
}
|
||||
|
||||
done:
|
||||
free(buf);
|
||||
if (!found)
|
||||
fprintf(stderr, "%s: field %s does not exist\n",
|
||||
getprogname(), name);
|
||||
}
|
||||
|
||||
static bool
|
||||
video_set_ctrl(uint32_t ctrl_id, int32_t value)
|
||||
{
|
||||
struct v4l2_control ctrl;
|
||||
const char *ctrlname;
|
||||
int32_t ovalue;
|
||||
int error;
|
||||
|
||||
ctrlname = video_cid2name(ctrl_id);
|
||||
|
||||
ctrl.id = ctrl_id;
|
||||
error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
|
||||
if (error)
|
||||
return false;
|
||||
ovalue = ctrl.value;
|
||||
ctrl.value = value;
|
||||
error = ioctl(video_fd, VIDIOC_S_CTRL, &ctrl);
|
||||
if (error)
|
||||
err(EXIT_FAILURE, "VIDIOC_S_CTRL failed for '%s'", ctrlname);
|
||||
error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
|
||||
if (error)
|
||||
err(EXIT_FAILURE, "VIDIOC_G_CTRL failed for '%s'", ctrlname);
|
||||
|
||||
if (ctrlname)
|
||||
printf("ctrl.%s: %d -> %d\n", ctrlname, ovalue, ctrl.value);
|
||||
else
|
||||
printf("ctrl.%08x: %d -> %d\n", ctrl.id, ovalue, ctrl.value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *
|
||||
video_cid2name(uint32_t id)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < __arraycount(videoctl_cid_names); i++)
|
||||
if (videoctl_cid_names[i].id == id)
|
||||
return videoctl_cid_names[i].name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
video_name2cid(const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < __arraycount(videoctl_cid_names); i++)
|
||||
if (strcmp(name, videoctl_cid_names[i].name) == 0)
|
||||
return videoctl_cid_names[i].id;
|
||||
|
||||
return (uint32_t)-1;
|
||||
}
|
Loading…
Reference in New Issue