diff options
Diffstat (limited to 'test/qv4l2/qv4l2.cpp')
-rw-r--r-- | test/qv4l2/qv4l2.cpp | 347 |
1 files changed, 321 insertions, 26 deletions
diff --git a/test/qv4l2/qv4l2.cpp b/test/qv4l2/qv4l2.cpp index ba43ad5c8..a4c675d48 100644 --- a/test/qv4l2/qv4l2.cpp +++ b/test/qv4l2/qv4l2.cpp @@ -1,5 +1,6 @@ #include "qv4l2.h" +#include "frequencies.h" #include <qimage.h> #include <qpixmap.h> @@ -24,6 +25,7 @@ #include <qcombobox.h> #include <qcheckbox.h> #include <qpushbutton.h> +#include <qtooltip.h> #include <qpainter.h> #include <qpaintdevicemetrics.h> #include <qwhatsthis.h> @@ -115,7 +117,14 @@ void ApplicationWindow::setDevice(const QString &device) ctrlMap.clear(); widgetMap.clear(); classMap.clear(); + videoInput = NULL; + videoOutput = NULL; audioInput = NULL; + audioOutput = NULL; + tvStandard = NULL; + freq = NULL; + freqChannel = NULL; + freqTable = NULL; fd = ::open(device, O_RDONLY); if (fd >= 0) { @@ -138,17 +147,21 @@ void ApplicationWindow::addGeneralTab() grid->setSpacing(3); tabs->addTab(vbox, "General"); + memset(&tuner, 0, sizeof(tuner)); + ioctl(fd, VIDIOC_G_TUNER, &tuner); + struct v4l2_input vin; memset(&vin, 0, sizeof(vin)); if (ioctl(fd, VIDIOC_ENUMINPUT, &vin) >= 0) { QLabel *label = new QLabel("Input", grid); label->setAlignment(Qt::AlignRight); - QComboBox *combo = new QComboBox(grid); + videoInput = new QComboBox(grid); while (ioctl(fd, VIDIOC_ENUMINPUT, &vin) >= 0) { - combo->insertItem((char *)vin.name); + videoInput->insertItem((char *)vin.name); vin.index++; } - connect(combo, SIGNAL(activated(int)), SLOT(inputChanged(int))); + connect(videoInput, SIGNAL(activated(int)), SLOT(inputChanged(int))); + updateVideoInput(); cnt++; } @@ -157,12 +170,13 @@ void ApplicationWindow::addGeneralTab() if (ioctl(fd, VIDIOC_ENUMOUTPUT, &vout) >= 0) { QLabel *label = new QLabel("Output", grid); label->setAlignment(Qt::AlignRight); - QComboBox *combo = new QComboBox(grid); + videoOutput = new QComboBox(grid); while (ioctl(fd, VIDIOC_ENUMOUTPUT, &vout) >= 0) { - combo->insertItem((char *)vout.name); + videoOutput->insertItem((char *)vout.name); vout.index++; } - connect(combo, SIGNAL(activated(int)), SLOT(outputChanged(int))); + connect(videoOutput, SIGNAL(activated(int)), SLOT(outputChanged(int))); + updateVideoOutput(); cnt++; } @@ -178,6 +192,7 @@ void ApplicationWindow::addGeneralTab() vaudio.index++; } connect(audioInput, SIGNAL(activated(int)), SLOT(inputAudioChanged(int))); + updateAudioInput(); cnt++; } @@ -186,12 +201,74 @@ void ApplicationWindow::addGeneralTab() if (ioctl(fd, VIDIOC_ENUMAUDOUT, &vaudioout) >= 0) { QLabel *label = new QLabel("Output Audio", grid); label->setAlignment(Qt::AlignRight); - QComboBox *combo = new QComboBox(grid); + audioOutput = new QComboBox(grid); while (ioctl(fd, VIDIOC_ENUMAUDOUT, &vaudioout) >= 0) { - combo->insertItem((char *)vaudioout.name); + audioOutput->insertItem((char *)vaudioout.name); vaudioout.index++; } - connect(combo, SIGNAL(activated(int)), SLOT(outputAudioChanged(int))); + connect(audioOutput, SIGNAL(activated(int)), SLOT(outputAudioChanged(int))); + updateAudioOutput(); + cnt++; + } + + struct v4l2_standard vs; + memset(&vs, 0, sizeof(vs)); + if (ioctl(fd, VIDIOC_ENUMSTD, &vs) >= 0) { + QLabel *label = new QLabel("TV Standard", grid); + label->setAlignment(Qt::AlignRight); + tvStandard = new QComboBox(grid); + while (ioctl(fd, VIDIOC_ENUMSTD, &vs) >= 0) { + tvStandard->insertItem((char *)vs.name); + vs.index++; + } + connect(tvStandard, SIGNAL(activated(int)), SLOT(standardChanged(int))); + updateStandard(); + cnt++; + } + + bool first = cnt & 1; + + if (first) { + QString what; + QLabel *label = new QLabel("Frequency", grid); + label->setAlignment(Qt::AlignRight); + freq = new QSpinBox(tuner.rangelow, tuner.rangehigh, 1, grid); + QWhatsThis::add(freq, what.sprintf("Frequency\n" + "Low: %d\n" + "High: %d\n", + tuner.rangelow, tuner.rangehigh)); + connect(freq, SIGNAL(valueChanged(int)), SLOT(freqChanged(int))); + updateFreq(); + cnt++; + } + + { + QLabel *label = new QLabel("Frequency Tables", grid); + label->setAlignment(Qt::AlignRight); + freqTable = new QComboBox(grid); + for (int i = 0; chanlists[i].name; i++) { + freqTable->insertItem(chanlists[i].name); + } + connect(freqTable, SIGNAL(activated(int)), SLOT(freqTableChanged(int))); + + label = new QLabel("Channels", grid); + label->setAlignment(Qt::AlignRight); + freqChannel = new QComboBox(grid); + connect(freqChannel, SIGNAL(activated(int)), SLOT(freqChannelChanged(int))); + updateFreqChannel(); + } + + if (!first) { + QString what; + QLabel *label = new QLabel("Frequency", grid); + label->setAlignment(Qt::AlignRight); + freq = new QSpinBox(tuner.rangelow, tuner.rangehigh, 1, grid); + QWhatsThis::add(freq, what.sprintf("Frequency\n" + "Low: %d\n" + "High: %d\n", + tuner.rangelow, tuner.rangehigh)); + connect(freq, SIGNAL(valueChanged(int)), SLOT(freqChanged(int))); + updateFreq(); cnt++; } @@ -468,13 +545,17 @@ long long ApplicationWindow::getVal64(unsigned id) { const v4l2_queryctrl &qctrl = ctrlMap[id]; QWidget *w = widgetMap[qctrl.id]; + long long v = 0; switch (qctrl.type) { case V4L2_CTRL_TYPE_INTEGER64: - return static_cast<QLineEdit *>(w)->text().toLongLong(); + v = static_cast<QLineEdit *>(w)->text().toLongLong(); + break; default: - return 0; + break; } + setWhat(w, id, v); + return v; } int ApplicationWindow::getVal(unsigned id) @@ -483,20 +564,25 @@ int ApplicationWindow::getVal(unsigned id) QWidget *w = widgetMap[qctrl.id]; v4l2_querymenu qmenu; int i, idx; + int v = 0; switch (qctrl.type) { case V4L2_CTRL_TYPE_INTEGER: if (qctrl.flags & V4L2_CTRL_FLAG_SLIDER) { - return static_cast<QSlider *>(w)->value(); + v = static_cast<QSlider *>(w)->value(); + break; } if (qctrl.maximum - qctrl.minimum <= 255) { - return static_cast<QSpinBox *>(w)->value(); + v = static_cast<QSpinBox *>(w)->value(); + break; } - return static_cast<QLineEdit *>(w)->text().toInt(); + v = static_cast<QLineEdit *>(w)->text().toInt(); + break; case V4L2_CTRL_TYPE_BOOLEAN: - return static_cast<QCheckBox *>(w)->isChecked(); + v = static_cast<QCheckBox *>(w)->isChecked(); + break; case V4L2_CTRL_TYPE_MENU: idx = static_cast<QComboBox *>(w)->currentItem(); @@ -508,12 +594,14 @@ int ApplicationWindow::getVal(unsigned id) if (idx-- == 0) break; } - return i; + v = i; + break; default: break; } - return 0; + setWhat(w, id, v); + return v; } void ApplicationWindow::updateCtrl(unsigned id) @@ -532,9 +620,11 @@ void ApplicationWindow::updateCtrl(unsigned id) c.value = getVal(id); if (::ioctl(fd, VIDIOC_S_CTRL, &c)) { int err = errno; + char buf[200]; - printf("error %08x (%s): %s\n", id, + sprintf(buf, "Error %08x (%s): %s", id, ctrlMap[id].name, strerror(err)); + statusBar()->message(buf, 10000); } return; } @@ -553,9 +643,11 @@ void ApplicationWindow::updateCtrl(unsigned id) ctrls.controls = &c; if (::ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) { int err = errno; + char buf[200]; - printf("error %08x (%s): %s\n", id, + sprintf(buf, "Error %08x (%s): %s", id, ctrlMap[id].name, strerror(err)); + statusBar()->message(buf, 10000); } else if (ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE) refresh(ctrl_class); @@ -578,9 +670,11 @@ void ApplicationWindow::refresh(unsigned ctrl_class) c.id = id; if (::ioctl(fd, VIDIOC_G_CTRL, &c)) { int err = errno; + char buf[200]; - printf("error %08x (%s): %s\n", id, + sprintf(buf, "Error %08x (%s): %s", id, ctrlMap[id].name, strerror(err)); + statusBar()->message(buf, 10000); } setVal(id, c.value); } @@ -601,12 +695,15 @@ void ApplicationWindow::refresh(unsigned ctrl_class) int err = errno; if (ctrls.error_idx >= ctrls.count) { - printf("error: %s\n", strerror(err)); + statusBar()->message(strerror(err), 10000); } else { unsigned id = c[ctrls.error_idx].id; - printf("error %08x (%s): %s\n", id, + char buf[200]; + + sprintf(buf, "Error %08x (%s): %s", id, ctrlMap[id].name, strerror(err)); + statusBar()->message(buf, 10000); } } else { @@ -624,6 +721,51 @@ void ApplicationWindow::refresh(unsigned ctrl_class) delete [] c; } +void ApplicationWindow::setWhat(QWidget *w, unsigned id, long long v) +{ + const v4l2_queryctrl &qctrl = ctrlMap[id]; + QString what; + QString flags = getCtrlFlags(qctrl.flags); + + switch (qctrl.type) { + case V4L2_CTRL_TYPE_INTEGER: + QWhatsThis::add(w, what.sprintf("Integer type control\n" + "Minimum: %d\n" + "Maximum: %d\n" + "Current: %d\n" + "Default: %d\n", + qctrl.minimum, qctrl.maximum, (int)v, qctrl.default_value) + flags); + break; + + case V4L2_CTRL_TYPE_INTEGER64: + QWhatsThis::add(w, what.sprintf("64-bit Integer type control\n" + "Current: %lld\n", v) + flags); + break; + + case V4L2_CTRL_TYPE_BUTTON: + QWhatsThis::add(w, what.sprintf("Button type control\n") + flags); + break; + + case V4L2_CTRL_TYPE_BOOLEAN: + QWhatsThis::add(w, what.sprintf("Boolean type control\n" + "Current: %d\n" + "Default: %d\n", + (int)v, qctrl.default_value) + flags); + break; + + case V4L2_CTRL_TYPE_MENU: + QWhatsThis::add(w, what.sprintf("Menu type control\n" + "Minimum: %d\n" + "Maximum: %d\n" + "Current: %d\n" + "Default: %d\n", + qctrl.minimum, qctrl.maximum, (int)v, qctrl.default_value) + flags); + break; + default: + break; + } +} + void ApplicationWindow::setVal(unsigned id, int v) { const v4l2_queryctrl &qctrl = ctrlMap[id]; @@ -659,6 +801,7 @@ void ApplicationWindow::setVal(unsigned id, int v) default: break; } + setWhat(w, id, v); } void ApplicationWindow::setVal64(unsigned id, long long v) @@ -673,6 +816,7 @@ void ApplicationWindow::setVal64(unsigned id, long long v) default: break; } + setWhat(w, id, v); } void ApplicationWindow::setDefaults(unsigned ctrl_class) @@ -687,6 +831,24 @@ void ApplicationWindow::setDefaults(unsigned ctrl_class) ctrlAction(ctrl_class | CTRL_UPDATE); } +QString ApplicationWindow::getCtrlFlags(unsigned flags) +{ + QString s; + + if (flags & V4L2_CTRL_FLAG_GRABBED) + s += "grabbed "; + if (flags & V4L2_CTRL_FLAG_READ_ONLY) + s += "readonly "; + if (flags & V4L2_CTRL_FLAG_UPDATE) + s += "update "; + if (flags & V4L2_CTRL_FLAG_INACTIVE) + s += "inactive "; + if (flags & V4L2_CTRL_FLAG_SLIDER) + s += "slider "; + if (s.length()) s = QString("Flags: ") + s; + return s; +} + void ApplicationWindow::choose() { QString fn = QFileDialog::getOpenFileName( "/dev/v4l", QString::null, @@ -706,17 +868,20 @@ void ApplicationWindow::closeEvent( QCloseEvent* ce ) void ApplicationWindow::inputChanged(int input) { - ioctl(fd, VIDIOC_S_INPUT, &input); + doIoctl("Set Input", VIDIOC_S_INPUT, &input); struct v4l2_audio vaudio; memset(&vaudio, 0, sizeof(vaudio)); if (audioInput && ioctl(fd, VIDIOC_G_AUDIO, &vaudio) >= 0) { audioInput->setCurrentItem(vaudio.index); + updateAudioInput(); } + updateVideoInput(); } void ApplicationWindow::outputChanged(int output) { - ioctl(fd, VIDIOC_S_OUTPUT, &output); + doIoctl("Set Output", VIDIOC_S_OUTPUT, &output); + updateVideoOutput(); } void ApplicationWindow::inputAudioChanged(int input) @@ -724,7 +889,8 @@ void ApplicationWindow::inputAudioChanged(int input) struct v4l2_audio vaudio; memset(&vaudio, 0, sizeof(vaudio)); vaudio.index = input; - ioctl(fd, VIDIOC_S_AUDIO, &vaudio); + doIoctl("Set Audio Input", VIDIOC_S_AUDIO, &vaudio); + updateAudioInput(); } void ApplicationWindow::outputAudioChanged(int output) @@ -732,7 +898,136 @@ void ApplicationWindow::outputAudioChanged(int output) struct v4l2_audioout vaudioout; memset(&vaudioout, 0, sizeof(vaudioout)); vaudioout.index = output; - ioctl(fd, VIDIOC_S_AUDOUT, &vaudioout); + doIoctl("Set Audio Output", VIDIOC_S_AUDOUT, &vaudioout); + updateAudioOutput(); +} + +void ApplicationWindow::standardChanged(int std) +{ + struct v4l2_standard vs; + memset(&vs, 0, sizeof(vs)); + vs.index = std; + ioctl(fd, VIDIOC_ENUMSTD, &vs); + doIoctl("Set TV Standard", VIDIOC_S_STD, &vs.id); + updateStandard(); +} + +void ApplicationWindow::freqTableChanged(int) +{ + updateFreqChannel(); + freqChannelChanged(0); +} + +void ApplicationWindow::freqChannelChanged(int idx) +{ + freq->setValue((int)(chanlists[freqTable->currentItem()].list[idx].freq / 62.5)); +} + +void ApplicationWindow::freqChanged(int val) +{ + struct v4l2_frequency f; + + memset(&f, 0, sizeof(f)); + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = val; + doIoctl("Set frequency", VIDIOC_S_FREQUENCY, &f); +} + +void ApplicationWindow::updateVideoInput() +{ + int input; + + ioctl(fd, VIDIOC_G_INPUT, &input); + videoInput->setCurrentItem(input); +} + +void ApplicationWindow::updateVideoOutput() +{ + int output; + + ioctl(fd, VIDIOC_G_OUTPUT, &output); + videoOutput->setCurrentItem(output); +} + +void ApplicationWindow::updateAudioInput() +{ + struct v4l2_audio audio; + QString what; + + memset(&audio, 0, sizeof(audio)); + ioctl(fd, VIDIOC_G_AUDIO, &audio); + audioInput->setCurrentItem(audio.index); + if (audio.capability & V4L2_AUDCAP_STEREO) + what = "stereo input"; + else + what = "mono input"; + if (audio.capability & V4L2_AUDCAP_AVL) + what += ", has AVL"; + if (audio.mode & V4L2_AUDMODE_AVL) + what += ", AVL is on"; + QWhatsThis::add(audioInput, what); +} + +void ApplicationWindow::updateAudioOutput() +{ + struct v4l2_audioout audio; + + memset(&audio, 0, sizeof(audio)); + ioctl(fd, VIDIOC_G_AUDOUT, &audio); + audioOutput->setCurrentItem(audio.index); +} + +void ApplicationWindow::updateStandard() +{ + v4l2_std_id std; + struct v4l2_standard vs; + QString what; + ioctl(fd, VIDIOC_G_STD, &std); + memset(&vs, 0, sizeof(vs)); + while (ioctl(fd, VIDIOC_ENUMSTD, &vs) != -1) { + if (vs.id & std) { + tvStandard->setCurrentItem(vs.index); + what.sprintf("TV Standard (0x%llX)\n" + "Frame period: %f (%d/%d)\n" + "Frame lines: %d\n", std, + (double)vs.frameperiod.numerator / vs.frameperiod.denominator, + vs.frameperiod.numerator, vs.frameperiod.denominator, + vs.framelines); + QWhatsThis::add(tvStandard, what); + return; + } + vs.index++; + } +} + +void ApplicationWindow::updateFreq() +{ + struct v4l2_frequency f; + + memset(&f, 0, sizeof(f)); + ioctl(fd, VIDIOC_G_FREQUENCY, &f); + freq->setValue(f.frequency); +} + +void ApplicationWindow::updateFreqChannel() +{ + freqChannel->clear(); + int tbl = freqTable->currentItem(); + struct CHANLIST *list = chanlists[tbl].list; + for (int i = 0; i < chanlists[tbl].count; i++) + freqChannel->insertItem(list[i].name); +} + +bool ApplicationWindow::doIoctl(QString descr, unsigned cmd, void *arg) +{ + statusBar()->clear(); + int err = ioctl(fd, cmd, arg); + + if (err == -1) { + QString s = strerror(errno); + statusBar()->message(descr + ": " + s, 10000); + } + return err != -1; } void ApplicationWindow::about() |