qv4l2: use new control helpers
authorHans Verkuil <hans.verkuil@cisco.com>
Sun, 20 Jul 2014 21:44:31 +0000 (23:44 +0200)
committerHans Verkuil <hans.verkuil@cisco.com>
Sun, 20 Jul 2014 21:44:31 +0000 (23:44 +0200)
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 <hans.verkuil@cisco.com>
utils/qv4l2/ctrl-tab.cpp
utils/qv4l2/qv4l2.cpp
utils/qv4l2/qv4l2.h
utils/v4l2-compliance/cv4l-helpers.h
utils/v4l2-compliance/v4l-helpers.h

index c264394..5ff3acc 100644 (file)
@@ -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<QLineEdit *>(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<QLineEdit *>(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<QSpinBox *>(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<QComboBox *>(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<QSlider *>(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<QSpinBox *>(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<QLineEdit *>(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<QLineEdit *>(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<QSpinBox *>(w)->setValue(v);
                else
                        static_cast<QLineEdit *>(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<QLineEdit *>(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<QLineEdit *>(w)->setText(v);
                break;
index a9c9dc9..472f203 100644 (file)
@@ -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;
index 7ebc887..a9ec30a 100644 (file)
@@ -49,7 +49,7 @@ class CaptureWin;
 
 typedef std::vector<unsigned> ClassIDVec;
 typedef std::map<unsigned, ClassIDVec> ClassMap;
-typedef std::map<unsigned, struct v4l2_queryctrl> CtrlMap;
+typedef std::map<unsigned, struct v4l2_query_ext_ctrl> CtrlMap;
 typedef std::map<unsigned, QWidget *> 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;
index 7664b05..c0d3195 100644 (file)
@@ -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);
index 8362144..1b7546c 100644 (file)
@@ -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 */