int testQueryControls(struct node *node) { struct test_queryctrl qctrl; __u32 id = 0; int ret; __u32 ctrl_class = 0; bool found_ctrl_class = false; unsigned user_controls = 0; unsigned priv_user_controls = 0; unsigned user_controls_check = 0; unsigned priv_user_controls_check = 0; unsigned class_count = 0; for (;;) { memset(&qctrl, 0xff, sizeof(qctrl)); qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL; ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); if (ret == ENOTTY) return ret; if (ret && ret != EINVAL) return fail("invalid queryctrl return code\n"); if (ret) break; if (checkQCtrl(node, qctrl)) return fail("invalid control %08x\n", qctrl.id); if (qctrl.id <= id) return fail("id did not increase!\n"); id = qctrl.id; if (id >= V4L2_CID_PRIVATE_BASE) return fail("no V4L2_CID_PRIVATE_BASE allowed\n"); if (V4L2_CTRL_ID2CLASS(id) != ctrl_class) { if (ctrl_class && !found_ctrl_class) return fail("missing control class for class %08x\n", ctrl_class); if (ctrl_class && !class_count) return fail("no controls in class %08x\n", ctrl_class); ctrl_class = V4L2_CTRL_ID2CLASS(id); found_ctrl_class = false; class_count = 0; } if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { found_ctrl_class = true; } else { class_count++; } if (ctrl_class == V4L2_CTRL_CLASS_USER && qctrl.type != V4L2_CTRL_TYPE_INTEGER64 && qctrl.type != V4L2_CTRL_TYPE_STRING && qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS) { if (V4L2_CTRL_DRIVER_PRIV(id)) priv_user_controls_check++; else if (id < V4L2_CID_LASTP1) user_controls_check++; } if (V4L2_CTRL_DRIVER_PRIV(id)) node->priv_controls++; else node->std_controls++; node->controls.push_back(qctrl); } if (ctrl_class && !found_ctrl_class) return fail("missing control class for class %08x\n", ctrl_class); if (ctrl_class && !class_count) return fail("no controls in class %08x\n", ctrl_class); for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) { memset(&qctrl, 0xff, sizeof(qctrl)); qctrl.id = id; ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); if (ret && ret != EINVAL) return fail("invalid queryctrl return code\n"); if (ret) continue; if (qctrl.id != id) return fail("qctrl.id (%08x) != id (%08x)\n", qctrl.id, id); if (checkQCtrl(node, qctrl)) return fail("invalid control %08x\n", qctrl.id); user_controls++; } for (id = V4L2_CID_PRIVATE_BASE; ; id++) { memset(&qctrl, 0xff, sizeof(qctrl)); qctrl.id = id; ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); if (ret && ret != EINVAL) return fail("invalid queryctrl return code\n"); if (ret) break; if (qctrl.id != id) return fail("qctrl.id (%08x) != id (%08x)\n", qctrl.id, id); if (checkQCtrl(node, qctrl)) return fail("invalid control %08x\n", qctrl.id); priv_user_controls++; } if (priv_user_controls + user_controls && node->controls.empty()) return fail("does not support V4L2_CTRL_FLAG_NEXT_CTRL\n"); if (user_controls != user_controls_check) return fail("expected %d user controls, got %d\n", user_controls_check, user_controls); if (priv_user_controls != priv_user_controls_check) return fail("expected %d private controls, got %d\n", priv_user_controls_check, priv_user_controls); return 0; }
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; struct v4l2_query_ext_ctrl &qc = ctrl_str2q[*iter]; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = qc.id; if (qc.type == V4L2_CTRL_TYPE_INTEGER64) use_ext_ctrls = true; if (qc.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { use_ext_ctrls = true; ctrl.size = qc.elems * qc.elem_size; ctrl.ptr = calloc(1, ctrl.size); } 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]; std::string &name = ctrl_id2str[ctrl.id]; struct v4l2_query_ext_ctrl &qc = ctrl_str2q[name]; if (qc.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { switch (qc.type) { case V4L2_CTRL_TYPE_U8: case V4L2_CTRL_TYPE_U16: case V4L2_CTRL_TYPE_U32: print_array(qc, ctrl.ptr); break; case V4L2_CTRL_TYPE_STRING: printf("%s: '%s'\n", name.c_str(), safename(ctrl.string).c_str()); break; default: fprintf(stderr, "%s: unsupported payload type\n", qc.name); break; } } else printf("%s: %d\n", name.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 HAVE_KLOGCTL 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_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; struct v4l2_query_ext_ctrl &qc = ctrl_str2q[iter->first]; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = qc.id; if (qc.type == V4L2_CTRL_TYPE_INTEGER64) use_ext_ctrls = true; if (qc.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { struct v4l2_ext_controls ctrls = { 0, 1 }; unsigned divide[V4L2_CTRL_MAX_DIMS] = { 0 }; ctrl_subset subset; long long v; unsigned d, i; use_ext_ctrls = true; ctrl.size = qc.elems * qc.elem_size; ctrl.ptr = malloc(ctrl.size); ctrls.controls = &ctrl; ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls); if (fill_subset(qc, subset)) return; divide[qc.nr_of_dims - 1] = 1; for (d = 0; d < qc.nr_of_dims - 1; d++) { divide[d] = qc.dims[d + 1]; for (i = 0; i < d; i++) divide[i] *= divide[d]; } switch (qc.type) { case V4L2_CTRL_TYPE_U8: v = strtoul(iter->second.c_str(), NULL, 0); for (i = 0; i < qc.elems; i++) if (idx_in_subset(qc, subset, divide, i)) ctrl.p_u8[i] = v; break; case V4L2_CTRL_TYPE_U16: v = strtoul(iter->second.c_str(), NULL, 0); for (i = 0; i < qc.elems; i++) if (idx_in_subset(qc, subset, divide, i)) ctrl.p_u16[i] = v; break; case V4L2_CTRL_TYPE_U32: v = strtoul(iter->second.c_str(), NULL, 0); for (i = 0; i < qc.elems; i++) if (idx_in_subset(qc, subset, divide, i)) ctrl.p_u32[i] = v; break; case V4L2_CTRL_TYPE_STRING: strncpy(ctrl.string, iter->second.c_str(), qc.maximum); ctrl.string[qc.maximum] = 0; break; default: fprintf(stderr, "%s: unsupported payload type\n", qc.name); break; } } 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 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 HAVE_KLOGCTL 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_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 ApplicationWindow::addTabs() { v4l2_queryctrl qctrl; unsigned ctrl_class; unsigned i; int id; memset(&qctrl, 0, sizeof(qctrl)); qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; while (queryctrl(qctrl)) { if (is_valid_type(qctrl.type) && (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) == 0) { m_ctrlMap[qctrl.id] = qctrl; if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS) m_classMap[V4L2_CTRL_ID2CLASS(qctrl.id)].push_back(qctrl.id); } qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; } if (qctrl.id == V4L2_CTRL_FLAG_NEXT_CTRL) { strcpy((char *)qctrl.name, "User Controls"); qctrl.id = V4L2_CTRL_CLASS_USER | 1; qctrl.type = V4L2_CTRL_TYPE_CTRL_CLASS; m_ctrlMap[qctrl.id] = qctrl; for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { qctrl.id = id; if (!queryctrl(qctrl)) continue; if (!is_valid_type(qctrl.type)) continue; if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue; m_ctrlMap[qctrl.id] = qctrl; m_classMap[V4L2_CTRL_CLASS_USER].push_back(qctrl.id); } for (qctrl.id = V4L2_CID_PRIVATE_BASE; queryctrl(qctrl); qctrl.id++) { if (!is_valid_type(qctrl.type)) continue; if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue; m_ctrlMap[qctrl.id] = qctrl; m_classMap[V4L2_CTRL_CLASS_USER].push_back(qctrl.id); } } m_haveExtendedUserCtrls = false; for (unsigned i = 0; i < m_classMap[V4L2_CTRL_CLASS_USER].size(); i++) { unsigned id = m_classMap[V4L2_CTRL_CLASS_USER][i]; if (m_ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64 || m_ctrlMap[id].type == V4L2_CTRL_TYPE_STRING || V4L2_CTRL_DRIVER_PRIV(id)) { m_haveExtendedUserCtrls = true; break; } } for (ClassMap::iterator iter = m_classMap.begin(); iter != m_classMap.end(); ++iter) { if (iter->second.size() == 0) continue; ctrl_class = V4L2_CTRL_ID2CLASS(iter->second[0]); id = ctrl_class | 1; m_col = m_row = 0; m_cols = 4; const v4l2_queryctrl &qctrl = m_ctrlMap[id]; QWidget *t = new QWidget(m_tabs); QVBoxLayout *vbox = new QVBoxLayout(t); QWidget *w = new QWidget(t); vbox->addWidget(w); QGridLayout *grid = new QGridLayout(w); grid->setSpacing(3); m_tabs->addTab(t, (char *)qctrl.name); for (i = 0; i < iter->second.size(); i++) { if (i & 1) id = iter->second[(1+iter->second.size()) / 2 + i / 2]; else id = iter->second[i / 2]; addCtrl(grid, m_ctrlMap[id]); } grid->addWidget(new QWidget(w), grid->rowCount(), 0, 1, m_cols); grid->setRowStretch(grid->rowCount() - 1, 1); w = new QWidget(t); vbox->addWidget(w); grid = new QGridLayout(w); finishGrid(grid, ctrl_class); } }