This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/v4l-utils.git tree:
Subject: v4l2-ctl: split up this overly large source. Author: Hans Verkuil <[email protected]> Date: Thu Jul 26 10:32:06 2012 +0200 Phase one: split off the handling of the common options. Signed-off-by: Hans Verkuil <[email protected]> (cherry picked from commit 052dced533310da8e23010b4fe0fa802a0a541f0) Signed-off-by: Gregor Jasny <[email protected]> utils/v4l2-ctl/Makefile | 2 +- utils/v4l2-ctl/v4l2-ctl-common.cpp | 729 ++++++++++++++++++++++++++++++ utils/v4l2-ctl/v4l2-ctl.cpp | 872 ++---------------------------------- utils/v4l2-ctl/v4l2-ctl.h | 174 +++++++ 4 files changed, 935 insertions(+), 842 deletions(-) --- http://git.linuxtv.org/v4l-utils.git?a=commitdiff;h=2b763a32b2ec1eeccd06aa01cc97c288285d1f76 diff --git a/utils/v4l2-ctl/Makefile b/utils/v4l2-ctl/Makefile index 5ea58c7..9432121 100644 --- a/utils/v4l2-ctl/Makefile +++ b/utils/v4l2-ctl/Makefile @@ -12,7 +12,7 @@ cx18-ctl: cx18-ctl.o ivtv-ctl: ivtv-ctl.o $(CC) $(LDFLAGS) -o $@ $^ -lm -v4l2-ctl: v4l2-ctl.o +v4l2-ctl: v4l2-ctl.o v4l2-ctl-common.o $(CXX) $(LDFLAGS) -o $@ $^ -lv4l2 -lv4lconvert -lrt install: $(TARGETS) diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp new file mode 100644 index 0000000..af0c3ea --- /dev/null +++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp @@ -0,0 +1,729 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <dirent.h> +#include <math.h> + +#ifdef __linux__ +#include <sys/klog.h> +#endif + +#include <linux/videodev2.h> +#include <libv4l2.h> + +#include <list> +#include <vector> +#include <map> +#include <string> +#include <algorithm> + +#include "v4l2-ctl.h" + +typedef std::map<unsigned, std::vector<struct v4l2_ext_control> > class2ctrls_map; + +typedef std::map<std::string, struct v4l2_queryctrl> ctrl_qmap; +static ctrl_qmap ctrl_str2q; +typedef std::map<unsigned, std::string> ctrl_idmap; +static ctrl_idmap ctrl_id2str; + +typedef std::list<std::string> ctrl_get_list; +static ctrl_get_list get_ctrls; + +typedef std::map<std::string, std::string> ctrl_set_map; +static ctrl_set_map set_ctrls; + +typedef std::vector<std::string> dev_vec; +typedef std::map<std::string, std::string> dev_map; + +static enum v4l2_priority prio = V4L2_PRIORITY_UNSET; + +void common_usage(void) +{ + printf("\nGeneral/Common options:\n" + " --all display all information available\n" + " -C, --get-ctrl=<ctrl>[,<ctrl>...]\n" + " get the value of the controls [VIDIOC_G_EXT_CTRLS]\n" + " -c, --set-ctrl=<ctrl>=<val>[,<ctrl>=<val>...]\n" + " set the value of the controls [VIDIOC_S_EXT_CTRLS]\n" + " -D, --info show driver info [VIDIOC_QUERYCAP]\n" + " -d, --device=<dev> use device <dev> instead of /dev/video0\n" + " if <dev> is a single digit, then /dev/video<dev> is used\n" + " -h, --help display this help message\n" + " --help-all all options\n" + " --help-io input/output options\n" + " --help-misc miscellaneous options\n" + " --help-overlay overlay format options\n" + " --help-selection crop/selection options\n" + " --help-stds standards and other video timings options\n" + " --help-tuner tuner/modulator options\n" + " --help-vbi VBI format options\n" + " --help-vidcap video capture format options\n" + " --help-vidout vidout output format options\n" + " -l, --list-ctrls display all controls and their values [VIDIOC_QUERYCTRL]\n" + " -L, --list-ctrls-menus\n" + " display all controls and their menus [VIDIOC_QUERYMENU]\n" + " -w, --wrapper use the libv4l2 wrapper library.\n" + " --list-devices list all v4l devices\n" + " --log-status log the board status in the kernel log [VIDIOC_LOG_STATUS]\n" + " --get-priority query the current access priority [VIDIOC_G_PRIORITY]\n" + " --set-priority=<prio>\n" + " set the new access priority [VIDIOC_S_PRIORITY]\n" + " <prio> is 1 (background), 2 (interactive) or 3 (record)\n" + " --silent only set the result code, do not print any messages\n" + " --sleep=<secs> sleep <secs>, call QUERYCAP and close the file handle\n" + " --verbose turn on verbose ioctl status reporting\n" + ); +} + +static bool is_v4l_dev(const char *name) +{ + return !memcmp(name, "vtx", 3) || + !memcmp(name, "video", 5) || + !memcmp(name, "radio", 5) || + !memcmp(name, "vbi", 3); +} + +static int calc_node_val(const char *s) +{ + int n = 0; + + s = strrchr(s, '/') + 1; + if (!memcmp(s, "video", 5)) n = 0; + else if (!memcmp(s, "radio", 5)) n = 0x100; + else if (!memcmp(s, "vbi", 3)) n = 0x200; + else if (!memcmp(s, "v4l-subdev", 10)) n = 0x300; + n += atol(s + (n >= 0x200 ? 3 : 5)); + return n; +} + +static bool sort_on_device_name(const std::string &s1, const std::string &s2) +{ + int n1 = calc_node_val(s1.c_str()); + int n2 = calc_node_val(s2.c_str()); + + return n1 < n2; +} + +static void list_devices() +{ + DIR *dp; + struct dirent *ep; + dev_vec files; + dev_map links; + dev_map cards; + struct v4l2_capability vcap; + + dp = opendir("/dev"); + if (dp == NULL) { + perror ("Couldn't open the directory"); + return; + } + while ((ep = readdir(dp))) + if (is_v4l_dev(ep->d_name)) + files.push_back(std::string("/dev/") + ep->d_name); + closedir(dp); + + /* Find device nodes which are links to other device nodes */ + for (dev_vec::iterator iter = files.begin(); + iter != files.end(); ) { + char link[64+1]; + int link_len; + std::string target; + + link_len = readlink(iter->c_str(), link, 64); + if (link_len < 0) { /* Not a link or error */ + iter++; + continue; + } + link[link_len] = '\0'; + + /* Only remove from files list if target itself is in list */ + if (link[0] != '/') /* Relative link */ + target = std::string("/dev/"); + target += link; + if (find(files.begin(), files.end(), target) == files.end()) { + iter++; + continue; + } + + /* Move the device node from files to links */ + if (links[target].empty()) + links[target] = *iter; + else + links[target] += ", " + *iter; + files.erase(iter); + } + + std::sort(files.begin(), files.end(), sort_on_device_name); + + for (dev_vec::iterator iter = files.begin(); + iter != files.end(); ++iter) { + int fd = open(iter->c_str(), O_RDWR); + std::string bus_info; + + if (fd < 0) + continue; + doioctl(fd, VIDIOC_QUERYCAP, &vcap); + close(fd); + bus_info = (const char *)vcap.bus_info; + if (cards[bus_info].empty()) + cards[bus_info] += std::string((char *)vcap.card) + " (" + bus_info + "):\n"; + cards[bus_info] += "\t" + (*iter); + if (!(links[*iter].empty())) + cards[bus_info] += " <- " + links[*iter]; + cards[bus_info] += "\n"; + } + for (dev_map::iterator iter = cards.begin(); + iter != cards.end(); ++iter) { + printf("%s\n", iter->second.c_str()); + } +} + +static std::string name2var(unsigned char *name) +{ + std::string s; + int add_underscore = 0; + + while (*name) { + if (isalnum(*name)) { + if (add_underscore) + s += '_'; + add_underscore = 0; + s += std::string(1, tolower(*name)); + } + else if (s.length()) add_underscore = 1; + name++; + } + return s; +} + +static std::string safename(const unsigned char *name) +{ + std::string s; + + while (*name) { + if (*name == '\n') { + s += "\\n"; + } + else if (*name == '\r') { + s += "\\r"; + } + else if (*name == '\f') { + s += "\\f"; + } + else if (*name == '\\') { + s += "\\\\"; + } + else if ((*name & 0x7f) < 0x20) { + char buf[3]; + + sprintf(buf, "%02x", *name); + s += "\\x"; + s += buf; + } + else { + s += *name; + } + name++; + } + return s; +} + +static std::string safename(const char *name) +{ + return safename((const unsigned char *)name); +} + +static std::string ctrlflags2s(__u32 flags) +{ + static const flag_def def[] = { + { V4L2_CTRL_FLAG_GRABBED, "grabbed" }, + { V4L2_CTRL_FLAG_DISABLED, "disabled" }, + { V4L2_CTRL_FLAG_READ_ONLY, "read-only" }, + { V4L2_CTRL_FLAG_UPDATE, "update" }, + { V4L2_CTRL_FLAG_INACTIVE, "inactive" }, + { V4L2_CTRL_FLAG_SLIDER, "slider" }, + { V4L2_CTRL_FLAG_WRITE_ONLY, "write-only" }, + { V4L2_CTRL_FLAG_VOLATILE, "volatile" }, + { 0, NULL } + }; + return flags2s(flags, def); +} + +static void print_qctrl(int fd, struct v4l2_queryctrl *queryctrl, + struct v4l2_ext_control *ctrl, int show_menus) +{ + struct v4l2_querymenu qmenu; + std::string s = name2var(queryctrl->name); + int i; + + memset(&qmenu, 0, sizeof(qmenu)); + qmenu.id = queryctrl->id; + switch (queryctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + printf("%31s (int) : min=%d max=%d step=%d default=%d value=%d", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->step, queryctrl->default_value, + ctrl->value); + break; + case V4L2_CTRL_TYPE_INTEGER64: + printf("%31s (int64) : value=%lld", s.c_str(), ctrl->value64); + break; + case V4L2_CTRL_TYPE_STRING: + printf("%31s (str) : min=%d max=%d step=%d value='%s'", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->step, safename(ctrl->string).c_str()); + break; + case V4L2_CTRL_TYPE_BOOLEAN: + printf("%31s (bool) : default=%d value=%d", + s.c_str(), + queryctrl->default_value, ctrl->value); + break; + case V4L2_CTRL_TYPE_MENU: + printf("%31s (menu) : min=%d max=%d default=%d value=%d", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->default_value, ctrl->value); + break; + case V4L2_CTRL_TYPE_INTEGER_MENU: + printf("%31s (intmenu): min=%d max=%d default=%d value=%d", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->default_value, ctrl->value); + break; + case V4L2_CTRL_TYPE_BUTTON: + printf("%31s (button) :", s.c_str()); + break; + case V4L2_CTRL_TYPE_BITMASK: + printf("%31s (bitmask): max=0x%08x default=0x%08x value=0x%08x", + s.c_str(), queryctrl->maximum, + queryctrl->default_value, ctrl->value); + break; + default: break; + } + if (queryctrl->flags) + printf(" flags=%s", ctrlflags2s(queryctrl->flags).c_str()); + printf("\n"); + if ((queryctrl->type == V4L2_CTRL_TYPE_MENU || + queryctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) && show_menus) { + for (i = queryctrl->minimum; i <= queryctrl->maximum; i++) { + qmenu.index = i; + if (test_ioctl(fd, VIDIOC_QUERYMENU, &qmenu)) + continue; + if (queryctrl->type == V4L2_CTRL_TYPE_MENU) + printf("\t\t\t\t%d: %s\n", i, qmenu.name); + else + printf("\t\t\t\t%d: %lld (0x%llx)\n", i, qmenu.value, qmenu.value); + } + } +} + +static int print_control(int fd, struct v4l2_queryctrl &qctrl, int show_menus) +{ + struct v4l2_control ctrl; + struct v4l2_ext_control ext_ctrl; + struct v4l2_ext_controls ctrls; + + memset(&ctrl, 0, sizeof(ctrl)); + memset(&ext_ctrl, 0, sizeof(ext_ctrl)); + memset(&ctrls, 0, sizeof(ctrls)); + if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) + return 1; + if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { + printf("\n%s\n\n", qctrl.name); + return 1; + } + ext_ctrl.id = qctrl.id; + if ((qctrl.flags & V4L2_CTRL_FLAG_WRITE_ONLY) || + qctrl.type == V4L2_CTRL_TYPE_BUTTON) { + print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); + return 1; + } + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(qctrl.id); + ctrls.count = 1; + ctrls.controls = &ext_ctrl; + if (qctrl.type == V4L2_CTRL_TYPE_INTEGER64 || + qctrl.type == V4L2_CTRL_TYPE_STRING || + (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_USER && + qctrl.id < V4L2_CID_PRIVATE_BASE)) { + if (qctrl.type == V4L2_CTRL_TYPE_STRING) { + ext_ctrl.size = qctrl.maximum + 1; + ext_ctrl.string = (char *)malloc(ext_ctrl.size); + ext_ctrl.string[0] = 0; + } + if (test_ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) { + printf("error %d getting ext_ctrl %s\n", + errno, qctrl.name); + return 0; + } + } + else { + ctrl.id = qctrl.id; + if (test_ioctl(fd, VIDIOC_G_CTRL, &ctrl)) { + printf("error %d getting ctrl %s\n", + errno, qctrl.name); + return 0; + } + ext_ctrl.value = ctrl.value; + } + print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); + if (qctrl.type == V4L2_CTRL_TYPE_STRING) + free(ext_ctrl.string); + return 1; +} + +static void list_controls(int fd, int show_menus) +{ + struct v4l2_queryctrl qctrl; + int id; + + memset(&qctrl, 0, sizeof(qctrl)); + qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; + while (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { + print_control(fd, qctrl, show_menus); + qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + } + if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) + return; + for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { + qctrl.id = id; + if (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) + print_control(fd, qctrl, show_menus); + } + for (qctrl.id = V4L2_CID_PRIVATE_BASE; + test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { + print_control(fd, qctrl, show_menus); + } +} + +static void find_controls(int fd) +{ + struct v4l2_queryctrl qctrl; + int id; + + memset(&qctrl, 0, sizeof(qctrl)); + qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; + while (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { + if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS && + !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl_str2q[name2var(qctrl.name)] = qctrl; + ctrl_id2str[qctrl.id] = name2var(qctrl.name); + } + qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + } + if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) + return; + for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { + qctrl.id = id; + if (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0 && + !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl_str2q[name2var(qctrl.name)] = qctrl; + ctrl_id2str[qctrl.id] = name2var(qctrl.name); + } + } + for (qctrl.id = V4L2_CID_PRIVATE_BASE; + test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { + if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl_str2q[name2var(qctrl.name)] = qctrl; + ctrl_id2str[qctrl.id] = name2var(qctrl.name); + } + } +} + +int common_find_ctrl_id(const char *name) +{ + if (ctrl_str2q.find(name) == ctrl_str2q.end()) + return 0; + return ctrl_str2q[name].id; +} + +void common_process_controls(int fd) +{ + find_controls(fd); + for (ctrl_get_list::iterator iter = get_ctrls.begin(); iter != get_ctrls.end(); ++iter) { + if (ctrl_str2q.find(*iter) == ctrl_str2q.end()) { + fprintf(stderr, "unknown control '%s'\n", (*iter).c_str()); + exit(1); + } + } + for (ctrl_set_map::iterator iter = set_ctrls.begin(); iter != set_ctrls.end(); ++iter) { + if (ctrl_str2q.find(iter->first) == ctrl_str2q.end()) { + fprintf(stderr, "unknown control '%s'\n", iter->first.c_str()); + exit(1); + } + } +} + +void common_control_event(const struct v4l2_event *ev) +{ + const struct v4l2_event_ctrl *ctrl; + + ctrl = &ev->u.ctrl; + printf("ctrl: %s\n", ctrl_id2str[ev->id].c_str()); + if (ctrl->changes & V4L2_EVENT_CTRL_CH_VALUE) { + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + printf("\tvalue: %lld 0x%llx\n", ctrl->value64, ctrl->value64); + else + printf("\tvalue: %d 0x%x\n", ctrl->value, ctrl->value); + } + if (ctrl->changes & V4L2_EVENT_CTRL_CH_FLAGS) + printf("\tflags: %s\n", ctrlflags2s(ctrl->flags).c_str()); +} + +static bool parse_next_subopt(char **subs, char **value) +{ + static char *const subopts[] = { + NULL + }; + int opt = getsubopt(subs, subopts, value); + + if (value == NULL) { + fprintf(stderr, "No value given to suboption <%s>\n", + subopts[opt]); + return true; + } + return false; +} + +void common_cmd(int ch, char *optarg) +{ + char *value, *subs; + + switch (ch) { + case OptGetCtrl: + subs = optarg; + while (*subs != '\0') { + if (parse_next_subopt(&subs, &value)) { + common_usage(); + exit(1); + } + if (strchr(value, '=')) { + common_usage(); + exit(1); + } + else { + get_ctrls.push_back(value); + } + } + break; + case OptSetCtrl: + subs = optarg; + while (*subs != '\0') { + if (parse_next_subopt(&subs, &value)) { + common_usage(); + exit(1); + } + if (const char *equal = strchr(value, '=')) { + set_ctrls[std::string(value, (equal - value))] = equal + 1; + } + else { + fprintf(stderr, "control '%s' without '='\n", value); + exit(1); + } + } + break; + case OptSetPriority: + prio = (enum v4l2_priority)strtoul(optarg, 0L, 0); + break; + case OptListDevices: + list_devices(); + break; + } +} + +void common_set(int fd) +{ + if (options[OptSetPriority]) { + if (doioctl(fd, VIDIOC_S_PRIORITY, &prio) >= 0) { + printf("Priority set: %d\n", prio); + } + } + + if (options[OptSetCtrl] && !set_ctrls.empty()) { + struct v4l2_ext_controls ctrls; + class2ctrls_map class2ctrls; + bool use_ext_ctrls = false; + + memset(&ctrls, 0, sizeof(ctrls)); + for (ctrl_set_map::iterator iter = set_ctrls.begin(); + iter != set_ctrls.end(); ++iter) { + struct v4l2_ext_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = ctrl_str2q[iter->first].id; + if (ctrl_str2q[iter->first].type == V4L2_CTRL_TYPE_INTEGER64) + use_ext_ctrls = true; + if (ctrl_str2q[iter->first].type == V4L2_CTRL_TYPE_STRING) { + unsigned len = iter->second.length(); + unsigned maxlen = ctrl_str2q[iter->first].maximum; + + use_ext_ctrls = true; + ctrl.size = maxlen + 1; + ctrl.string = (char *)malloc(ctrl.size); + if (len > maxlen) { + memcpy(ctrl.string, iter->second.c_str(), maxlen); + ctrl.string[maxlen] = 0; + } + else { + strcpy(ctrl.string, iter->second.c_str()); + } + } else { + if (V4L2_CTRL_DRIVER_PRIV(ctrl.id)) + use_ext_ctrls = true; + ctrl.value = strtol(iter->second.c_str(), NULL, 0); + } + class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); + } + for (class2ctrls_map::iterator iter = class2ctrls.begin(); + iter != class2ctrls.end(); ++iter) { + if (!use_ext_ctrls && + (iter->first == V4L2_CTRL_CLASS_USER || + iter->first == V4L2_CID_PRIVATE_BASE)) { + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_control ctrl; + + ctrl.id = iter->second[i].id; + ctrl.value = iter->second[i].value; + if (doioctl(fd, VIDIOC_S_CTRL, &ctrl)) { + fprintf(stderr, "%s: %s\n", + ctrl_id2str[ctrl.id].c_str(), + strerror(errno)); + } + } + continue; + } + if (iter->second.size()) { + ctrls.ctrl_class = iter->first; + ctrls.count = iter->second.size(); + ctrls.controls = &iter->second[0]; + if (doioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) { + if (ctrls.error_idx >= ctrls.count) { + fprintf(stderr, "Error setting MPEG controls: %s\n", + strerror(errno)); + } + else { + fprintf(stderr, "%s: %s\n", + ctrl_id2str[iter->second[ctrls.error_idx].id].c_str(), + strerror(errno)); + } + } + } + } + } +} + +void common_get(int fd) +{ + if (options[OptGetCtrl] && !get_ctrls.empty()) { + struct v4l2_ext_controls ctrls; + class2ctrls_map class2ctrls; + bool use_ext_ctrls = false; + + memset(&ctrls, 0, sizeof(ctrls)); + for (ctrl_get_list::iterator iter = get_ctrls.begin(); + iter != get_ctrls.end(); ++iter) { + struct v4l2_ext_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = ctrl_str2q[*iter].id; + if (ctrl_str2q[*iter].type == V4L2_CTRL_TYPE_INTEGER64) + use_ext_ctrls = true; + if (ctrl_str2q[*iter].type == V4L2_CTRL_TYPE_STRING) { + use_ext_ctrls = true; + ctrl.size = ctrl_str2q[*iter].maximum + 1; + ctrl.string = (char *)malloc(ctrl.size); + ctrl.string[0] = 0; + } + if (V4L2_CTRL_DRIVER_PRIV(ctrl.id)) + use_ext_ctrls = true; + class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); + } + for (class2ctrls_map::iterator iter = class2ctrls.begin(); + iter != class2ctrls.end(); ++iter) { + if (!use_ext_ctrls && + (iter->first == V4L2_CTRL_CLASS_USER || + iter->first == V4L2_CID_PRIVATE_BASE)) { + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_control ctrl; + + ctrl.id = iter->second[i].id; + doioctl(fd, VIDIOC_G_CTRL, &ctrl); + printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + } + continue; + } + if (iter->second.size()) { + ctrls.ctrl_class = iter->first; + ctrls.count = iter->second.size(); + ctrls.controls = &iter->second[0]; + doioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls); + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_ext_control ctrl = iter->second[i]; + + if (ctrl_str2q[ctrl_id2str[ctrl.id]].type == V4L2_CTRL_TYPE_STRING) + printf("%s: '%s'\n", ctrl_id2str[ctrl.id].c_str(), + safename(ctrl.string).c_str()); + else + printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + } + } + } + } + + if (options[OptGetPriority]) { + if (doioctl(fd, VIDIOC_G_PRIORITY, &prio) == 0) + printf("Priority: %d\n", prio); + } + + if (options[OptLogStatus]) { + static char buf[40960]; + int len = -1; + + if (doioctl(fd, VIDIOC_LOG_STATUS, NULL) == 0) { + printf("\nStatus Log:\n\n"); +#ifdef __linux__ + len = klogctl(3, buf, sizeof(buf) - 1); +#endif + if (len >= 0) { + char *p = buf; + char *q; + + buf[len] = 0; + while ((q = strstr(p, "START STATUS"))) { + p = q + 1; + } + if (p) { + while (p > buf && *p != '<') p--; + q = p; + while ((q = strstr(q, "<6>"))) { + memcpy(q, " ", 3); + } + printf("%s", p); + } + } + } + } +} + +void common_list(int fd) +{ + if (options[OptListCtrlsMenus]) { + list_controls(fd, 1); + } + + if (options[OptListCtrls]) { + list_controls(fd, 0); + } +} diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp index ad64751..442db3c 100644 --- a/utils/v4l2-ctl/v4l2-ctl.cpp +++ b/utils/v4l2-ctl/v4l2-ctl.cpp @@ -46,179 +46,16 @@ #include <string> #include <algorithm> -/* Short option list - - Please keep in alphabetical order. - That makes it easier to see which short options are still free. - - In general the lower case is used to set something and the upper - case is used to retrieve a setting. */ -enum Option { - OptGetSlicedVbiFormat = 'B', - OptSetSlicedVbiFormat = 'b', - OptGetCtrl = 'C', - OptSetCtrl = 'c', - OptSetDevice = 'd', - OptGetDriverInfo = 'D', - OptGetFreq = 'F', - OptSetFreq = 'f', - OptHelp = 'h', - OptGetInput = 'I', - OptSetInput = 'i', - OptListCtrls = 'l', - OptListCtrlsMenus = 'L', - OptListOutputs = 'N', - OptListInputs = 'n', - OptGetOutput = 'O', - OptSetOutput = 'o', - OptGetParm = 'P', - OptSetParm = 'p', - OptGetStandard = 'S', - OptSetStandard = 's', - OptGetTuner = 'T', - OptSetTuner = 't', - OptGetVideoFormat = 'V', - OptSetVideoFormat = 'v', - OptUseWrapper = 'w', - - OptGetVideoMplaneFormat = 128, - OptSetVideoMplaneFormat, - OptGetSlicedVbiOutFormat, - OptGetOverlayFormat, - OptGetOutputOverlayFormat, - OptGetVbiFormat, - OptGetVbiOutFormat, - OptGetVideoOutFormat, - OptGetVideoOutMplaneFormat, - OptSetSlicedVbiOutFormat, - OptSetOutputOverlayFormat, - OptSetOverlayFormat, - //OptSetVbiFormat, TODO - //OptSetVbiOutFormat, TODO - OptSetVideoOutFormat, - OptSetVideoOutMplaneFormat, - OptTryVideoOutFormat, - OptTryVideoOutMplaneFormat, - OptTrySlicedVbiOutFormat, - OptTrySlicedVbiFormat, - OptTryVideoFormat, - OptTryVideoMplaneFormat, - OptTryOutputOverlayFormat, - OptTryOverlayFormat, - //OptTryVbiFormat, TODO - //OptTryVbiOutFormat, TODO - OptAll, - OptStreamOff, - OptStreamOn, - OptListStandards, - OptListFormats, - OptListMplaneFormats, - OptListFormatsExt, - OptListMplaneFormatsExt, - OptListFrameSizes, - OptListFrameIntervals, - OptListOverlayFormats, - OptListOutFormats, - OptListOutMplaneFormats, - OptLogStatus, - OptVerbose, - OptSilent, - OptGetSlicedVbiCap, - OptGetSlicedVbiOutCap, - OptGetFBuf, - OptSetFBuf, - OptGetCrop, - OptSetCrop, - OptGetOutputCrop, - OptSetOutputCrop, - OptGetOverlayCrop, - OptSetOverlayCrop, - OptGetOutputOverlayCrop, - OptSetOutputOverlayCrop, - OptGetSelection, - OptSetSelection, - OptGetOutputSelection, - OptSetOutputSelection, - OptGetAudioInput, - OptSetAudioInput, - OptGetAudioOutput, - OptSetAudioOutput, - OptListAudioOutputs, - OptListAudioInputs, - OptGetCropCap, - OptGetOutputCropCap, - OptGetOverlayCropCap, - OptGetOutputOverlayCropCap, - OptOverlay, - OptSleep, - OptGetJpegComp, - OptSetJpegComp, - OptGetModulator, - OptSetModulator, - OptListDevices, - OptGetOutputParm, - OptSetOutputParm, - OptQueryStandard, - OptPollForEvent, - OptWaitForEvent, - OptGetPriority, - OptSetPriority, - OptListDvPresets, - OptSetDvPreset, - OptGetDvPreset, - OptQueryDvPreset, - OptListDvTimings, - OptQueryDvTimings, - OptGetDvTimings, - OptSetDvBtTimings, - OptGetDvTimingsCap, - OptFreqSeek, - OptEncoderCmd, - OptTryEncoderCmd, - OptDecoderCmd, - OptTryDecoderCmd, - OptTunerIndex, - OptHelpTuner, - OptHelpIO, - OptHelpStds, - OptHelpVidCap, - OptHelpVidOut, - OptHelpOverlay, - OptHelpVbi, - OptHelpSelection, - OptHelpMisc, - OptHelpAll, - OptLast = 256 -}; -static char options[OptLast]; +#include "v4l2-ctl.h" + +char options[OptLast]; static int app_result; static int verbose; static unsigned capabilities; -typedef std::map<unsigned, std::vector<struct v4l2_ext_control> > class2ctrls_map; - -typedef std::map<std::string, struct v4l2_queryctrl> ctrl_qmap; -static ctrl_qmap ctrl_str2q; -typedef std::map<unsigned, std::string> ctrl_idmap; -static ctrl_idmap ctrl_id2str; - -typedef std::list<std::string> ctrl_get_list; -static ctrl_get_list get_ctrls; - -typedef std::map<std::string, std::string> ctrl_set_map; -static ctrl_set_map set_ctrls; - -typedef std::vector<std::string> dev_vec; -typedef std::map<std::string, std::string> dev_map; - -typedef struct { - unsigned flag; - const char *str; -} flag_def; - static const flag_def service_def[] = { { V4L2_SLICED_TELETEXT_B, "teletext" }, { V4L2_SLICED_VPS, "vps" }, @@ -383,44 +220,6 @@ static struct option long_options[] = { {0, 0, 0, 0} }; -static void usage(void) -{ - printf("\nGeneral/Common options:\n" - " --all display all information available\n" - " -C, --get-ctrl=<ctrl>[,<ctrl>...]\n" - " get the value of the controls [VIDIOC_G_EXT_CTRLS]\n" - " -c, --set-ctrl=<ctrl>=<val>[,<ctrl>=<val>...]\n" - " set the value of the controls [VIDIOC_S_EXT_CTRLS]\n" - " -D, --info show driver info [VIDIOC_QUERYCAP]\n" - " -d, --device=<dev> use device <dev> instead of /dev/video0\n" - " if <dev> is a single digit, then /dev/video<dev> is used\n" - " -h, --help display this help message\n" - " --help-all all options\n" - " --help-io input/output options\n" - " --help-misc miscellaneous options\n" - " --help-overlay overlay format options\n" - " --help-selection crop/selection options\n" - " --help-stds standards and other video timings options\n" - " --help-tuner tuner/modulator options\n" - " --help-vbi VBI format options\n" - " --help-vidcap video capture format options\n" - " --help-vidout vidout output format options\n" - " -l, --list-ctrls display all controls and their values [VIDIOC_QUERYCTRL]\n" - " -L, --list-ctrls-menus\n" - " display all controls and their menus [VIDIOC_QUERYMENU]\n" - " -w, --wrapper use the libv4l2 wrapper library.\n" - " --list-devices list all v4l devices\n" - " --log-status log the board status in the kernel log [VIDIOC_LOG_STATUS]\n" - " --get-priority query the current access priority [VIDIOC_G_PRIORITY]\n" - " --set-priority=<prio>\n" - " set the new access priority [VIDIOC_S_PRIORITY]\n" - " <prio> is 1 (background), 2 (interactive) or 3 (record)\n" - " --silent only set the result code, do not print any messages\n" - " --sleep=<secs> sleep <secs>, call QUERYCAP and close the file handle\n" - " --verbose turn on verbose ioctl status reporting\n" - ); -} - static void usage_tuner(void) { printf("\nTuner/Modulator options:\n" @@ -730,7 +529,7 @@ static void usage_misc(void) static void usage_all(void) { - usage(); + common_usage(); usage_tuner(); usage_io(); usage_stds(); @@ -752,12 +551,12 @@ static int test_close(int fd) return options[OptUseWrapper] ? v4l2_close(fd) : close(fd); } -static int test_ioctl(int fd, int cmd, void *arg) +int test_ioctl(int fd, int cmd, void *arg) { return options[OptUseWrapper] ? v4l2_ioctl(fd, cmd, arg) : ioctl(fd, cmd, arg); } -static int doioctl_name(int fd, unsigned long int request, void *parm, const char *name) +int doioctl_name(int fd, unsigned long int request, void *parm, const char *name) { int retval = test_ioctl(fd, request, parm); @@ -773,8 +572,6 @@ static int doioctl_name(int fd, unsigned long int request, void *parm, const cha return retval; } -#define doioctl(n, r, p) doioctl_name(n, r, p, #r) - static std::string num2s(unsigned num) { char buf[10]; @@ -878,7 +675,7 @@ static std::string colorspace2s(int val) } } -static std::string flags2s(unsigned val, const flag_def *def) +std::string flags2s(unsigned val, const flag_def *def) { std::string s; @@ -956,258 +753,6 @@ static void print_sliced_vbi_cap(struct v4l2_sliced_vbi_cap &cap) } } -static std::string name2var(unsigned char *name) -{ - std::string s; - int add_underscore = 0; - - while (*name) { - if (isalnum(*name)) { - if (add_underscore) - s += '_'; - add_underscore = 0; - s += std::string(1, tolower(*name)); - } - else if (s.length()) add_underscore = 1; - name++; - } - return s; -} - -static std::string safename(const unsigned char *name) -{ - std::string s; - - while (*name) { - if (*name == '\n') { - s += "\\n"; - } - else if (*name == '\r') { - s += "\\r"; - } - else if (*name == '\f') { - s += "\\f"; - } - else if (*name == '\\') { - s += "\\\\"; - } - else if ((*name & 0x7f) < 0x20) { - char buf[3]; - - sprintf(buf, "%02x", *name); - s += "\\x"; - s += buf; - } - else { - s += *name; - } - name++; - } - return s; -} - -static std::string safename(const char *name) -{ - return safename((const unsigned char *)name); -} - -static std::string ctrlflags2s(__u32 flags) -{ - static const flag_def def[] = { - { V4L2_CTRL_FLAG_GRABBED, "grabbed" }, - { V4L2_CTRL_FLAG_DISABLED, "disabled" }, - { V4L2_CTRL_FLAG_READ_ONLY, "read-only" }, - { V4L2_CTRL_FLAG_UPDATE, "update" }, - { V4L2_CTRL_FLAG_INACTIVE, "inactive" }, - { V4L2_CTRL_FLAG_SLIDER, "slider" }, - { V4L2_CTRL_FLAG_WRITE_ONLY, "write-only" }, - { V4L2_CTRL_FLAG_VOLATILE, "volatile" }, - { 0, NULL } - }; - return flags2s(flags, def); -} - -static void print_qctrl(int fd, struct v4l2_queryctrl *queryctrl, - struct v4l2_ext_control *ctrl, int show_menus) -{ - struct v4l2_querymenu qmenu; - std::string s = name2var(queryctrl->name); - int i; - - memset(&qmenu, 0, sizeof(qmenu)); - qmenu.id = queryctrl->id; - switch (queryctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - printf("%31s (int) : min=%d max=%d step=%d default=%d value=%d", - s.c_str(), - queryctrl->minimum, queryctrl->maximum, - queryctrl->step, queryctrl->default_value, - ctrl->value); - break; - case V4L2_CTRL_TYPE_INTEGER64: - printf("%31s (int64) : value=%lld", s.c_str(), ctrl->value64); - break; - case V4L2_CTRL_TYPE_STRING: - printf("%31s (str) : min=%d max=%d step=%d value='%s'", - s.c_str(), - queryctrl->minimum, queryctrl->maximum, - queryctrl->step, safename(ctrl->string).c_str()); - break; - case V4L2_CTRL_TYPE_BOOLEAN: - printf("%31s (bool) : default=%d value=%d", - s.c_str(), - queryctrl->default_value, ctrl->value); - break; - case V4L2_CTRL_TYPE_MENU: - printf("%31s (menu) : min=%d max=%d default=%d value=%d", - s.c_str(), - queryctrl->minimum, queryctrl->maximum, - queryctrl->default_value, ctrl->value); - break; - case V4L2_CTRL_TYPE_INTEGER_MENU: - printf("%31s (intmenu): min=%d max=%d default=%d value=%d", - s.c_str(), - queryctrl->minimum, queryctrl->maximum, - queryctrl->default_value, ctrl->value); - break; - case V4L2_CTRL_TYPE_BUTTON: - printf("%31s (button) :", s.c_str()); - break; - case V4L2_CTRL_TYPE_BITMASK: - printf("%31s (bitmask): max=0x%08x default=0x%08x value=0x%08x", - s.c_str(), queryctrl->maximum, - queryctrl->default_value, ctrl->value); - break; - default: break; - } - if (queryctrl->flags) - printf(" flags=%s", ctrlflags2s(queryctrl->flags).c_str()); - printf("\n"); - if ((queryctrl->type == V4L2_CTRL_TYPE_MENU || - queryctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU) && show_menus) { - for (i = queryctrl->minimum; i <= queryctrl->maximum; i++) { - qmenu.index = i; - if (test_ioctl(fd, VIDIOC_QUERYMENU, &qmenu)) - continue; - if (queryctrl->type == V4L2_CTRL_TYPE_MENU) - printf("\t\t\t\t%d: %s\n", i, qmenu.name); - else - printf("\t\t\t\t%d: %lld (0x%llx)\n", i, qmenu.value, qmenu.value); - } - } -} - -static int print_control(int fd, struct v4l2_queryctrl &qctrl, int show_menus) -{ - struct v4l2_control ctrl; - struct v4l2_ext_control ext_ctrl; - struct v4l2_ext_controls ctrls; - - memset(&ctrl, 0, sizeof(ctrl)); - memset(&ext_ctrl, 0, sizeof(ext_ctrl)); - memset(&ctrls, 0, sizeof(ctrls)); - if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) - return 1; - if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { - printf("\n%s\n\n", qctrl.name); - return 1; - } - ext_ctrl.id = qctrl.id; - if ((qctrl.flags & V4L2_CTRL_FLAG_WRITE_ONLY) || - qctrl.type == V4L2_CTRL_TYPE_BUTTON) { - print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); - return 1; - } - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(qctrl.id); - ctrls.count = 1; - ctrls.controls = &ext_ctrl; - if (qctrl.type == V4L2_CTRL_TYPE_INTEGER64 || - qctrl.type == V4L2_CTRL_TYPE_STRING || - (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_USER && - qctrl.id < V4L2_CID_PRIVATE_BASE)) { - if (qctrl.type == V4L2_CTRL_TYPE_STRING) { - ext_ctrl.size = qctrl.maximum + 1; - ext_ctrl.string = (char *)malloc(ext_ctrl.size); - ext_ctrl.string[0] = 0; - } - if (test_ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) { - printf("error %d getting ext_ctrl %s\n", - errno, qctrl.name); - return 0; - } - } - else { - ctrl.id = qctrl.id; - if (test_ioctl(fd, VIDIOC_G_CTRL, &ctrl)) { - printf("error %d getting ctrl %s\n", - errno, qctrl.name); - return 0; - } - ext_ctrl.value = ctrl.value; - } - print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); - if (qctrl.type == V4L2_CTRL_TYPE_STRING) - free(ext_ctrl.string); - return 1; -} - -static void list_controls(int fd, int show_menus) -{ - struct v4l2_queryctrl qctrl; - int id; - - memset(&qctrl, 0, sizeof(qctrl)); - qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - while (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { - print_control(fd, qctrl, show_menus); - qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - } - if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) - return; - for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { - qctrl.id = id; - if (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) - print_control(fd, qctrl, show_menus); - } - for (qctrl.id = V4L2_CID_PRIVATE_BASE; - test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { - print_control(fd, qctrl, show_menus); - } -} - -static void find_controls(int fd) -{ - struct v4l2_queryctrl qctrl; - int id; - - memset(&qctrl, 0, sizeof(qctrl)); - qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - while (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { - if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS && - !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2q[name2var(qctrl.name)] = qctrl; - ctrl_id2str[qctrl.id] = name2var(qctrl.name); - } - qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - } - if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) - return; - for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { - qctrl.id = id; - if (test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0 && - !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2q[name2var(qctrl.name)] = qctrl; - ctrl_id2str[qctrl.id] = name2var(qctrl.name); - } - } - for (qctrl.id = V4L2_CID_PRIVATE_BASE; - test_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { - if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2q[name2var(qctrl.name)] = qctrl; - ctrl_id2str[qctrl.id] = name2var(qctrl.name); - } - } -} static std::string fbufcap2s(unsigned cap) { @@ -1759,120 +1304,6 @@ static v4l2_std_id parse_ntsc(const char *ntsc) return 0; } -static bool is_v4l_dev(const char *name) -{ - return !memcmp(name, "vtx", 3) || - !memcmp(name, "video", 5) || - !memcmp(name, "radio", 5) || - !memcmp(name, "vbi", 3); -} - -static int calc_node_val(const char *s) -{ - int n = 0; - - s = strrchr(s, '/') + 1; - if (!memcmp(s, "video", 5)) n = 0; - else if (!memcmp(s, "radio", 5)) n = 0x100; - else if (!memcmp(s, "vbi", 3)) n = 0x200; - else if (!memcmp(s, "vtx", 3)) n = 0x300; - n += atol(s + (n >= 0x200 ? 3 : 5)); - return n; -} - -static bool sort_on_device_name(const std::string &s1, const std::string &s2) -{ - int n1 = calc_node_val(s1.c_str()); - int n2 = calc_node_val(s2.c_str()); - - return n1 < n2; -} - -static void list_devices() -{ - DIR *dp; - struct dirent *ep; - dev_vec files; - dev_map links; - dev_map cards; - struct v4l2_capability vcap; - - dp = opendir("/dev"); - if (dp == NULL) { - perror ("Couldn't open the directory"); - return; - } - while ((ep = readdir(dp))) - if (is_v4l_dev(ep->d_name)) - files.push_back(std::string("/dev/") + ep->d_name); - closedir(dp); - -#if 0 - dp = opendir("/dev/v4l"); - if (dp) { - while (ep = readdir(dp)) - if (is_v4l_dev(ep->d_name)) - files.push_back(std::string("/dev/v4l/") + ep->d_name); - closedir(dp); - } -#endif - - /* Find device nodes which are links to other device nodes */ - for (dev_vec::iterator iter = files.begin(); - iter != files.end(); ) { - char link[64+1]; - int link_len; - std::string target; - - link_len = readlink(iter->c_str(), link, 64); - if (link_len < 0) { /* Not a link or error */ - iter++; - continue; - } - link[link_len] = '\0'; - - /* Only remove from files list if target itself is in list */ - if (link[0] != '/') /* Relative link */ - target = std::string("/dev/"); - target += link; - if (find(files.begin(), files.end(), target) == files.end()) { - iter++; - continue; - } - - /* Move the device node from files to links */ - if (links[target].empty()) - links[target] = *iter; - else - links[target] += ", " + *iter; - files.erase(iter); - } - - std::sort(files.begin(), files.end(), sort_on_device_name); - - for (dev_vec::iterator iter = files.begin(); - iter != files.end(); ++iter) { - int fd = open(iter->c_str(), O_RDWR); - std::string bus_info; - - if (fd < 0) - continue; - doioctl(fd, VIDIOC_QUERYCAP, &vcap); - close(fd); - bus_info = (const char *)vcap.bus_info; - if (cards[bus_info].empty()) - cards[bus_info] += std::string((char *)vcap.card) + " (" + bus_info + "):\n"; - cards[bus_info] += "\t" + (*iter); - if (!(links[*iter].empty())) - cards[bus_info] += " <- " + links[*iter]; - cards[bus_info] += "\n"; - } - for (dev_map::iterator iter = cards.begin(); - iter != cards.end(); ++iter) { - printf("%s\n", iter->second.c_str()); - } -} - static int parse_subopt(char **subs, const char * const *subopts, char **value) { int opt = getsubopt(subs, (char * const *)subopts, value); @@ -1889,21 +1320,6 @@ static int parse_subopt(char **subs, const char * const *subopts, char **value) return opt; } -static bool parse_next_subopt(char **subs, char **value) -{ - static char *const subopts[] = { - NULL - }; - int opt = getsubopt(subs, subopts, value); - - if (value == NULL) { - fprintf(stderr, "No value given to suboption <%s>\n", - subopts[opt]); - return true; - } - return false; -} - static std::string partstd2s(const char *prefix, const char *stds[], unsigned long long std) { std::string s = std::string(prefix) + "-"; @@ -2410,8 +1826,6 @@ static enum v4l2_field parse_field(const char *s) static void print_event(const struct v4l2_event *ev) { - const struct v4l2_event_ctrl *ctrl; - printf("%ld.%06ld: event %u, pending %u: ", ev->timestamp.tv_sec, ev->timestamp.tv_nsec / 1000, ev->sequence, ev->pending); @@ -2423,16 +1837,7 @@ static void print_event(const struct v4l2_event *ev) printf("eos\n"); break; case V4L2_EVENT_CTRL: - ctrl = &ev->u.ctrl; - printf("ctrl: %s\n", ctrl_id2str[ev->id].c_str()); - if (ctrl->changes & V4L2_EVENT_CTRL_CH_VALUE) { - if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - printf("\tvalue: %lld 0x%llx\n", ctrl->value64, ctrl->value64); - else - printf("\tvalue: %d 0x%x\n", ctrl->value, ctrl->value); - } - if (ctrl->changes & V4L2_EVENT_CTRL_CH_FLAGS) - printf("\tflags: %s\n", ctrlflags2s(ctrl->flags).c_str()); + common_control_event(ev); break; case V4L2_EVENT_FRAME_SYNC: printf("frame_sync %d\n", ev->u.frame_sync.frame_sequence); @@ -2559,12 +1964,11 @@ int main(int argc, char **argv) int overlay; /* overlay */ unsigned int *set_overlay_fmt_ptr = NULL; struct v4l2_format *overlay_fmt_ptr = NULL; + unsigned secs = 0; __u32 wait_for_event = 0; /* wait for this event */ const char *wait_event_id = NULL; __u32 poll_for_event = 0; /* poll for this event */ const char *poll_event_id = NULL; - unsigned secs = 0; - enum v4l2_priority prio = V4L2_PRIORITY_UNSET; char short_options[26 * 2 * 2 + 1]; int idx = 0; int ret; @@ -2604,7 +2008,7 @@ int main(int argc, char **argv) memset(&freq_seek, 0, sizeof(freq_seek)); if (argc == 1) { - usage(); + common_usage(); return 0; } for (i = 0; long_options[i].name; i++) { @@ -2626,7 +2030,7 @@ int main(int argc, char **argv) options[(int)ch] = 1; switch (ch) { case OptHelp: - usage(); + common_usage(); return 0; case OptHelpTuner: usage_tuner(); @@ -2668,6 +2072,9 @@ int main(int argc, char **argv) device = newdev; } break; + case OptSleep: + secs = strtoul(optarg, 0L, 0); + break; case OptSetVideoOutMplaneFormat: case OptTryVideoOutMplaneFormat: case OptSetVideoOutFormat: @@ -2970,38 +2377,6 @@ int main(int argc, char **argv) case OptSetOutputParm: output_fps = strtod(optarg, NULL); break; - case OptGetCtrl: - subs = optarg; - while (*subs != '\0') { - if (parse_next_subopt(&subs, &value)) { - usage(); - exit(1); - } - if (strchr(value, '=')) { - usage(); - exit(1); - } - else { - get_ctrls.push_back(value); - } - } - break; - case OptSetCtrl: - subs = optarg; - while (*subs != '\0') { - if (parse_next_subopt(&subs, &value)) { - usage(); - exit(1); - } - if (const char *equal = strchr(value, '=')) { - set_ctrls[std::string(value, (equal - value))] = equal + 1; - } - else { - fprintf(stderr, "control '%s' without '='\n", value); - exit(1); - } - } - break; case OptSetTuner: if (!strcmp(optarg, "stereo")) mode = V4L2_TUNER_MODE_STEREO; @@ -3153,12 +2528,6 @@ int main(int argc, char **argv) } break; } - case OptSleep: - secs = strtoul(optarg, 0L, 0); - break; - case OptSetPriority: - prio = (enum v4l2_priority)strtoul(optarg, 0L, 0); - break; case OptWaitForEvent: wait_for_event = parse_event(optarg, &wait_event_id); if (wait_for_event == 0) @@ -3169,9 +2538,6 @@ int main(int argc, char **argv) if (poll_for_event == 0) return 1; break; - case OptListDevices: - list_devices(); - break; case OptSetDvPreset: dv_preset.preset = strtoul(optarg, 0L, 0); break; @@ -3249,13 +2615,16 @@ int main(int argc, char **argv) case ':': fprintf(stderr, "Option '%s' requires a value\n", argv[optind]); - usage(); + common_usage(); return 1; case '?': if (argv[optind]) fprintf(stderr, "Unknown argument '%s'\n", argv[optind]); - usage(); + common_usage(); return 1; + default: + common_cmd(ch, optarg); + break; } } if (optind < argc) { @@ -3263,7 +2632,7 @@ int main(int argc, char **argv) while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); - usage(); + common_usage(); return 1; } @@ -3276,26 +2645,16 @@ int main(int argc, char **argv) verbose = options[OptVerbose]; doioctl(fd, VIDIOC_QUERYCAP, &vcap); capabilities = vcap.capabilities; - find_controls(fd); - for (ctrl_get_list::iterator iter = get_ctrls.begin(); iter != get_ctrls.end(); ++iter) { - if (ctrl_str2q.find(*iter) == ctrl_str2q.end()) { - fprintf(stderr, "unknown control '%s'\n", (*iter).c_str()); - exit(1); - } - } - for (ctrl_set_map::iterator iter = set_ctrls.begin(); iter != set_ctrls.end(); ++iter) { - if (ctrl_str2q.find(iter->first) == ctrl_str2q.end()) { - fprintf(stderr, "unknown control '%s'\n", iter->first.c_str()); - exit(1); - } - } + + common_process_controls(fd); + if (wait_for_event == V4L2_EVENT_CTRL && wait_event_id) - if (ctrl_str2q.find(wait_event_id) == ctrl_str2q.end()) { + if (!common_find_ctrl_id(wait_event_id)) { fprintf(stderr, "unknown control '%s'\n", wait_event_id); exit(1); } if (poll_for_event == V4L2_EVENT_CTRL && poll_event_id) - if (ctrl_str2q.find(poll_event_id) == ctrl_str2q.end()) { + if (!common_find_ctrl_id(poll_event_id)) { fprintf(stderr, "unknown control '%s'\n", poll_event_id); exit(1); } @@ -3331,6 +2690,7 @@ int main(int argc, char **argv) options[OptGetPriority] = 1; options[OptGetSelection] = 1; options[OptGetOutputSelection] = 1; + options[OptListCtrls] = 1; get_sel_target = -1; options[OptSilent] = 1; } @@ -3363,11 +2723,7 @@ int main(int argc, char **argv) doioctl(fd, VIDIOC_STREAMOFF, &type); } - if (options[OptSetPriority]) { - if (doioctl(fd, VIDIOC_S_PRIORITY, &prio) >= 0) { - printf("Priority set: %d\n", prio); - } - } + common_set(fd); if (options[OptSetFreq]) { double fac = 16; @@ -3731,78 +3087,6 @@ int main(int argc, char **argv) if (options[OptSetOutputSelection]) { do_selection(fd, set_selection_out, vselection_out, V4L2_BUF_TYPE_VIDEO_OUTPUT); } - - if (options[OptSetCtrl] && !set_ctrls.empty()) { - struct v4l2_ext_controls ctrls; - class2ctrls_map class2ctrls; - bool use_ext_ctrls = false; - - memset(&ctrls, 0, sizeof(ctrls)); - for (ctrl_set_map::iterator iter = set_ctrls.begin(); - iter != set_ctrls.end(); ++iter) { - struct v4l2_ext_control ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = ctrl_str2q[iter->first].id; - if (ctrl_str2q[iter->first].type == V4L2_CTRL_TYPE_INTEGER64) - use_ext_ctrls = true; - if (ctrl_str2q[iter->first].type == V4L2_CTRL_TYPE_STRING) { - unsigned len = iter->second.length(); - unsigned maxlen = ctrl_str2q[iter->first].maximum; - - use_ext_ctrls = true; - ctrl.size = maxlen + 1; - ctrl.string = (char *)malloc(ctrl.size); - if (len > maxlen) { - memcpy(ctrl.string, iter->second.c_str(), maxlen); - ctrl.string[maxlen] = 0; - } - else { - strcpy(ctrl.string, iter->second.c_str()); - } - } else { - if (V4L2_CTRL_DRIVER_PRIV(ctrl.id)) - use_ext_ctrls = true; - ctrl.value = strtol(iter->second.c_str(), NULL, 0); - } - class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); - } - for (class2ctrls_map::iterator iter = class2ctrls.begin(); - iter != class2ctrls.end(); ++iter) { - if (!use_ext_ctrls && - (iter->first == V4L2_CTRL_CLASS_USER || - iter->first == V4L2_CID_PRIVATE_BASE)) { - for (unsigned i = 0; i < iter->second.size(); i++) { - struct v4l2_control ctrl; - - ctrl.id = iter->second[i].id; - ctrl.value = iter->second[i].value; - if (doioctl(fd, VIDIOC_S_CTRL, &ctrl)) { - fprintf(stderr, "%s: %s\n", - ctrl_id2str[ctrl.id].c_str(), - strerror(errno)); - } - } - continue; - } - if (iter->second.size()) { - ctrls.ctrl_class = iter->first; - ctrls.count = iter->second.size(); - ctrls.controls = &iter->second[0]; - if (doioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) { - if (ctrls.error_idx >= ctrls.count) { - fprintf(stderr, "Error setting MPEG controls: %s\n", - strerror(errno)); - } - else { - fprintf(stderr, "%s: %s\n", - ctrl_id2str[iter->second[ctrls.error_idx].id].c_str(), - strerror(errno)); - } - } - } - } - } if (options[OptFreqSeek]) { freq_seek.tuner = tuner_index; @@ -4170,62 +3454,6 @@ int main(int argc, char **argv) } } - if (options[OptGetCtrl] && !get_ctrls.empty()) { - struct v4l2_ext_controls ctrls; - class2ctrls_map class2ctrls; - bool use_ext_ctrls = false; - - memset(&ctrls, 0, sizeof(ctrls)); - for (ctrl_get_list::iterator iter = get_ctrls.begin(); - iter != get_ctrls.end(); ++iter) { - struct v4l2_ext_control ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = ctrl_str2q[*iter].id; - if (ctrl_str2q[*iter].type == V4L2_CTRL_TYPE_INTEGER64) - use_ext_ctrls = true; - if (ctrl_str2q[*iter].type == V4L2_CTRL_TYPE_STRING) { - use_ext_ctrls = true; - ctrl.size = ctrl_str2q[*iter].maximum + 1; - ctrl.string = (char *)malloc(ctrl.size); - ctrl.string[0] = 0; - } - if (V4L2_CTRL_DRIVER_PRIV(ctrl.id)) - use_ext_ctrls = true; - class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); - } - for (class2ctrls_map::iterator iter = class2ctrls.begin(); - iter != class2ctrls.end(); ++iter) { - if (!use_ext_ctrls && - (iter->first == V4L2_CTRL_CLASS_USER || - iter->first == V4L2_CID_PRIVATE_BASE)) { - for (unsigned i = 0; i < iter->second.size(); i++) { - struct v4l2_control ctrl; - - ctrl.id = iter->second[i].id; - doioctl(fd, VIDIOC_G_CTRL, &ctrl); - printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); - } - continue; - } - if (iter->second.size()) { - ctrls.ctrl_class = iter->first; - ctrls.count = iter->second.size(); - ctrls.controls = &iter->second[0]; - doioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls); - for (unsigned i = 0; i < iter->second.size(); i++) { - struct v4l2_ext_control ctrl = iter->second[i]; - - if (ctrl_str2q[ctrl_id2str[ctrl.id]].type == V4L2_CTRL_TYPE_STRING) - printf("%s: '%s'\n", ctrl_id2str[ctrl.id].c_str(), - safename(ctrl.string).c_str()); - else - printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); - } - } - } - } - if (options[OptGetTuner]) { struct v4l2_tuner vt; @@ -4268,38 +3496,6 @@ int main(int argc, char **argv) } } - if (options[OptGetPriority]) { - if (doioctl(fd, VIDIOC_G_PRIORITY, &prio) == 0) - printf("Priority: %d\n", prio); - } - - if (options[OptLogStatus]) { - static char buf[40960]; - int len; - - if (doioctl(fd, VIDIOC_LOG_STATUS, NULL) == 0) { - printf("\nStatus Log:\n\n"); - len = klogctl(3, buf, sizeof(buf) - 1); - if (len >= 0) { - char *p = buf; - char *q; - - buf[len] = 0; - while ((q = strstr(p, "START STATUS"))) { - p = q + 1; - } - if (p) { - while (p > buf && *p != '<') p--; - q = p; - while ((q = strstr(q, "<6>"))) { - memcpy(q, " ", 3); - } - printf("%s", p); - } - } - } - } - /* List options */ if (options[OptListInputs]) { @@ -4434,6 +3630,8 @@ int main(int argc, char **argv) print_video_formats(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); } + common_list(fd); + if (options[OptGetSlicedVbiCap]) { struct v4l2_sliced_vbi_cap cap; @@ -4452,14 +3650,6 @@ int main(int argc, char **argv) } } - if (options[OptListCtrlsMenus]) { - list_controls(fd, 1); - } - - if (options[OptListCtrls]) { - list_controls(fd, 0); - } - if (options[OptListDvPresets]) { dv_enum_preset.index = 0; printf("ioctl: VIDIOC_ENUM_DV_PRESETS\n"); @@ -4500,7 +3690,7 @@ int main(int argc, char **argv) memset(&sub, 0, sizeof(sub)); sub.type = wait_for_event; if (wait_for_event == V4L2_EVENT_CTRL) - sub.id = ctrl_str2q[wait_event_id].id; + sub.id = common_find_ctrl_id(wait_event_id); if (!doioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub)) if (!doioctl(fd, VIDIOC_DQEVENT, &ev)) print_event(&ev); @@ -4514,7 +3704,7 @@ int main(int argc, char **argv) sub.flags = V4L2_EVENT_SUB_FL_SEND_INITIAL; sub.type = poll_for_event; if (poll_for_event == V4L2_EVENT_CTRL) - sub.id = ctrl_str2q[poll_event_id].id; + sub.id = common_find_ctrl_id(poll_event_id); if (!doioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub)) { fd_set fds; __u32 seq = 0; diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h new file mode 100644 index 0000000..6b0f65c --- /dev/null +++ b/utils/v4l2-ctl/v4l2-ctl.h @@ -0,0 +1,174 @@ +#ifndef _V4L2_CTL_H +#define _V4L2_CTL_H + +/* Available options. + + Please keep the first part (options < 128) in alphabetical order. + That makes it easier to see which short options are still free. + + In general the lower case is used to set something and the upper + case is used to retrieve a setting. */ +enum Option { + OptGetSlicedVbiFormat = 'B', + OptSetSlicedVbiFormat = 'b', + OptGetCtrl = 'C', + OptSetCtrl = 'c', + OptSetDevice = 'd', + OptGetDriverInfo = 'D', + OptGetFreq = 'F', + OptSetFreq = 'f', + OptHelp = 'h', + OptGetInput = 'I', + OptSetInput = 'i', + OptListCtrls = 'l', + OptListCtrlsMenus = 'L', + OptListOutputs = 'N', + OptListInputs = 'n', + OptGetOutput = 'O', + OptSetOutput = 'o', + OptGetParm = 'P', + OptSetParm = 'p', + OptGetStandard = 'S', + OptSetStandard = 's', + OptGetTuner = 'T', + OptSetTuner = 't', + OptGetVideoFormat = 'V', + OptSetVideoFormat = 'v', + OptUseWrapper = 'w', + + OptGetVideoMplaneFormat = 128, + OptSetVideoMplaneFormat, + OptGetSlicedVbiOutFormat, + OptGetOverlayFormat, + OptGetOutputOverlayFormat, + OptGetVbiFormat, + OptGetVbiOutFormat, + OptGetVideoOutFormat, + OptGetVideoOutMplaneFormat, + OptSetSlicedVbiOutFormat, + OptSetOutputOverlayFormat, + OptSetOverlayFormat, + //OptSetVbiFormat, TODO + //OptSetVbiOutFormat, TODO + OptSetVideoOutFormat, + OptSetVideoOutMplaneFormat, + OptTryVideoOutFormat, + OptTryVideoOutMplaneFormat, + OptTrySlicedVbiOutFormat, + OptTrySlicedVbiFormat, + OptTryVideoFormat, + OptTryVideoMplaneFormat, + OptTryOutputOverlayFormat, + OptTryOverlayFormat, + //OptTryVbiFormat, TODO + //OptTryVbiOutFormat, TODO + OptAll, + OptStreamOff, + OptStreamOn, + OptListStandards, + OptListFormats, + OptListMplaneFormats, + OptListFormatsExt, + OptListMplaneFormatsExt, + OptListFrameSizes, + OptListFrameIntervals, + OptListOverlayFormats, + OptListOutFormats, + OptListOutMplaneFormats, + OptLogStatus, + OptVerbose, + OptSilent, + OptGetSlicedVbiCap, + OptGetSlicedVbiOutCap, + OptGetFBuf, + OptSetFBuf, + OptGetCrop, + OptSetCrop, + OptGetOutputCrop, + OptSetOutputCrop, + OptGetOverlayCrop, + OptSetOverlayCrop, + OptGetOutputOverlayCrop, + OptSetOutputOverlayCrop, + OptGetSelection, + OptSetSelection, + OptGetOutputSelection, + OptSetOutputSelection, + OptGetAudioInput, + OptSetAudioInput, + OptGetAudioOutput, + OptSetAudioOutput, + OptListAudioOutputs, + OptListAudioInputs, + OptGetCropCap, + OptGetOutputCropCap, + OptGetOverlayCropCap, + OptGetOutputOverlayCropCap, + OptOverlay, + OptSleep, + OptGetJpegComp, + OptSetJpegComp, + OptGetModulator, + OptSetModulator, + OptListDevices, + OptGetOutputParm, + OptSetOutputParm, + OptQueryStandard, + OptPollForEvent, + OptWaitForEvent, + OptGetPriority, + OptSetPriority, + OptListDvPresets, + OptSetDvPreset, + OptGetDvPreset, + OptQueryDvPreset, + OptListDvTimings, + OptQueryDvTimings, + OptGetDvTimings, + OptSetDvBtTimings, + OptGetDvTimingsCap, + OptFreqSeek, + OptEncoderCmd, + OptTryEncoderCmd, + OptDecoderCmd, + OptTryDecoderCmd, + OptTunerIndex, + OptHelpTuner, + OptHelpIO, + OptHelpStds, + OptHelpVidCap, + OptHelpVidOut, + OptHelpOverlay, + OptHelpVbi, + OptHelpSelection, + OptHelpMisc, + OptHelpAll, + OptLast = 256 +}; + +extern char options[OptLast]; + +typedef struct { + unsigned flag; + const char *str; +} flag_def; + +// v4l2-ctl.cpp +int doioctl_name(int fd, unsigned long int request, void *parm, const char *name); +int test_ioctl(int fd, int cmd, void *arg); +std::string flags2s(unsigned val, const flag_def *def); + +#define doioctl(n, r, p) doioctl_name(n, r, p, #r) + +// v4l2-ctl-common.cpp +void common_usage(void); +void common_cmd(int ch, char *optarg); +void common_set(int fd); +void common_get(int fd); +void common_list(int fd); +void common_process_controls(int fd); +void common_control_event(const struct v4l2_event *ev); +int common_find_ctrl_id(const char *name); + + +#endif _______________________________________________ linuxtv-commits mailing list [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits
