summaryrefslogtreecommitdiff
path: root/test/qv4l2/qv4l2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/qv4l2/qv4l2.cpp')
-rw-r--r--test/qv4l2/qv4l2.cpp347
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()