aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-07-25 16:24:39 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2014-07-25 16:28:30 +0200
commit9f2bd0777bfa1c1118b506663f99d2086805b59f (patch)
treeeab5a3b399c75f345be82fc291069a54b2b40938
parent3ab2d8c43c37205de92f84e865a46eadb9f0cf44 (diff)
qv4l2: add support for output video devices
Hook the test pattern generator into qv4l2, allowing it to be used as a generator for video output devices. Careful attention has been given to correct colorspace and RGB quantization handling. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--utils/qv4l2/Makefile.am7
-rw-r--r--utils/qv4l2/general-tab.cpp18
-rw-r--r--utils/qv4l2/general-tab.h16
-rw-r--r--utils/qv4l2/qv4l2.cpp215
-rw-r--r--utils/qv4l2/qv4l2.h40
-rw-r--r--utils/qv4l2/tpg-tab.cpp362
-rw-r--r--utils/v4l2-compliance/cv4l-helpers.h22
7 files changed, 633 insertions, 47 deletions
diff --git a/utils/qv4l2/Makefile.am b/utils/qv4l2/Makefile.am
index 1e3d0812..ab570565 100644
--- a/utils/qv4l2/Makefile.am
+++ b/utils/qv4l2/Makefile.am
@@ -1,13 +1,14 @@
bin_PROGRAMS = qv4l2
man_MANS = qv4l2.1
-qv4l2_SOURCES = qv4l2.cpp general-tab.cpp ctrl-tab.cpp vbi-tab.cpp capture-win.cpp \
+qv4l2_SOURCES = qv4l2.cpp general-tab.cpp ctrl-tab.cpp vbi-tab.cpp capture-win.cpp tpg-tab.cpp \
capture-win-qt.cpp capture-win-qt.h capture-win-gl.cpp capture-win-gl.h alsa_stream.c alsa_stream.h \
- raw2sliced.cpp qv4l2.h capture-win.h general-tab.h vbi-tab.h raw2sliced.h
+ raw2sliced.cpp qv4l2.h capture-win.h general-tab.h vbi-tab.h raw2sliced.h \
+ ../v4l2-ctl/vivid-tpg.c ../v4l2-ctl/vivid-tpg.h ../v4l2-ctl/vivid-tpg-colors.c ../v4l2-ctl/vivid-tpg-colors.h
nodist_qv4l2_SOURCES = moc_qv4l2.cpp moc_general-tab.cpp moc_capture-win.cpp moc_vbi-tab.cpp qrc_qv4l2.cpp
qv4l2_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la ../libv4l2util/libv4l2util.la \
../libmedia_dev/libmedia_dev.la
-qv4l2_CPPFLAGS = -I../v4l2-compliance
+qv4l2_CPPFLAGS = -I../v4l2-compliance -I../v4l2-ctl
if WITH_QTGL
qv4l2_CPPFLAGS += $(QTGL_CFLAGS)
diff --git a/utils/qv4l2/general-tab.cpp b/utils/qv4l2/general-tab.cpp
index e94d99f1..8a716b77 100644
--- a/utils/qv4l2/general-tab.cpp
+++ b/utils/qv4l2/general-tab.cpp
@@ -1197,7 +1197,7 @@ CapMethod GeneralTab::capMethod()
return (CapMethod)m_capMethods->itemData(m_capMethods->currentIndex()).toInt();
}
-void GeneralTab::updateGUIInput(int input)
+void GeneralTab::updateGUIInput(__u32 input)
{
v4l2_input in;
enum_input(in, true, input);
@@ -1237,7 +1237,7 @@ void GeneralTab::updateGUIInput(int input)
}
}
-void GeneralTab::updateGUIOutput(int output)
+void GeneralTab::updateGUIOutput(__u32 output)
{
v4l2_output out;
enum_output(out, true, output);
@@ -1272,7 +1272,7 @@ void GeneralTab::updateGUIOutput(int output)
void GeneralTab::inputChanged(int input)
{
- s_input(input);
+ s_input((__u32)input);
if (m_audioInput)
updateAudioInput();
@@ -1284,7 +1284,7 @@ void GeneralTab::inputChanged(int input)
void GeneralTab::outputChanged(int output)
{
- s_output(output);
+ s_output((__u32)output);
updateVideoOutput();
updateVidOutFormat();
updateGUIOutput(output);
@@ -1292,13 +1292,13 @@ void GeneralTab::outputChanged(int output)
void GeneralTab::inputAudioChanged(int input)
{
- s_audio(input);
+ s_audio((__u32)input);
updateAudioInput();
}
void GeneralTab::outputAudioChanged(int output)
{
- s_audout(output);
+ s_audout((__u32)output);
updateAudioOutput();
}
@@ -1598,7 +1598,7 @@ void GeneralTab::composeChanged()
void GeneralTab::updateVideoInput()
{
- int input;
+ __u32 input;
v4l2_input in;
if (g_input(input))
@@ -1657,7 +1657,7 @@ void GeneralTab::updateVideoInput()
void GeneralTab::updateVideoOutput()
{
- int output;
+ __u32 output;
v4l2_output out;
if (g_output(output))
@@ -1676,6 +1676,7 @@ void GeneralTab::updateVideoOutput()
updateTimings();
m_videoTimings->setEnabled(out.capabilities & V4L2_OUT_CAP_DV_TIMINGS);
}
+ g_mw->updateLimRGBRange();
}
void GeneralTab::updateAudioInput()
@@ -1815,6 +1816,7 @@ void GeneralTab::updateTimings()
m_videoTimings->setStatusTip(what);
m_videoTimings->setWhatsThis(what);
updateVidFormat();
+ g_mw->updateLimRGBRange();
}
void GeneralTab::qryTimingsClicked()
diff --git a/utils/qv4l2/general-tab.h b/utils/qv4l2/general-tab.h
index ac9868ed..e39589cd 100644
--- a/utils/qv4l2/general-tab.h
+++ b/utils/qv4l2/general-tab.h
@@ -132,8 +132,8 @@ private:
void formatSection(v4l2_fmtdesc fmt);
void cropSection();
void fixWidth();
- void updateGUIInput(int);
- void updateGUIOutput(int);
+ void updateGUIInput(__u32);
+ void updateGUIOutput(__u32);
void updateVideoInput();
void updateVideoOutput();
void updateAudioInput();
@@ -233,14 +233,14 @@ private:
int enum_audout(v4l2_audioout &audout, bool init = false, int index = 0) { return m_fd->enum_audout(audout, init, index); }
int subscribe_event(v4l2_event_subscription &sub) { return m_fd->subscribe_event(sub); }
int dqevent(v4l2_event &ev) { return m_fd->dqevent(ev); }
- int g_input(int &input) { return m_fd->g_input(input); }
- int s_input(int input) { return m_fd->s_input(input); }
- int g_output(int &output) { return m_fd->g_output(output); }
- int s_output(int output) { return m_fd->s_output(output); }
+ int g_input(__u32 &input) { return m_fd->g_input(input); }
+ int s_input(__u32 input) { return m_fd->s_input(input); }
+ int g_output(__u32 &output) { return m_fd->g_output(output); }
+ int s_output(__u32 output) { return m_fd->s_output(output); }
int g_audio(v4l2_audio &audio) { return m_fd->g_audio(audio); }
- int s_audio(int input) { return m_fd->s_audio(input); }
+ int s_audio(__u32 input) { return m_fd->s_audio(input); }
int g_audout(v4l2_audioout &audout) { return m_fd->g_audout(audout); }
- int s_audout(int output) { return m_fd->s_audout(output); }
+ int s_audout(__u32 output) { return m_fd->s_audout(output); }
int g_std(v4l2_std_id &std) { return m_fd->g_std(std); }
int s_std(v4l2_std_id std) { return m_fd->s_std(std); }
int query_std(v4l2_std_id &std) { return m_fd->query_std(std); }
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index c4c071a2..3147d68b 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -77,11 +77,13 @@ ApplicationWindow::ApplicationWindow() :
setAttribute(Qt::WA_DeleteOnClose, true);
m_capNotifier = NULL;
+ m_outNotifier = NULL;
m_ctrlNotifier = NULL;
m_capImage = NULL;
m_frameData = NULL;
m_nbuffers = 0;
m_makeSnapshot = false;
+ m_tpgLimRGBRange = NULL;
for (unsigned b = 0; b < sizeof(m_clear); b++)
m_clear[b] = false;
@@ -267,6 +269,14 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
connect(m_genTab, SIGNAL(displayColorspaceChanged()), this, SLOT(updateDisplayColorspace()));
connect(m_genTab, SIGNAL(clearBuffers()), this, SLOT(clearBuffers()));
m_tabs->addTab(w, "General Settings");
+
+ m_tpgLimRGBRange = NULL;
+ if (has_vid_out()) {
+ addTpgTab(m_minWidth);
+ tpg_init(&m_tpg, 640, 360);
+ updateLimRGBRange();
+ }
+
addTabs(m_winWidth);
m_vbiTab = NULL;
if (has_vbi_cap()) {
@@ -281,7 +291,7 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
m_tabs->show();
m_tabs->setFocus();
m_convertData = v4lconvert_create(g_fd());
- bool canStream = g_fd() >= 0 && v4l_type_is_capture(g_type()) &&
+ bool canStream = g_fd() >= 0 && (v4l_type_is_capture(g_type()) || has_vid_out()) &&
!has_radio_rx() && !has_radio_tx();
m_capStartAct->setEnabled(canStream);
m_saveRawAct->setEnabled(canStream);
@@ -423,7 +433,7 @@ void ApplicationWindow::newCaptureWin()
connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
}
-bool ApplicationWindow::startCapture()
+bool ApplicationWindow::startStreaming()
{
startAudio();
@@ -463,11 +473,23 @@ bool ApplicationWindow::startCapture()
break;
}
- for (unsigned i = 0; i < m_queue.g_buffers(); i++) {
- cv4l_buffer buf;
-
- m_queue.buffer_init(buf, i);
- qbuf(buf);
+ if (v4l_type_is_capture(g_type())) {
+ for (unsigned i = 0; i < m_queue.g_buffers(); i++) {
+ cv4l_buffer buf;
+
+ m_queue.buffer_init(buf, i);
+ qbuf(buf);
+ }
+ } else {
+ for (unsigned i = 0; i < m_queue.g_buffers(); i++) {
+ cv4l_buffer buf;
+
+ m_queue.buffer_init(buf, i);
+ for (unsigned p = 0; p < m_queue.g_num_planes(); p++)
+ tpg_fillbuffer(&m_tpg, m_tpgStd, p, (u8 *)m_queue.g_dataptr(i, p));
+ qbuf(buf);
+ tpg_update_mv_count(&m_tpg, V4L2_FIELD_HAS_T_OR_B(m_tpgField));
+ }
}
if (streamon()) {
@@ -688,6 +710,76 @@ void ApplicationWindow::capSdrFrame()
refresh();
}
+void ApplicationWindow::outFrame()
+{
+ cv4l_buffer buf(m_queue);
+ int s = 0;
+
+ switch (m_capMethod) {
+ case methodRead:
+ tpg_fillbuffer(&m_tpg, m_tpgStd, 0, (u8 *)m_frameData);
+ s = write(m_frameData, m_tpgSizeImage);
+ tpg_update_mv_count(&m_tpg, V4L2_FIELD_HAS_T_OR_B(m_tpgField));
+
+ if (s < 0) {
+ if (errno != EAGAIN) {
+ error("write");
+ m_capStartAct->setChecked(false);
+ }
+ return;
+ }
+ break;
+
+ case methodMmap:
+ case methodUser:
+ if (dqbuf(buf)) {
+ if (errno == EAGAIN)
+ return;
+ error("dqbuf");
+ m_capStartAct->setChecked(false);
+ return;
+ }
+ m_queue.buffer_init(buf, buf.g_index());
+ for (unsigned p = 0; p < m_queue.g_num_planes(); p++)
+ tpg_fillbuffer(&m_tpg, m_tpgStd, p, (u8 *)m_queue.g_dataptr(buf.g_index(), p));
+ tpg_update_mv_count(&m_tpg, V4L2_FIELD_HAS_T_OR_B(m_tpgField));
+ break;
+ }
+
+ QString status, curStatus;
+ struct timeval tv, res;
+
+ if (m_frame == 0)
+ gettimeofday(&m_tv, NULL);
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &m_tv, &res);
+ if (res.tv_sec) {
+ m_fps = (100 * (m_frame - m_lastFrame)) /
+ (res.tv_sec * 100 + res.tv_usec / 10000);
+ m_lastFrame = m_frame;
+ m_tv = tv;
+ }
+
+
+ status = QString("Frame: %1 Fps: %2").arg(++m_frame).arg(m_fps);
+
+ if (m_capMethod == methodMmap || m_capMethod == methodUser) {
+ if (m_clear[buf.g_index()]) {
+ for (unsigned p = 0; p < m_queue.g_num_planes(); p++)
+ memset(m_queue.g_dataptr(buf.g_index(), p), 0, buf.g_length(p));
+ m_clear[buf.g_index()] = false;
+ }
+
+ qbuf(buf);
+ }
+
+ curStatus = statusBar()->currentMessage();
+ if (curStatus.isEmpty() || curStatus.startsWith("Frame: "))
+ statusBar()->showMessage(status);
+ if (m_frame == 1)
+ refresh();
+}
+
void ApplicationWindow::capFrame()
{
cv4l_buffer buf(m_queue);
@@ -825,8 +917,10 @@ void ApplicationWindow::capFrame()
refresh();
}
-void ApplicationWindow::stopCapture()
+void ApplicationWindow::stopStreaming()
{
+ v4l2_encoder_cmd cmd;
+
stopAudio();
s_priority(V4L2_PRIORITY_DEFAULT);
@@ -834,16 +928,18 @@ void ApplicationWindow::stopCapture()
if (!m_genTab->isSDR() && m_genTab->isRadio())
return;
- v4l2_encoder_cmd cmd;
+ if (v4l_type_is_capture(g_type()))
+ m_capture->stop();
- m_capture->stop();
m_snapshotAct->setDisabled(true);
m_useGLAct->setEnabled(CaptureWinGL::isSupported());
switch (m_capMethod) {
case methodRead:
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = V4L2_ENC_CMD_STOP;
- cv4l_ioctl(VIDIOC_ENCODER_CMD, &cmd);
+ if (v4l_type_is_capture(g_type())) {
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd = V4L2_ENC_CMD_STOP;
+ cv4l_ioctl(VIDIOC_ENCODER_CMD, &cmd);
+ }
break;
case methodMmap:
@@ -965,13 +1061,88 @@ void ApplicationWindow::closeCaptureWin()
m_capStartAct->setChecked(false);
}
+void ApplicationWindow::outStart(bool start)
+{
+ if (start) {
+ cv4l_fmt fmt;
+ v4l2_output out;
+ v4l2_control ctrl = { V4L2_CID_DV_TX_RGB_RANGE };
+ int factor = 1;
+
+ g_output(out.index);
+ enum_output(out, true, out.index);
+ m_frame = m_lastFrame = m_fps = 0;
+ m_capMethod = m_genTab->capMethod();
+ g_fmt(fmt);
+ if (out.capabilities & V4L2_OUT_CAP_STD)
+ g_std(m_tpgStd);
+ else
+ m_tpgStd = 0;
+ m_tpgField = fmt.g_field();
+ m_tpgSizeImage = fmt.g_sizeimage(0);
+ tpg_alloc(&m_tpg, fmt.g_width());
+ m_useTpg = tpg_s_fourcc(&m_tpg, fmt.g_pixelformat());
+ if (V4L2_FIELD_HAS_T_OR_B(fmt.g_field()))
+ factor = 2;
+ tpg_reset_source(&m_tpg, fmt.g_width(), fmt.g_height() * factor, fmt.g_field());
+ tpg_init_mv_count(&m_tpg);
+ if (g_ctrl(ctrl))
+ tpg_s_rgb_range(&m_tpg, V4L2_DV_RGB_RANGE_AUTO);
+ else
+ tpg_s_rgb_range(&m_tpg, ctrl.value);
+ if (m_tpgColorspace == 0)
+ fmt.s_colorspace(defaultColorspace(false));
+ else
+ fmt.s_colorspace(m_tpgColorspace);
+ s_fmt(fmt);
+
+ if (out.capabilities & V4L2_OUT_CAP_STD) {
+ tpg_s_pixel_aspect(&m_tpg, (m_tpgStd & V4L2_STD_525_60) ?
+ TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL);
+ } else if (out.capabilities & V4L2_OUT_CAP_DV_TIMINGS) {
+ v4l2_dv_timings timings;
+
+ g_dv_timings(timings);
+ if (timings.bt.width == 720 && timings.bt.height <= 576)
+ tpg_s_pixel_aspect(&m_tpg, timings.bt.height == 480 ?
+ TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL);
+ else
+ tpg_s_pixel_aspect(&m_tpg, TPG_PIXEL_ASPECT_SQUARE);
+ } else {
+ tpg_s_pixel_aspect(&m_tpg, TPG_PIXEL_ASPECT_SQUARE);
+ }
+
+ tpg_s_colorspace(&m_tpg, m_tpgColorspace ? m_tpgColorspace : fmt.g_colorspace());
+ tpg_s_bytesperline(&m_tpg, 0, fmt.g_bytesperline(0));
+ tpg_s_bytesperline(&m_tpg, 1, fmt.g_bytesperline(1));
+ if (m_capMethod == methodRead)
+ m_frameData = new unsigned char[fmt.g_sizeimage(0)];
+ if (startStreaming()) {
+ m_outNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Write, m_tabs);
+ connect(m_outNotifier, SIGNAL(activated(int)), this, SLOT(outFrame()));
+ }
+ } else {
+ stopStreaming();
+ tpg_free(&m_tpg);
+ delete m_frameData;
+ m_frameData = NULL;
+ delete m_outNotifier;
+ m_outNotifier = NULL;
+ }
+}
+
void ApplicationWindow::capStart(bool start)
{
+ if (has_vid_out()) {
+ outStart(start);
+ return;
+ }
+
if (!m_genTab->isSDR() && m_genTab->isRadio()) {
if (start)
- startCapture();
+ startStreaming();
else
- stopCapture();
+ stopStreaming();
return;
}
@@ -982,7 +1153,7 @@ void ApplicationWindow::capStart(bool start)
unsigned colorspace, field;
if (!start) {
- stopCapture();
+ stopStreaming();
delete m_capNotifier;
m_capNotifier = NULL;
delete m_capImage;
@@ -1012,7 +1183,7 @@ void ApplicationWindow::capStart(bool start)
m_vbiTab->slicedFormat(fmt.fmt.sliced);
m_vbiSize = fmt.fmt.sliced.io_size;
m_frameData = new unsigned char[m_vbiSize];
- if (startCapture()) {
+ if (startStreaming()) {
m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capVbiFrame()));
}
@@ -1054,7 +1225,7 @@ void ApplicationWindow::capStart(bool start)
m_capture->show();
statusBar()->showMessage("No frame");
- if (startCapture()) {
+ if (startStreaming()) {
m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capVbiFrame()));
}
@@ -1083,7 +1254,7 @@ void ApplicationWindow::capStart(bool start)
m_capture->show();
statusBar()->showMessage("No frame");
- if (startCapture()) {
+ if (startStreaming()) {
m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capSdrFrame()));
}
@@ -1159,7 +1330,7 @@ void ApplicationWindow::capStart(bool start)
m_capture->show();
statusBar()->showMessage("No frame");
- if (startCapture()) {
+ if (startStreaming()) {
m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capFrame()));
}
@@ -1186,6 +1357,10 @@ void ApplicationWindow::closeDevice()
m_capNotifier = NULL;
m_capImage = NULL;
}
+ if (m_outNotifier) {
+ delete m_outNotifier;
+ m_outNotifier = NULL;
+ }
if (m_ctrlNotifier) {
delete m_ctrlNotifier;
m_ctrlNotifier = NULL;
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index 46a72651..fd648684 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -36,12 +36,16 @@
// Must come before cv4l-helpers.h
#include <libv4l2.h>
+extern "C" {
+#include <vivid-tpg.h>
+}
#include "cv4l-helpers.h"
#include "raw2sliced.h"
#include "capture-win.h"
class QComboBox;
class QSpinBox;
+class QCheckBox;
class GeneralTab;
class VbiTab;
class QCloseEvent;
@@ -103,11 +107,14 @@ public:
private:
CaptureWin *m_capture;
- bool startCapture();
- void stopCapture();
+ bool startStreaming();
+ void stopStreaming();
void newCaptureWin();
void startAudio();
void stopAudio();
+ bool startOutput();
+ void stopOutput();
+ __u32 defaultColorspace(bool capture);
bool m_clear[64];
cv4l_fmt m_capSrcFormat;
@@ -122,8 +129,10 @@ private:
private slots:
void capStart(bool);
+ void outStart(bool);
void makeFullScreen(bool);
void capFrame();
+ void outFrame();
void ctrlEvent();
void snapshot();
void capVbiFrame();
@@ -150,6 +159,22 @@ private slots:
void clearBuffers();
void about();
+ // tpg
+private slots:
+ void testPatternChanged(int val);
+ void horMovementChanged(int val);
+ void vertMovementChanged(int val);
+ void showBorderChanged(int val);
+ void showSquareChanged(int val);
+ void insSAVChanged(int val);
+ void insEAVChanged(int val);
+ void videoAspectRatioChanged(int val);
+ void colorspaceChanged(int val);
+ void limRGBRangeChanged(int val);
+ void fillPercentageChanged(int val);
+ void alphaComponentChanged(int val);
+ void applyToRedChanged(int val);
+
public:
virtual void error(const QString &text);
void error(int err);
@@ -158,6 +183,7 @@ public:
void errorCtrl(unsigned id, int err, const QString &v);
void info(const QString &info);
virtual void closeEvent(QCloseEvent *event);
+ void updateLimRGBRange();
QAction *m_resetScalingAct;
QAction *m_useBlendingAct;
QAction *m_snapshotAct;
@@ -171,6 +197,7 @@ private:
}
void fixWidth(QGridLayout *grid);
void addTabs(int m_winWidth);
+ void addTpgTab(int m_winWidth);
void finishGrid(QGridLayout *grid, unsigned ctrl_class);
void addCtrl(QGridLayout *grid, const struct v4l2_query_ext_ctrl &qec);
void updateCtrl(unsigned id);
@@ -198,6 +225,14 @@ private:
void updateFreqChannel();
bool showFrames();
+ struct tpg_data m_tpg;
+ v4l2_std_id m_tpgStd;
+ unsigned m_tpgField;
+ unsigned m_tpgSizeImage;
+ unsigned m_tpgColorspace;
+ bool m_useTpg;
+ QCheckBox *m_tpgLimRGBRange;
+
cv4l_queue m_queue;
const double m_pxw;
@@ -219,6 +254,7 @@ private:
QSignalMapper *m_sigMapper;
QTabWidget *m_tabs;
QSocketNotifier *m_capNotifier;
+ QSocketNotifier *m_outNotifier;
QSocketNotifier *m_ctrlNotifier;
QImage *m_capImage;
int m_row, m_col, m_cols;
diff --git a/utils/qv4l2/tpg-tab.cpp b/utils/qv4l2/tpg-tab.cpp
new file mode 100644
index 00000000..2b69d633
--- /dev/null
+++ b/utils/qv4l2/tpg-tab.cpp
@@ -0,0 +1,362 @@
+/*
+ * qv4l2 - Test Pattern Generator Tab
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "qv4l2.h"
+
+#include <QFrame>
+#include <QVBoxLayout>
+#include <QStatusBar>
+#include <QLineEdit>
+#include <QValidator>
+#include <QLayout>
+#include <QGridLayout>
+#include <QLabel>
+#include <QSlider>
+#include <QSpinBox>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QPushButton>
+#include <QToolButton>
+#include <QToolTip>
+
+#include <math.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+void ApplicationWindow::addTpgTab(int m_winWidth)
+{
+ QWidget *t = new QWidget(m_tabs);
+ QVBoxLayout *vbox = new QVBoxLayout(t);
+ QWidget *w = new QWidget(t);
+ QCheckBox *check;
+ QComboBox *combo;
+ QSpinBox *spin;
+
+ m_col = m_row = 0;
+ m_cols = 4;
+ for (int j = 0; j < m_cols; j++) {
+ m_maxw[j] = 0;
+ }
+
+ vbox->addWidget(w);
+
+ QGridLayout *grid = new QGridLayout(w);
+ QLabel *title_tab = new QLabel("Test Pattern Generator", parentWidget());
+ QFont f = title_tab->font();
+ f.setBold(true);
+ title_tab->setFont(f);
+ grid->addWidget(title_tab, m_row, m_col, 1, m_cols, Qt::AlignLeft);
+ grid->setRowMinimumHeight(m_row, 25);
+ m_row++;
+
+ QFrame *m_line = new QFrame(grid->parentWidget());
+ m_line->setFrameShape(QFrame::HLine);
+ m_line->setFrameShadow(QFrame::Sunken);
+ grid->addWidget(m_line, m_row, m_col, 1, m_cols, Qt::AlignVCenter);
+ m_row++;
+
+ m_tabs->addTab(t, "Test Pattern Generator");
+ grid->addWidget(new QWidget(w), grid->rowCount(), 0, 1, m_cols);
+
+ addLabel(grid, "Test Pattern");
+ combo = new QComboBox(w);
+ for (int i = 0; tpg_pattern_strings[i]; i++)
+ combo->addItem(tpg_pattern_strings[i]);
+ addWidget(grid, combo);
+ connect(combo, SIGNAL(activated(int)), SLOT(testPatternChanged(int)));
+
+ m_row++;
+ m_col = 0;
+
+ addLabel(grid, "Horizontal Movement");
+ combo = new QComboBox(w);
+ combo->addItem("Move Left Fast");
+ combo->addItem("Move Left");
+ combo->addItem("Move Left Slow");
+ combo->addItem("No Movement");
+ combo->addItem("Move Right Slow");
+ combo->addItem("Move Right");
+ combo->addItem("Move Right Fast");
+ combo->setCurrentIndex(3);
+ addWidget(grid, combo);
+ connect(combo, SIGNAL(activated(int)), SLOT(horMovementChanged(int)));
+
+ addLabel(grid, "Video Aspect Ratio");
+ combo = new QComboBox(w);
+ combo->addItem("Source Width x Height");
+ combo->addItem("4x3");
+ combo->addItem("16x9");
+ combo->addItem("16x9 Anamorphic");
+ addWidget(grid, combo);
+ connect(combo, SIGNAL(activated(int)), SLOT(videoAspectRatioChanged(int)));
+
+ addLabel(grid, "Vertical Movement");
+ combo = new QComboBox(w);
+ combo->addItem("Move Up Fast");
+ combo->addItem("Move Up");
+ combo->addItem("Move Up Slow");
+ combo->addItem("No Movement");
+ combo->addItem("Move Down Slow");
+ combo->addItem("Move Down");
+ combo->addItem("Move Down Fast");
+ combo->setCurrentIndex(3);
+ addWidget(grid, combo);
+ connect(combo, SIGNAL(activated(int)), SLOT(vertMovementChanged(int)));
+
+ m_tpgColorspace = 0;
+ addLabel(grid, "Colorspace");
+ combo = new QComboBox(w);
+ combo->addItem("Autodetect");
+ combo->addItem("SMPTE 170M");
+ combo->addItem("SMPTE 240M");
+ combo->addItem("REC 709");
+ combo->addItem("470 System M");
+ combo->addItem("470 System BG");
+ combo->addItem("sRGB");
+ addWidget(grid, combo);
+ connect(combo, SIGNAL(activated(int)), SLOT(colorspaceChanged(int)));
+
+ addLabel(grid, "Show Border");
+ check = new QCheckBox(w);
+ addWidget(grid, check);
+ connect(check, SIGNAL(stateChanged(int)), SLOT(showBorderChanged(int)));
+
+ addLabel(grid, "Insert SAV Code in Image");
+ check = new QCheckBox(w);
+ addWidget(grid, check);
+ connect(check, SIGNAL(stateChanged(int)), SLOT(insSAVChanged(int)));
+
+ addLabel(grid, "Show Square");
+ check = new QCheckBox(w);
+ addWidget(grid, check);
+ connect(check, SIGNAL(stateChanged(int)), SLOT(showSquareChanged(int)));
+
+ addLabel(grid, "Insert EAV Code in Image");
+ check = new QCheckBox(w);
+ addWidget(grid, check);
+ connect(check, SIGNAL(stateChanged(int)), SLOT(insEAVChanged(int)));
+
+ addLabel(grid, "Fill Percentage of Frame");
+ spin = new QSpinBox(w);
+ spin->setRange(0, 100);
+ spin->setValue(100);
+ addWidget(grid, spin);
+ connect(spin, SIGNAL(valueChanged(int)), SLOT(fillPercentageChanged(int)));
+
+ addLabel(grid, "Limited RGB Range (16-235)");
+ m_tpgLimRGBRange = new QCheckBox(w);
+ addWidget(grid, m_tpgLimRGBRange);
+ connect(m_tpgLimRGBRange, SIGNAL(stateChanged(int)), SLOT(limRGBRangeChanged(int)));
+
+ addLabel(grid, "Alpha Component");
+ spin = new QSpinBox(w);
+ spin->setRange(0, 255);
+ spin->setValue(0);
+ addWidget(grid, spin);
+ connect(spin, SIGNAL(valueChanged(int)), SLOT(alphaComponentChanged(int)));
+
+ addLabel(grid, "Apply Alpha To Red Only");
+ check = new QCheckBox(w);
+ addWidget(grid, check);
+ connect(check, SIGNAL(stateChanged(int)), SLOT(applyToRedChanged(int)));
+
+ m_row++;
+ m_col = 0;
+ addWidget(grid, new QWidget(w));
+ grid->setRowStretch(grid->rowCount() - 1, 1);
+ w = new QWidget(t);
+ vbox->addWidget(w);
+ fixWidth(grid);
+
+ int totalw = 0;
+ int diff = 0;
+ for (int i = 0; i < m_cols; i++) {
+ totalw += m_maxw[i] + m_pxw;
+ }
+ if (totalw > m_winWidth)
+ m_winWidth = totalw;
+ else {
+ diff = m_winWidth - totalw;
+ grid->setHorizontalSpacing(diff/5);
+ }
+}
+
+void ApplicationWindow::testPatternChanged(int val)
+{
+ tpg_s_pattern(&m_tpg, (tpg_pattern)val);
+}
+
+void ApplicationWindow::horMovementChanged(int val)
+{
+ tpg_s_mv_hor_mode(&m_tpg, (tpg_move_mode)val);
+}
+
+void ApplicationWindow::vertMovementChanged(int val)
+{
+ tpg_s_mv_vert_mode(&m_tpg, (tpg_move_mode)val);
+}
+
+void ApplicationWindow::showBorderChanged(int val)
+{
+ tpg_s_show_border(&m_tpg, val);
+}
+
+void ApplicationWindow::showSquareChanged(int val)
+{
+ tpg_s_show_square(&m_tpg, val);
+}
+
+void ApplicationWindow::insSAVChanged(int val)
+{
+ tpg_s_insert_sav(&m_tpg, val);
+}
+
+void ApplicationWindow::insEAVChanged(int val)
+{
+ tpg_s_insert_eav(&m_tpg, val);
+}
+
+void ApplicationWindow::videoAspectRatioChanged(int val)
+{
+ tpg_s_video_aspect(&m_tpg, (tpg_video_aspect)val);
+}
+
+void ApplicationWindow::updateLimRGBRange()
+{
+ if (m_tpgLimRGBRange == NULL)
+ return;
+
+ v4l2_output out;
+
+ g_output(out.index);
+ enum_output(out, true, out.index);
+
+ if (out.capabilities & V4L2_OUT_CAP_STD) {
+ m_tpgLimRGBRange->setChecked(false);
+ } else if (out.capabilities & V4L2_OUT_CAP_DV_TIMINGS) {
+ v4l2_dv_timings timings;
+
+ g_dv_timings(timings);
+ if (timings.bt.standards & V4L2_DV_BT_STD_CEA861)
+ m_tpgLimRGBRange->setChecked(true);
+ else
+ m_tpgLimRGBRange->setChecked(false);
+ } else {
+ m_tpgLimRGBRange->setChecked(false);
+ }
+}
+
+__u32 ApplicationWindow::defaultColorspace(bool capture)
+{
+ v4l2_dv_timings timings = { 0 };
+ v4l2_output out;
+ v4l2_input in;
+ __u32 io_caps;
+ bool dvi_d = false;
+
+ if (capture) {
+ g_input(in.index);
+ enum_input(in, true, in.index);
+ io_caps = in.capabilities;
+ } else {
+ g_output(out.index);
+ enum_output(out, true, out.index);
+ io_caps = out.capabilities;
+ v4l2_control ctrl = { V4L2_CID_DV_TX_MODE };
+
+ if (!g_ctrl(ctrl))
+ dvi_d = ctrl.value == V4L2_DV_TX_MODE_DVI_D;
+ }
+
+ if (io_caps & V4L2_OUT_CAP_STD)
+ return V4L2_COLORSPACE_SMPTE170M;
+ if (!(io_caps & V4L2_OUT_CAP_DV_TIMINGS))
+ return V4L2_COLORSPACE_SRGB;
+
+ g_dv_timings(timings);
+
+ if (!(timings.bt.standards & V4L2_DV_BT_STD_CEA861) || dvi_d)
+ return V4L2_COLORSPACE_SRGB;
+ if (timings.bt.width == 720 && timings.bt.height <= 576)
+ return V4L2_COLORSPACE_SMPTE170M;
+ return V4L2_COLORSPACE_REC709;
+}
+
+void ApplicationWindow::colorspaceChanged(int val)
+{
+ switch (val) {
+ case 0:
+ m_tpgColorspace = 0;
+ break;
+ case 1:
+ m_tpgColorspace = V4L2_COLORSPACE_SMPTE170M;
+ break;
+ case 2:
+ m_tpgColorspace = V4L2_COLORSPACE_SMPTE240M;
+ break;
+ case 3:
+ m_tpgColorspace = V4L2_COLORSPACE_REC709;
+ break;
+ case 4:
+ m_tpgColorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ case 5:
+ m_tpgColorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ case 6:
+ default:
+ m_tpgColorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ cv4l_fmt fmt;
+ v4l2_output out;
+
+ g_output(out.index);
+ enum_output(out, true, out.index);
+
+ g_fmt(fmt);
+ if (m_tpgColorspace == 0)
+ fmt.s_colorspace(defaultColorspace(false));
+ else
+ fmt.s_colorspace(m_tpgColorspace);
+ s_fmt(fmt);
+ tpg_s_colorspace(&m_tpg, m_tpgColorspace ? m_tpgColorspace : fmt.g_colorspace());
+}
+
+void ApplicationWindow::limRGBRangeChanged(int val)
+{
+ tpg_s_real_rgb_range(&m_tpg, val ? V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
+}
+
+void ApplicationWindow::fillPercentageChanged(int val)
+{
+ tpg_s_perc_fill(&m_tpg, val);
+}
+
+void ApplicationWindow::alphaComponentChanged(int val)
+{
+ tpg_s_alpha_component(&m_tpg, val);
+}
+
+void ApplicationWindow::applyToRedChanged(int val)
+{
+ tpg_s_alpha_mode(&m_tpg, val);
+}
diff --git a/utils/v4l2-compliance/cv4l-helpers.h b/utils/v4l2-compliance/cv4l-helpers.h
index c0d3195a..b18c2aca 100644
--- a/utils/v4l2-compliance/cv4l-helpers.h
+++ b/utils/v4l2-compliance/cv4l-helpers.h
@@ -74,6 +74,16 @@ public:
return v4l_query_ext_ctrl(this, &qec, next_ctrl, next_compound);
}
+ int g_ctrl(v4l2_control &ctrl)
+ {
+ return cv4l_ioctl(VIDIOC_G_CTRL, &ctrl);
+ }
+
+ int s_ctrl(v4l2_control &ctrl)
+ {
+ return cv4l_ioctl(VIDIOC_S_CTRL, &ctrl);
+ }
+
int g_ext_ctrls(v4l2_ext_controls &ec)
{
return v4l_g_ext_ctrls(this, &ec);
@@ -236,22 +246,22 @@ public:
return cv4l_ioctl(VIDIOC_DQEVENT, &ev);
}
- int g_input(int &input)
+ int g_input(__u32 &input)
{
return cv4l_ioctl(VIDIOC_G_INPUT, &input);
}
- int s_input(int input)
+ int s_input(__u32 input)
{
return cv4l_ioctl(VIDIOC_S_INPUT, &input);
}
- int g_output(int &output)
+ int g_output(__u32 &output)
{
return cv4l_ioctl(VIDIOC_G_OUTPUT, &output);
}
- int s_output(int output)
+ int s_output(__u32 output)
{
return cv4l_ioctl(VIDIOC_S_OUTPUT, &output);
}
@@ -262,7 +272,7 @@ public:
return cv4l_ioctl(VIDIOC_G_AUDIO, &audio);
}
- int s_audio(int input)
+ int s_audio(__u32 input)
{
v4l2_audio audio;
@@ -277,7 +287,7 @@ public:
return cv4l_ioctl(VIDIOC_G_AUDOUT, &audout);
}
- int s_audout(int output)
+ int s_audout(__u32 output)
{
v4l2_audioout audout;

Privacy Policy