From c44cae94e57e3abab97d43edfd6036dd03065db9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2014 23:44:31 +0200 Subject: [PATCH] qv4l2: use new control helpers Instead of trying to handle the various levels of control support that drivers provide in every application, add helper functions that abstract away the differences and that simplify working with controls. Signed-off-by: Hans Verkuil --- utils/qv4l2/ctrl-tab.cpp | 328 ++++++++++++++--------------------- utils/qv4l2/qv4l2.cpp | 2 +- utils/qv4l2/qv4l2.h | 5 +- utils/v4l2-compliance/cv4l-helpers.h | 20 +++ utils/v4l2-compliance/v4l-helpers.h | 139 +++++++++++++++ 5 files changed, 295 insertions(+), 199 deletions(-) diff --git a/utils/qv4l2/ctrl-tab.cpp b/utils/qv4l2/ctrl-tab.cpp index c264394..5ff3acc 100644 --- a/utils/qv4l2/ctrl-tab.cpp +++ b/utils/qv4l2/ctrl-tab.cpp @@ -76,59 +76,35 @@ void ApplicationWindow::addWidget(QGridLayout *grid, QWidget *w, Qt::Alignment a void ApplicationWindow::addTabs(int size[]) { - v4l2_queryctrl qctrl; + v4l2_query_ext_ctrl qec = { 0 }; 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); + while (query_ext_ctrl(qec, true) == 0) { + if (is_valid_type(qec.type) && + (qec.flags & V4L2_CTRL_FLAG_DISABLED) == 0) { + m_ctrlMap[qec.id] = qec; + if (qec.type != V4L2_CTRL_TYPE_CTRL_CLASS) + m_classMap[V4L2_CTRL_ID2CLASS(qec.id)].push_back(qec.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; - } + if (m_classMap.find(V4L2_CTRL_CLASS_USER) != m_classMap.end() && + m_ctrlMap.find(V4L2_CID_USER_CLASS) == m_ctrlMap.end()) { + memset(&qec, 0, sizeof(qec)); + qec.id = V4L2_CID_USER_CLASS; + strcpy(qec.name, "User Controls"); + qec.type = V4L2_CTRL_TYPE_CTRL_CLASS; + m_ctrlMap[qec.id] = qec; + } + if (m_classMap.find(V4L2_CTRL_CLASS_CAMERA) != m_classMap.end() && + m_ctrlMap.find(V4L2_CID_CAMERA_CLASS) == m_ctrlMap.end()) { + // UVC still doesn't provide this :-( + memset(&qec, 0, sizeof(qec)); + qec.id = V4L2_CID_CAMERA_CLASS; + strcpy(qec.name, "Camera Controls"); + qec.type = V4L2_CTRL_TYPE_CTRL_CLASS; + m_ctrlMap[qec.id] = qec; } for (ClassMap::iterator iter = m_classMap.begin(); iter != m_classMap.end(); ++iter) { @@ -142,7 +118,7 @@ void ApplicationWindow::addTabs(int size[]) m_maxw[j] = 0; } - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; QWidget *t = new QWidget(m_tabs); QVBoxLayout *vbox = new QVBoxLayout(t); QWidget *w = new QWidget(t); @@ -150,7 +126,7 @@ void ApplicationWindow::addTabs(int size[]) vbox->addWidget(w); QGridLayout *grid = new QGridLayout(w); - QString tabName((char *)qctrl.name); + QString tabName(qec.name); if (tabName != "User Controls" && tabName.endsWith(" Controls")) tabName.chop(9); @@ -274,12 +250,12 @@ void ApplicationWindow::finishGrid(QGridLayout *grid, unsigned ctrl_class) refresh(ctrl_class); } -void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) +void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_query_ext_ctrl &qec) { QWidget *p = grid->parentWidget(); QIntValidator *val; QLineEdit *edit; - QString name((char *)qctrl.name); + QString name(qec.name); QComboBox *combo; QSpinBox *spin; QSlider *slider; @@ -287,23 +263,23 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) QWidget *wContainer = new QWidget(); QHBoxLayout *m_boxLayout = new QHBoxLayout(wContainer); m_boxLayout->setMargin(0); - unsigned dif; + __u64 dif; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER: addLabel(grid, name); - dif = qctrl.maximum - qctrl.minimum; - if (dif <= 0xffffU || (qctrl.flags & V4L2_CTRL_FLAG_SLIDER)) { - m_sliderMap[qctrl.id] = slider = new QSlider(Qt::Horizontal, p); + dif = qec.maximum - qec.minimum; + if (dif <= 0xffffU || (qec.flags & V4L2_CTRL_FLAG_SLIDER)) { + m_sliderMap[qec.id] = slider = new QSlider(Qt::Horizontal, p); slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); - slider->setMinimum(qctrl.minimum); - slider->setMaximum(qctrl.maximum); - slider->setSingleStep(qctrl.step); - slider->setSliderPosition(qctrl.default_value); + slider->setMinimum(qec.minimum); + slider->setMaximum(qec.maximum); + slider->setSingleStep(qec.step); + slider->setSliderPosition(qec.default_value); - m_widgetMap[qctrl.id] = spin = new QSpinBox(p); - spin->setRange(qctrl.minimum, qctrl.maximum); - spin->setSingleStep(qctrl.step); + m_widgetMap[qec.id] = spin = new QSpinBox(p); + spin->setRange(qec.minimum, qec.maximum); + spin->setSingleStep(qec.step); m_boxLayout->addWidget(slider); m_boxLayout->addWidget(spin); @@ -312,30 +288,30 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) connect(spin, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); connect(slider, SIGNAL(valueChanged(int)), spin, SLOT(setValue(int))); - connect(m_widgetMap[qctrl.id], SIGNAL(valueChanged(int)), + connect(m_widgetMap[qec.id], SIGNAL(valueChanged(int)), m_sigMapper, SLOT(map())); break; } - val = new QIntValidator(qctrl.minimum, qctrl.maximum, p); + val = new QIntValidator(qec.minimum, qec.maximum, p); edit = new QLineEdit(p); edit->setValidator(val); addWidget(grid, edit); - m_widgetMap[qctrl.id] = edit; - connect(m_widgetMap[qctrl.id], SIGNAL(lostFocus()), + m_widgetMap[qec.id] = edit; + connect(m_widgetMap[qec.id], SIGNAL(lostFocus()), m_sigMapper, SLOT(map())); - connect(m_widgetMap[qctrl.id], SIGNAL(returnPressed()), + connect(m_widgetMap[qec.id], SIGNAL(returnPressed()), m_sigMapper, SLOT(map())); break; case V4L2_CTRL_TYPE_INTEGER64: addLabel(grid, name); edit = new QLineEdit(p); - m_widgetMap[qctrl.id] = edit; + m_widgetMap[qec.id] = edit; addWidget(grid, edit); - connect(m_widgetMap[qctrl.id], SIGNAL(lostFocus()), + connect(m_widgetMap[qec.id], SIGNAL(lostFocus()), m_sigMapper, SLOT(map())); - connect(m_widgetMap[qctrl.id], SIGNAL(returnPressed()), + connect(m_widgetMap[qec.id], SIGNAL(returnPressed()), m_sigMapper, SLOT(map())); break; @@ -344,40 +320,40 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) edit = new QLineEdit(p); edit->setInputMask("HHHHHHHH"); addWidget(grid, edit); - m_widgetMap[qctrl.id] = edit; - connect(m_widgetMap[qctrl.id], SIGNAL(lostFocus()), + m_widgetMap[qec.id] = edit; + connect(m_widgetMap[qec.id], SIGNAL(lostFocus()), m_sigMapper, SLOT(map())); - connect(m_widgetMap[qctrl.id], SIGNAL(returnPressed()), + connect(m_widgetMap[qec.id], SIGNAL(returnPressed()), m_sigMapper, SLOT(map())); break; case V4L2_CTRL_TYPE_STRING: addLabel(grid, name); edit = new QLineEdit(p); - m_widgetMap[qctrl.id] = edit; - edit->setMaxLength(qctrl.maximum); + m_widgetMap[qec.id] = edit; + edit->setMaxLength(qec.maximum); addWidget(grid, edit); - connect(m_widgetMap[qctrl.id], SIGNAL(lostFocus()), + connect(m_widgetMap[qec.id], SIGNAL(lostFocus()), m_sigMapper, SLOT(map())); - connect(m_widgetMap[qctrl.id], SIGNAL(returnPressed()), + connect(m_widgetMap[qec.id], SIGNAL(returnPressed()), m_sigMapper, SLOT(map())); break; case V4L2_CTRL_TYPE_BOOLEAN: addLabel(grid, name); - m_widgetMap[qctrl.id] = new QCheckBox(p); - addWidget(grid, m_widgetMap[qctrl.id]); - connect(m_widgetMap[qctrl.id], SIGNAL(clicked()), + m_widgetMap[qec.id] = new QCheckBox(p); + addWidget(grid, m_widgetMap[qec.id]); + connect(m_widgetMap[qec.id], SIGNAL(clicked()), m_sigMapper, SLOT(map())); break; case V4L2_CTRL_TYPE_BUTTON: - addLabel(grid, (char *)qctrl.name); + addLabel(grid, (char *)qec.name); QToolButton *button; - m_widgetMap[qctrl.id] = button = new QToolButton(p); + m_widgetMap[qec.id] = button = new QToolButton(p); button->setIcon(QIcon(":/enterbutt.png")); - addWidget(grid, m_widgetMap[qctrl.id]); - connect(m_widgetMap[qctrl.id], SIGNAL(clicked()), + addWidget(grid, m_widgetMap[qec.id]); + connect(m_widgetMap[qec.id], SIGNAL(clicked()), m_sigMapper, SLOT(map())); break; @@ -385,19 +361,19 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) case V4L2_CTRL_TYPE_INTEGER_MENU: addLabel(grid, name); combo = new QComboBox(p); - m_widgetMap[qctrl.id] = combo; - for (int i = qctrl.minimum; i <= qctrl.maximum; i++) { - qmenu.id = qctrl.id; + m_widgetMap[qec.id] = combo; + for (int i = (int)qec.minimum; i <= (int)qec.maximum; i++) { + qmenu.id = qec.id; qmenu.index = i; if (querymenu(qmenu)) continue; - if (qctrl.type == V4L2_CTRL_TYPE_MENU) + if (qec.type == V4L2_CTRL_TYPE_MENU) combo->addItem((char *)qmenu.name); else combo->addItem(QString("%1").arg(qmenu.value)); } - addWidget(grid, m_widgetMap[qctrl.id]); - connect(m_widgetMap[qctrl.id], SIGNAL(activated(int)), + addWidget(grid, m_widgetMap[qec.id]); + connect(m_widgetMap[qec.id], SIGNAL(activated(int)), m_sigMapper, SLOT(map())); break; @@ -405,11 +381,11 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) return; } - m_sigMapper->setMapping(m_widgetMap[qctrl.id], qctrl.id); - if (qctrl.flags & CTRL_FLAG_DISABLED) { - m_widgetMap[qctrl.id]->setDisabled(true); - if (m_sliderMap.find(qctrl.id) != m_sliderMap.end()) - m_sliderMap[qctrl.id]->setDisabled(true); + m_sigMapper->setMapping(m_widgetMap[qec.id], qec.id); + if (qec.flags & CTRL_FLAG_DISABLED) { + m_widgetMap[qec.id]->setDisabled(true); + if (m_sliderMap.find(qec.id) != m_sliderMap.end()) + m_sliderMap[qec.id]->setDisabled(true); } } @@ -433,16 +409,6 @@ void ApplicationWindow::ctrlAction(int id) } if (!update && !all && m_ctrlMap[id].type != V4L2_CTRL_TYPE_BUTTON) return; - if (!m_haveExtendedUserCtrls && ctrl_class == V4L2_CTRL_CLASS_USER) { - if (!all) { - updateCtrl(id); - return; - } - for (unsigned i = 0; i < m_classMap[ctrl_class].size(); i++) { - updateCtrl(m_classMap[ctrl_class][i]); - } - return; - } if (!all) { updateCtrl(id); return; @@ -474,7 +440,7 @@ void ApplicationWindow::ctrlAction(int id) ctrls.count = idx; ctrls.ctrl_class = ctrl_class; ctrls.controls = c; - if (cv4l_ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) { + if (s_ext_ctrls(ctrls)) { if (ctrls.error_idx >= ctrls.count) { error(errno); } @@ -492,17 +458,17 @@ void ApplicationWindow::ctrlAction(int id) QString ApplicationWindow::getString(unsigned id) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; - QWidget *w = m_widgetMap[qctrl.id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; + QWidget *w = m_widgetMap[qec.id]; QString v; int mod; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_STRING: v = static_cast(w)->text(); - mod = v.length() % qctrl.step; + mod = v.length() % qec.step; if (mod) - v += QString(qctrl.step - mod, ' '); + v += QString(qec.step - mod, ' '); break; default: break; @@ -513,11 +479,11 @@ QString ApplicationWindow::getString(unsigned id) long long ApplicationWindow::getVal64(unsigned id) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; - QWidget *w = m_widgetMap[qctrl.id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; + QWidget *w = m_widgetMap[qec.id]; long long v = 0; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER64: v = static_cast(w)->text().toLongLong(); break; @@ -530,17 +496,17 @@ long long ApplicationWindow::getVal64(unsigned id) int ApplicationWindow::getVal(unsigned id) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; - QWidget *w = m_widgetMap[qctrl.id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; + QWidget *w = m_widgetMap[qec.id]; v4l2_querymenu qmenu; int i, idx; int v = 0; unsigned dif; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER: - dif = qctrl.maximum - qctrl.minimum; - if (dif <= 0xffffU || (qctrl.flags & V4L2_CTRL_FLAG_SLIDER)) { + dif = qec.maximum - qec.minimum; + if (dif <= 0xffffU || (qec.flags & V4L2_CTRL_FLAG_SLIDER)) { v = static_cast(w)->value(); break; } @@ -557,8 +523,8 @@ int ApplicationWindow::getVal(unsigned id) case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU: idx = static_cast(w)->currentIndex(); - for (i = qctrl.minimum; i <= qctrl.maximum; i++) { - qmenu.id = qctrl.id; + for (i = qec.minimum; i <= qec.maximum; i++) { + qmenu.id = qec.id; qmenu.index = i; if (querymenu(qmenu)) continue; @@ -584,18 +550,6 @@ void ApplicationWindow::updateCtrl(unsigned id) if (m_ctrlMap[id].flags & CTRL_FLAG_DISABLED) return; - if (!m_haveExtendedUserCtrls && ctrl_class == V4L2_CTRL_CLASS_USER) { - struct v4l2_control c; - - c.id = id; - c.value = getVal(id); - if (cv4l_ioctl(VIDIOC_S_CTRL, &c)) { - errorCtrl(id, errno, c.value); - } - else if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE) - refresh(ctrl_class); - return; - } struct v4l2_ext_control c; struct v4l2_ext_controls ctrls; @@ -614,7 +568,7 @@ void ApplicationWindow::updateCtrl(unsigned id) ctrls.count = 1; ctrls.ctrl_class = ctrl_class; ctrls.controls = &c; - if (cv4l_ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) { + if (s_ext_ctrls(ctrls)) { errorCtrl(id, errno, c.value); } else if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE) @@ -633,37 +587,37 @@ void ApplicationWindow::updateCtrl(unsigned id) void ApplicationWindow::updateCtrlRange(unsigned id, __s32 new_val) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; QLineEdit *edit; QIntValidator *val; unsigned dif; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER: - dif = qctrl.maximum - qctrl.minimum; - if (dif <= 0xffffU || (qctrl.flags & V4L2_CTRL_FLAG_SLIDER)) { + dif = qec.maximum - qec.minimum; + if (dif <= 0xffffU || (qec.flags & V4L2_CTRL_FLAG_SLIDER)) { QSlider *slider = static_cast(m_sliderMap[id]); - slider->setMinimum(qctrl.minimum); - slider->setMaximum(qctrl.maximum); - slider->setSingleStep(qctrl.step); + slider->setMinimum(qec.minimum); + slider->setMaximum(qec.maximum); + slider->setSingleStep(qec.step); slider->setSliderPosition(new_val); QSpinBox *spin = static_cast(m_widgetMap[id]); - spin->setRange(qctrl.minimum, qctrl.maximum); - spin->setSingleStep(qctrl.step); + spin->setRange(qec.minimum, qec.maximum); + spin->setSingleStep(qec.step); spin->setValue(new_val); break; } edit = static_cast(m_widgetMap[id]); - val = new QIntValidator(qctrl.minimum, qctrl.maximum, edit->parent()); + val = new QIntValidator(qec.minimum, qec.maximum, edit->parent()); // FIXME: will this delete the old validator? edit->setValidator(val); break; case V4L2_CTRL_TYPE_STRING: QLineEdit *edit = static_cast(m_widgetMap[id]); - edit->setMaxLength(qctrl.maximum); + edit->setMaxLength(qec.maximum); break; } } @@ -685,27 +639,6 @@ void ApplicationWindow::subscribeCtrlEvents() void ApplicationWindow::refresh(unsigned ctrl_class) { - if (!m_haveExtendedUserCtrls && ctrl_class == V4L2_CTRL_CLASS_USER) { - for (unsigned i = 0; i < m_classMap[ctrl_class].size(); i++) { - unsigned id = m_classMap[ctrl_class][i]; - v4l2_control c; - - queryctrl(m_ctrlMap[id]); - if (m_ctrlMap[id].type == V4L2_CTRL_TYPE_BUTTON) - continue; - if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_WRITE_ONLY) - continue; - c.id = id; - if (cv4l_ioctl(VIDIOC_G_CTRL, &c)) { - errorCtrl(id, errno); - } - setVal(id, c.value); - m_widgetMap[id]->setDisabled(m_ctrlMap[id].flags & CTRL_FLAG_DISABLED); - if (m_sliderMap.find(id) != m_sliderMap.end()) - m_sliderMap[id]->setDisabled(m_ctrlMap[id].flags & CTRL_FLAG_DISABLED); - } - return; - } unsigned count = m_classMap[ctrl_class].size(); unsigned cnt = 0; struct v4l2_ext_control *c = new v4l2_ext_control[count]; @@ -728,7 +661,7 @@ void ApplicationWindow::refresh(unsigned ctrl_class) ctrls.count = cnt; ctrls.ctrl_class = ctrl_class; ctrls.controls = c; - if (cv4l_ioctl(VIDIOC_G_EXT_CTRLS, &ctrls)) { + if (g_ext_ctrls(ctrls)) { if (ctrls.error_idx >= ctrls.count) { error(errno); } @@ -740,7 +673,7 @@ void ApplicationWindow::refresh(unsigned ctrl_class) for (unsigned i = 0; i < ctrls.count; i++) { unsigned id = c[i].id; - queryctrl(m_ctrlMap[id]); + query_ext_ctrl(m_ctrlMap[id]); if (m_ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64) setVal64(id, c[i].value64); else if (m_ctrlMap[id].type == V4L2_CTRL_TYPE_STRING) { @@ -765,18 +698,18 @@ void ApplicationWindow::refresh() void ApplicationWindow::setWhat(QWidget *w, unsigned id, const QString &v) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; QString what; - QString flags = getCtrlFlags(qctrl.flags); + QString flags = getCtrlFlags(qec.flags); - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_STRING: w->setWhatsThis(QString("Type: String\n" "Minimum: %1\n" "Maximum: %2\n" "Step: %3\n" "Current: %4") - .arg(qctrl.minimum).arg(qctrl.maximum).arg(qctrl.step).arg(v) + flags); + .arg(qec.minimum).arg(qec.maximum).arg(qec.step).arg(v) + flags); w->setStatusTip(w->whatsThis()); break; default: @@ -786,11 +719,11 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, const QString &v) void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; QString what; - QString flags = getCtrlFlags(qctrl.flags); + QString flags = getCtrlFlags(qec.flags); - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER: w->setWhatsThis(QString("Type: Integer\n" "Minimum: %1\n" @@ -798,13 +731,18 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) "Step: %3\n" "Current: %4\n" "Default: %5") - .arg(qctrl.minimum).arg(qctrl.maximum).arg(qctrl.step).arg(v).arg(qctrl.default_value) + flags); + .arg(qec.minimum).arg(qec.maximum).arg(qec.step).arg(v).arg(qec.default_value) + flags); w->setStatusTip(w->whatsThis()); break; case V4L2_CTRL_TYPE_INTEGER64: w->setWhatsThis(QString("Type: Integer64\n" - "Current: %1").arg(v) + flags); + "Minimum: %1\n" + "Maximum: %2\n" + "Step: %3\n" + "Current: %4\n" + "Default: %5") + .arg(qec.minimum).arg(qec.maximum).arg(qec.step).arg(v).arg(qec.default_value) + flags); w->setStatusTip(w->whatsThis()); break; @@ -813,8 +751,8 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) "Maximum: %1\n" "Current: %2\n" "Default: %3") - .arg((unsigned)qctrl.maximum, 0, 16).arg((unsigned)v, 0, 16) - .arg((unsigned)qctrl.default_value, 0, 16) + flags); + .arg((unsigned)qec.maximum, 0, 16).arg((unsigned)v, 0, 16) + .arg((unsigned)qec.default_value, 0, 16) + flags); w->setStatusTip(w->whatsThis()); break; @@ -827,7 +765,7 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) w->setWhatsThis(QString("Type: Boolean\n" "Current: %1\n" "Default: %2") - .arg(v).arg(qctrl.default_value) + flags); + .arg(v).arg(qec.default_value) + flags); w->setStatusTip(w->whatsThis()); break; @@ -837,7 +775,7 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) "Maximum: %2\n" "Current: %3\n" "Default: %4") - .arg(qctrl.minimum).arg(qctrl.maximum).arg(v).arg(qctrl.default_value) + flags); + .arg(qec.minimum).arg(qec.maximum).arg(v).arg(qec.default_value) + flags); w->setStatusTip(w->whatsThis()); break; @@ -847,7 +785,7 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) "Maximum: %2\n" "Current: %3\n" "Default: %4") - .arg(qctrl.minimum).arg(qctrl.maximum).arg(v).arg(qctrl.default_value) + flags); + .arg(qec.minimum).arg(qec.maximum).arg(v).arg(qec.default_value) + flags); w->setStatusTip(w->whatsThis()); break; default: @@ -857,16 +795,16 @@ void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) void ApplicationWindow::setVal(unsigned id, int v) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; v4l2_querymenu qmenu; - QWidget *w = m_widgetMap[qctrl.id]; + QWidget *w = m_widgetMap[qec.id]; int i, idx; unsigned dif; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER: - dif = qctrl.maximum - qctrl.minimum; - if (dif <= 0xffffU || (qctrl.flags & V4L2_CTRL_FLAG_SLIDER)) + dif = qec.maximum - qec.minimum; + if (dif <= 0xffffU || (qec.flags & V4L2_CTRL_FLAG_SLIDER)) static_cast(w)->setValue(v); else static_cast(w)->setText(QString::number(v)); @@ -883,7 +821,7 @@ void ApplicationWindow::setVal(unsigned id, int v) case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU: idx = 0; - for (i = qctrl.minimum; i <= v; i++) { + for (i = qec.minimum; i <= v; i++) { qmenu.id = id; qmenu.index = i; if (querymenu(qmenu)) @@ -900,10 +838,10 @@ void ApplicationWindow::setVal(unsigned id, int v) void ApplicationWindow::setVal64(unsigned id, long long v) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; - QWidget *w = m_widgetMap[qctrl.id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; + QWidget *w = m_widgetMap[qec.id]; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_INTEGER64: static_cast(w)->setText(QString::number(v)); break; @@ -915,10 +853,10 @@ void ApplicationWindow::setVal64(unsigned id, long long v) void ApplicationWindow::setString(unsigned id, const QString &v) { - const v4l2_queryctrl &qctrl = m_ctrlMap[id]; - QWidget *w = m_widgetMap[qctrl.id]; + const v4l2_query_ext_ctrl &qec = m_ctrlMap[id]; + QWidget *w = m_widgetMap[qec.id]; - switch (qctrl.type) { + switch (qec.type) { case V4L2_CTRL_TYPE_STRING: static_cast(w)->setText(v); break; diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp index a9c9dc9..472f203 100644 --- a/utils/qv4l2/qv4l2.cpp +++ b/utils/qv4l2/qv4l2.cpp @@ -382,7 +382,7 @@ void ApplicationWindow::ctrlEvent() } if (m_ctrlMap[ev.id].type != V4L2_CTRL_TYPE_STRING) continue; - queryctrl(m_ctrlMap[ev.id]); + query_ext_ctrl(m_ctrlMap[ev.id]); struct v4l2_ext_control c; struct v4l2_ext_controls ctrls; diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h index 7ebc887..a9ec30a 100644 --- a/utils/qv4l2/qv4l2.h +++ b/utils/qv4l2/qv4l2.h @@ -49,7 +49,7 @@ class CaptureWin; typedef std::vector ClassIDVec; typedef std::map ClassMap; -typedef std::map CtrlMap; +typedef std::map CtrlMap; typedef std::map WidgetMap; enum { @@ -171,7 +171,7 @@ private: void fixWidth(QGridLayout *grid); void addTabs(int size[]); void finishGrid(QGridLayout *grid, unsigned ctrl_class); - void addCtrl(QGridLayout *grid, const struct v4l2_queryctrl &qctrl); + void addCtrl(QGridLayout *grid, const struct v4l2_query_ext_ctrl &qec); void updateCtrl(unsigned id); void updateCtrlRange(unsigned id, __s32 val); void subscribeCtrlEvents(); @@ -226,7 +226,6 @@ private: WidgetMap m_widgetMap; WidgetMap m_sliderMap; ClassMap m_classMap; - bool m_haveExtendedUserCtrls; int m_vbiSize; unsigned m_vbiWidth; unsigned m_vbiHeight; diff --git a/utils/v4l2-compliance/cv4l-helpers.h b/utils/v4l2-compliance/cv4l-helpers.h index 7664b05..c0d3195 100644 --- a/utils/v4l2-compliance/cv4l-helpers.h +++ b/utils/v4l2-compliance/cv4l-helpers.h @@ -69,6 +69,26 @@ public: return cv4l_ioctl(VIDIOC_QUERYMENU, &qm); } + int query_ext_ctrl(v4l2_query_ext_ctrl &qec, bool next_ctrl = false, bool next_compound = false) + { + return v4l_query_ext_ctrl(this, &qec, next_ctrl, next_compound); + } + + int g_ext_ctrls(v4l2_ext_controls &ec) + { + return v4l_g_ext_ctrls(this, &ec); + } + + int try_ext_ctrls(v4l2_ext_controls &ec) + { + return v4l_try_ext_ctrls(this, &ec); + } + + int s_ext_ctrls(v4l2_ext_controls &ec) + { + return v4l_s_ext_ctrls(this, &ec); + } + int g_fmt(v4l2_format &fmt, unsigned type = 0) { return v4l_g_fmt(this, &fmt, type); diff --git a/utils/v4l2-compliance/v4l-helpers.h b/utils/v4l2-compliance/v4l-helpers.h index 8362144..1b7546c 100644 --- a/utils/v4l2-compliance/v4l-helpers.h +++ b/utils/v4l2-compliance/v4l-helpers.h @@ -25,6 +25,9 @@ struct v4l_fd { __u32 caps; bool trace; bool direct; + bool have_query_ext_ctrl; + bool have_ext_ctrls; + bool have_next_ctrl; int (*open)(struct v4l_fd *f, const char *file, int oflag, ...); int (*close)(struct v4l_fd *f); @@ -387,6 +390,10 @@ static inline __u32 v4l_determine_type(const struct v4l_fd *f) static inline int v4l_open(struct v4l_fd *f, const char *devname, bool non_blocking) { + struct v4l2_query_ext_ctrl qec = { V4L2_CTRL_FLAG_NEXT_CTRL }; + struct v4l2_ext_controls ec = { 0, 0 }; + struct v4l2_queryctrl qc = { V4L2_CTRL_FLAG_NEXT_CTRL }; + f->fd = f->open(f, devname, O_RDWR | (non_blocking ? O_NONBLOCK : 0)); if (f->fd < 0) @@ -399,6 +406,10 @@ static inline int v4l_open(struct v4l_fd *f, const char *devname, bool non_block v4l_close(f); return -1; } + f->have_query_ext_ctrl = v4l_ioctl(f, VIDIOC_QUERY_EXT_CTRL, &qec) == 0; + f->have_ext_ctrls = v4l_ioctl(f, VIDIOC_TRY_EXT_CTRLS, &ec) == 0; + f->have_next_ctrl = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc) == 0; + f->caps = v4l_capability_g_caps(&f->cap); f->type = v4l_determine_type(f); return f->fd; @@ -1367,6 +1378,134 @@ static inline void v4l_queue_buffer_init(const struct v4l_queue *q, struct v4l_b } } +static inline int v4l_query_ext_ctrl(v4l_fd *f, struct v4l2_query_ext_ctrl *qec, + bool next_ctrl, bool next_compound) +{ + struct v4l2_queryctrl qc; + int ret; + + if (next_compound && !f->have_query_ext_ctrl) { + if (!next_ctrl) + return -EINVAL; + next_compound = false; + } + if (next_compound) + qec->id |= V4L2_CTRL_FLAG_NEXT_COMPOUND; + if (next_ctrl) { + if (f->have_next_ctrl) + qec->id |= V4L2_CTRL_FLAG_NEXT_CTRL; + else + qec->id = qec->id ? qec->id + 1 : V4L2_CID_BASE; + } + if (f->have_query_ext_ctrl) + return v4l_ioctl(f, VIDIOC_QUERY_EXT_CTRL, qec); + + for (;;) { + if (qec->id == V4L2_CID_LASTP1 && next_ctrl) + qec->id = V4L2_CID_PRIVATE_BASE; + qc.id = qec->id; + ret = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc); + if (!ret) + break; + if (ret != EINVAL) + return ret; + if (!next_ctrl || f->have_next_ctrl) + return ret; + if (qec->id >= V4L2_CID_PRIVATE_BASE) + return ret; + qec->id++; + } + qec->id = qc.id; + qec->type = qc.type; + memcpy(qec->name, qc.name, sizeof(qec->name)); + qec->minimum = qc.minimum; + qec->maximum = qc.maximum; + qec->step = qc.step; + qec->default_value = qc.default_value; + qec->flags = qc.flags; + qec->elems = 1; + qec->nr_of_dims = 0; + memset(qec->dims, 0, sizeof(qec->dims)); + switch (qec->type) { + case V4L2_CTRL_TYPE_INTEGER64: + qec->elem_size = sizeof(__s64); + qec->minimum = 0x8000000000000000ULL; + qec->maximum = 0x7fffffffffffffffULL; + qec->step = 1; + break; + case V4L2_CTRL_TYPE_STRING: + qec->elem_size = qc.maximum + 1; + break; + default: + qec->elem_size = sizeof(__s32); + break; + } + memset(qec->reserved, 0, sizeof(qec->reserved)); + return 0; +} + +static inline int v4l_g_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec) +{ + unsigned i; + + if (f->have_ext_ctrls) + return v4l_ioctl(f, VIDIOC_G_EXT_CTRLS, ec); + if (ec->count == 0) + return 0; + for (i = 0; i < ec->count; i++) { + struct v4l2_control c = { ec->controls[i].id }; + int ret = v4l_ioctl(f, VIDIOC_G_CTRL, &c); + + if (ret) { + ec->error_idx = i; + return ret; + } + ec->controls[i].value = c.value; + } + return 0; +} + +static inline int v4l_s_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec) +{ + unsigned i; + + if (f->have_ext_ctrls) + return v4l_ioctl(f, VIDIOC_S_EXT_CTRLS, ec); + if (ec->count == 0) + return 0; + for (i = 0; i < ec->count; i++) { + struct v4l2_control c = { ec->controls[i].id, ec->controls[i].value }; + int ret = v4l_ioctl(f, VIDIOC_S_CTRL, &c); + + if (ret) { + ec->error_idx = i; + return ret; + } + } + return 0; +} + +static inline int v4l_try_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec) +{ + unsigned i; + + if (f->have_ext_ctrls) + return v4l_ioctl(f, VIDIOC_TRY_EXT_CTRLS, ec); + if (ec->count == 0) + return 0; + for (i = 0; i < ec->count; i++) { + struct v4l2_queryctrl qc = { ec->controls[i].id }; + int ret = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc); + + if (ret || qc.type == V4L2_CTRL_TYPE_STRING || + qc.type == V4L2_CTRL_TYPE_INTEGER64) { + ec->error_idx = i; + return ret ? ret : EINVAL; + } + } + return 0; +} + #ifdef __cplusplus } #endif /* __cplusplus */ -- 2.7.4