3
#include "libv4l2util.h"
5
#include <qstatusbar.h>
7
#include <qvalidator.h>
14
#include <qcombobox.h>
15
#include <qcheckbox.h>
16
#include <qpushbutton.h>
18
#include <qwhatsthis.h>
21
#include <sys/ioctl.h>
24
void ApplicationWindow::addTabs()
26
struct v4l2_queryctrl qctrl;
31
memset(&qctrl, 0, sizeof(qctrl));
32
qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
33
while (::ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) {
34
if ((qctrl.flags & V4L2_CTRL_FLAG_DISABLED) == 0) {
35
ctrlMap[qctrl.id] = qctrl;
36
if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS)
37
classMap[V4L2_CTRL_ID2CLASS(qctrl.id)].push_back(qctrl.id);
39
qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
41
if (qctrl.id == V4L2_CTRL_FLAG_NEXT_CTRL) {
42
strcpy((char *)qctrl.name, "User Controls");
43
qctrl.id = V4L2_CTRL_CLASS_USER | 1;
44
qctrl.type = V4L2_CTRL_TYPE_CTRL_CLASS;
45
ctrlMap[qctrl.id] = qctrl;
46
for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) {
48
if (::ioctl(fd, VIDIOC_QUERYCTRL, &qctrl))
50
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
52
ctrlMap[qctrl.id] = qctrl;
53
classMap[V4L2_CTRL_CLASS_USER].push_back(qctrl.id);
55
for (qctrl.id = V4L2_CID_PRIVATE_BASE;
56
::ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) {
57
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
59
ctrlMap[qctrl.id] = qctrl;
60
classMap[V4L2_CTRL_CLASS_USER].push_back(qctrl.id);
64
for (ClassMap::iterator iter = classMap.begin(); iter != classMap.end(); ++iter) {
65
ctrl_class = V4L2_CTRL_ID2CLASS(iter->second[0]);
67
const struct v4l2_queryctrl &qctrl = ctrlMap[id];
68
QVBox *vbox = new QVBox(tabs);
69
QGrid *grid = new QGrid(4, vbox);
71
tabs->addTab(vbox, (char *)qctrl.name);
72
for (i = 0; i < iter->second.size(); i++) {
74
id = iter->second[(1+iter->second.size()) / 2 + i / 2];
76
id = iter->second[i / 2];
77
addCtrl(grid, ctrlMap[id]);
79
finishGrid(vbox, grid, ctrl_class, i & 1);
83
void ApplicationWindow::finishGrid(QWidget *vbox, QGrid *grid, unsigned ctrl_class, bool odd)
89
QWidget *stretch = new QWidget(grid);
90
stretch->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
92
QFrame *frame = new QFrame(vbox);
93
frame->setFrameShape(QFrame::HLine);
94
frame->setFrameShadow(QFrame::Sunken);
97
QHBox *hbox = new QHBox(vbox);
100
QCheckBox *cbox = new QCheckBox("Update on change", hbox);
101
widgetMap[ctrl_class | CTRL_UPDATE_ON_CHANGE] = cbox;
102
connect(cbox, SIGNAL(clicked()), sigMapper, SLOT(map()));
103
sigMapper->setMapping(cbox, ctrl_class | CTRL_UPDATE_ON_CHANGE);
105
stretch = new QWidget(hbox);
106
stretch->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
108
QPushButton *defBut = new QPushButton("Set Defaults", hbox);
109
widgetMap[ctrl_class | CTRL_DEFAULTS] = defBut;
110
connect(defBut, SIGNAL(clicked()), sigMapper, SLOT(map()));
111
sigMapper->setMapping(defBut, ctrl_class | CTRL_DEFAULTS);
113
QPushButton *refreshBut = new QPushButton("Refresh", hbox);
114
widgetMap[ctrl_class | CTRL_REFRESH] = refreshBut;
115
connect(refreshBut, SIGNAL(clicked()), sigMapper, SLOT(map()));
116
sigMapper->setMapping(refreshBut, ctrl_class | CTRL_REFRESH);
118
QPushButton *button = new QPushButton("Update", hbox);
119
widgetMap[ctrl_class | CTRL_UPDATE] = button;
120
connect(button, SIGNAL(clicked()), sigMapper, SLOT(map()));
121
sigMapper->setMapping(button, ctrl_class | CTRL_UPDATE);
122
connect(cbox, SIGNAL(toggled(bool)), button, SLOT(setDisabled(bool)));
124
cbox->setChecked(ctrl_class == V4L2_CTRL_CLASS_USER);
129
void ApplicationWindow::addCtrl(QGrid *grid, const struct v4l2_queryctrl &qctrl)
133
QString name((char *)qctrl.name);
135
struct v4l2_querymenu qmenu;
137
QLabel *label = new QLabel(name, grid);
138
label->setAlignment(Qt::AlignRight);
140
switch (qctrl.type) {
141
case V4L2_CTRL_TYPE_INTEGER:
142
if (qctrl.flags & V4L2_CTRL_FLAG_SLIDER) {
143
widgetMap[qctrl.id] =
144
new QSlider(qctrl.minimum, qctrl.maximum,
145
qctrl.step, qctrl.default_value,
147
connect(widgetMap[qctrl.id], SIGNAL(valueChanged(int)),
148
sigMapper, SLOT(map()));
152
if (qctrl.maximum - qctrl.minimum <= 255) {
153
widgetMap[qctrl.id] =
154
new QSpinBox(qctrl.minimum, qctrl.maximum, 1, grid);
155
connect(widgetMap[qctrl.id], SIGNAL(valueChanged(int)),
156
sigMapper, SLOT(map()));
160
val = new QIntValidator(qctrl.minimum, qctrl.maximum, grid);
161
edit = new QLineEdit(grid);
162
edit->setValidator(val);
163
widgetMap[qctrl.id] = edit;
164
connect(widgetMap[qctrl.id], SIGNAL(lostFocus()),
165
sigMapper, SLOT(map()));
166
connect(widgetMap[qctrl.id], SIGNAL(returnPressed()),
167
sigMapper, SLOT(map()));
170
case V4L2_CTRL_TYPE_INTEGER64:
171
widgetMap[qctrl.id] = new QLineEdit(grid);
172
connect(widgetMap[qctrl.id], SIGNAL(lostFocus()),
173
sigMapper, SLOT(map()));
174
connect(widgetMap[qctrl.id], SIGNAL(returnPressed()),
175
sigMapper, SLOT(map()));
178
case V4L2_CTRL_TYPE_BOOLEAN:
180
widgetMap[qctrl.id] = new QCheckBox(name, grid);
181
connect(widgetMap[qctrl.id], SIGNAL(clicked()),
182
sigMapper, SLOT(map()));
185
case V4L2_CTRL_TYPE_BUTTON:
187
widgetMap[qctrl.id] = new QPushButton((char *)qctrl.name, grid);
188
connect(widgetMap[qctrl.id], SIGNAL(clicked()),
189
sigMapper, SLOT(map()));
192
case V4L2_CTRL_TYPE_MENU:
193
combo = new QComboBox(grid);
194
widgetMap[qctrl.id] = combo;
195
for (int i = qctrl.minimum; i <= qctrl.maximum; i++) {
198
if (::ioctl(fd, VIDIOC_QUERYMENU, &qmenu))
200
combo->insertItem((char *)qmenu.name);
202
connect(widgetMap[qctrl.id], SIGNAL(activated(int)),
203
sigMapper, SLOT(map()));
209
sigMapper->setMapping(widgetMap[qctrl.id], qctrl.id);
210
if (qctrl.flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_INACTIVE))
211
widgetMap[qctrl.id]->setDisabled(true);
214
void ApplicationWindow::ctrlAction(int id)
216
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
217
if (ctrl_class == V4L2_CID_PRIVATE_BASE)
218
ctrl_class = V4L2_CTRL_CLASS_USER;
219
unsigned ctrl = id & 0xffff;
220
QCheckBox *cbox = static_cast<QCheckBox *>(widgetMap[ctrl_class | CTRL_UPDATE_ON_CHANGE]);
221
bool update = cbox->isChecked();
222
bool all = (ctrl == CTRL_UPDATE || (update && ctrl == CTRL_UPDATE_ON_CHANGE));
224
if (ctrl == CTRL_DEFAULTS) {
225
setDefaults(ctrl_class);
228
if (ctrl == CTRL_REFRESH) {
232
if (!update && !all && ctrlMap[id].type != V4L2_CTRL_TYPE_BUTTON)
234
if (ctrl_class == V4L2_CTRL_CLASS_USER) {
239
for (unsigned i = 0; i < classMap[ctrl_class].size(); i++) {
240
updateCtrl(classMap[ctrl_class][i]);
248
unsigned count = classMap[ctrl_class].size();
249
struct v4l2_ext_control *c = new v4l2_ext_control[count];
250
struct v4l2_ext_controls ctrls;
253
for (unsigned i = 0; i < count; i++) {
254
unsigned id = classMap[ctrl_class][i];
256
if (ctrlMap[id].flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_INACTIVE))
259
if (ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64)
260
c[idx].value64 = getVal64(id);
262
c[idx].value = getVal(id);
265
memset(&ctrls, 0, sizeof(ctrls));
267
ctrls.ctrl_class = ctrl_class;
269
if (::ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) {
272
if (ctrls.error_idx >= ctrls.count) {
273
printf("error: %s\n", strerror(err));
276
id = c[ctrls.error_idx].id;
277
printf("error %08x (%s): %s\n", id,
278
ctrlMap[id].name, strerror(err));
285
long long ApplicationWindow::getVal64(unsigned id)
287
const v4l2_queryctrl &qctrl = ctrlMap[id];
288
QWidget *w = widgetMap[qctrl.id];
291
switch (qctrl.type) {
292
case V4L2_CTRL_TYPE_INTEGER64:
293
v = static_cast<QLineEdit *>(w)->text().toLongLong();
302
int ApplicationWindow::getVal(unsigned id)
304
const v4l2_queryctrl &qctrl = ctrlMap[id];
305
QWidget *w = widgetMap[qctrl.id];
306
v4l2_querymenu qmenu;
310
switch (qctrl.type) {
311
case V4L2_CTRL_TYPE_INTEGER:
312
if (qctrl.flags & V4L2_CTRL_FLAG_SLIDER) {
313
v = static_cast<QSlider *>(w)->value();
317
if (qctrl.maximum - qctrl.minimum <= 255) {
318
v = static_cast<QSpinBox *>(w)->value();
321
v = static_cast<QLineEdit *>(w)->text().toInt();
324
case V4L2_CTRL_TYPE_BOOLEAN:
325
v = static_cast<QCheckBox *>(w)->isChecked();
328
case V4L2_CTRL_TYPE_MENU:
329
idx = static_cast<QComboBox *>(w)->currentItem();
330
for (i = qctrl.minimum; i <= qctrl.maximum; i++) {
333
if (::ioctl(fd, VIDIOC_QUERYMENU, &qmenu))
348
void ApplicationWindow::updateCtrl(unsigned id)
350
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
351
if (ctrl_class == V4L2_CID_PRIVATE_BASE)
352
ctrl_class = V4L2_CTRL_CLASS_USER;
354
if (ctrlMap[id].flags & (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_INACTIVE))
357
if (ctrl_class == V4L2_CTRL_CLASS_USER) {
358
struct v4l2_control c;
361
c.value = getVal(id);
362
if (::ioctl(fd, VIDIOC_S_CTRL, &c)) {
366
sprintf(buf, "Error %08x (%s): %s", id,
367
ctrlMap[id].name, strerror(err));
368
statusBar()->message(buf, 10000);
372
struct v4l2_ext_control c;
373
struct v4l2_ext_controls ctrls;
375
memset(&c, 0, sizeof(c));
376
memset(&ctrls, 0, sizeof(ctrls));
378
if (ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64)
379
c.value64 = getVal64(id);
381
c.value = getVal(id);
383
ctrls.ctrl_class = ctrl_class;
385
if (::ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) {
389
sprintf(buf, "Error %08x (%s): %s", id,
390
ctrlMap[id].name, strerror(err));
391
statusBar()->message(buf, 10000);
393
else if (ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE)
396
if (ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64)
397
setVal64(id, c.value64);
403
void ApplicationWindow::refresh(unsigned ctrl_class)
405
if (ctrl_class == V4L2_CTRL_CLASS_USER) {
406
for (unsigned i = 0; i < classMap[ctrl_class].size(); i++) {
407
unsigned id = classMap[ctrl_class][i];
412
if (::ioctl(fd, VIDIOC_G_CTRL, &c)) {
416
sprintf(buf, "Error %08x (%s): %s", id,
417
ctrlMap[id].name, strerror(err));
418
statusBar()->message(buf, 10000);
424
unsigned count = classMap[ctrl_class].size();
425
struct v4l2_ext_control *c = new v4l2_ext_control[count];
426
struct v4l2_ext_controls ctrls;
428
for (unsigned i = 0; i < count; i++) {
429
c[i].id = classMap[ctrl_class][i];
431
memset(&ctrls, 0, sizeof(ctrls));
433
ctrls.ctrl_class = ctrl_class;
435
if (::ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) {
438
if (ctrls.error_idx >= ctrls.count) {
439
statusBar()->message(strerror(err), 10000);
442
unsigned id = c[ctrls.error_idx].id;
445
sprintf(buf, "Error %08x (%s): %s", id,
446
ctrlMap[id].name, strerror(err));
447
statusBar()->message(buf, 10000);
451
for (unsigned i = 0; i < ctrls.count; i++) {
452
unsigned id = c[i].id;
453
if (ctrlMap[id].type == V4L2_CTRL_TYPE_INTEGER64)
454
setVal64(id, c[i].value64);
456
setVal(id, c[i].value);
457
::ioctl(fd, VIDIOC_QUERYCTRL, &ctrlMap[id]);
458
widgetMap[id]->setDisabled(ctrlMap[id].flags &
459
(V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_INACTIVE));
465
void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v)
467
const v4l2_queryctrl &qctrl = ctrlMap[id];
469
QString flags = getCtrlFlags(qctrl.flags);
471
switch (qctrl.type) {
472
case V4L2_CTRL_TYPE_INTEGER:
473
QWhatsThis::add(w, what.sprintf("Integer type control\n"
478
qctrl.minimum, qctrl.maximum, (int)v, qctrl.default_value) + flags);
481
case V4L2_CTRL_TYPE_INTEGER64:
482
QWhatsThis::add(w, what.sprintf("64-bit Integer type control\n"
483
"Current: %lld\n", v) + flags);
486
case V4L2_CTRL_TYPE_BUTTON:
487
QWhatsThis::add(w, what.sprintf("Button type control\n") + flags);
490
case V4L2_CTRL_TYPE_BOOLEAN:
491
QWhatsThis::add(w, what.sprintf("Boolean type control\n"
494
(int)v, qctrl.default_value) + flags);
497
case V4L2_CTRL_TYPE_MENU:
498
QWhatsThis::add(w, what.sprintf("Menu type control\n"
503
qctrl.minimum, qctrl.maximum, (int)v, qctrl.default_value) + flags);
510
void ApplicationWindow::setVal(unsigned id, int v)
512
const v4l2_queryctrl &qctrl = ctrlMap[id];
513
v4l2_querymenu qmenu;
514
QWidget *w = widgetMap[qctrl.id];
517
switch (qctrl.type) {
518
case V4L2_CTRL_TYPE_INTEGER:
519
if (qctrl.flags & V4L2_CTRL_FLAG_SLIDER)
520
static_cast<QSlider *>(w)->setValue(v);
521
else if (qctrl.maximum - qctrl.minimum <= 255)
522
static_cast<QSpinBox *>(w)->setValue(v);
524
static_cast<QLineEdit *>(w)->setText(QString::number(v));
527
case V4L2_CTRL_TYPE_BOOLEAN:
528
static_cast<QCheckBox *>(w)->setChecked(v);
531
case V4L2_CTRL_TYPE_MENU:
533
for (i = qctrl.minimum; i <= v; i++) {
536
if (::ioctl(fd, VIDIOC_QUERYMENU, &qmenu))
540
static_cast<QComboBox *>(w)->setCurrentItem(idx - 1);
548
void ApplicationWindow::setVal64(unsigned id, long long v)
550
const v4l2_queryctrl &qctrl = ctrlMap[id];
551
QWidget *w = widgetMap[qctrl.id];
553
switch (qctrl.type) {
554
case V4L2_CTRL_TYPE_INTEGER64:
555
static_cast<QLineEdit *>(w)->setText(QString::number(v));
563
void ApplicationWindow::setDefaults(unsigned ctrl_class)
565
for (unsigned i = 0; i < classMap[ctrl_class].size(); i++) {
566
unsigned id = classMap[ctrl_class][i];
568
if (ctrlMap[id].type != V4L2_CTRL_TYPE_INTEGER64 &&
569
ctrlMap[id].type != V4L2_CTRL_TYPE_BUTTON)
570
setVal(id, ctrlMap[id].default_value);
572
ctrlAction(ctrl_class | CTRL_UPDATE);
575
QString ApplicationWindow::getCtrlFlags(unsigned flags)
579
if (flags & V4L2_CTRL_FLAG_GRABBED)
581
if (flags & V4L2_CTRL_FLAG_READ_ONLY)
583
if (flags & V4L2_CTRL_FLAG_UPDATE)
585
if (flags & V4L2_CTRL_FLAG_INACTIVE)
587
if (flags & V4L2_CTRL_FLAG_SLIDER)
589
if (s.length()) s = QString("Flags: ") + s;