aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-07-23 18:59:40 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2014-07-23 19:03:00 +0200
commit9fba88de8fc452b45f64269af14ab7a7afba9e92 (patch)
tree8db7c1590c69106672668cb6068acafac482c736
parent79f62a6c9cdb647e10f55eb1c0fe2003988e5626 (diff)
qv4l2: add SDR visualization.
Just show a simple waveform of the first 1025 samples of the I and Q samples in each captured buffer. It's simple but remarkably effective. Currently only the CU8 format is supported. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--utils/qv4l2/general-tab.cpp16
-rw-r--r--utils/qv4l2/qv4l2.cpp142
-rw-r--r--utils/qv4l2/qv4l2.h2
3 files changed, 148 insertions, 12 deletions
diff --git a/utils/qv4l2/general-tab.cpp b/utils/qv4l2/general-tab.cpp
index d7c4ea41..e94d99f1 100644
--- a/utils/qv4l2/general-tab.cpp
+++ b/utils/qv4l2/general-tab.cpp
@@ -201,7 +201,7 @@ GeneralTab::GeneralTab(const QString &device, cv4l_fd *fd, int n, QWidget *paren
m_audioOutDevice = NULL;
}
- if (isRadio())
+ if (!isSDR() && isRadio())
goto done;
addTitle("Format Settings");
@@ -219,7 +219,7 @@ GeneralTab::GeneralTab(const QString &device, cv4l_fd *fd, int n, QWidget *paren
updateVideoOutput();
else
updateVideoInput();
- } else {
+ } else if (!isSDR()) {
formatSection(fmt);
}
@@ -262,11 +262,13 @@ GeneralTab::GeneralTab(const QString &device, cv4l_fd *fd, int n, QWidget *paren
cropSection();
}
- if (m_isOutput)
- updateVideoOutput();
- else
- updateVideoInput();
- updateVidFormat();
+ if (!isSDR()) {
+ if (m_isOutput)
+ updateVideoOutput();
+ else
+ updateVideoInput();
+ updateVidFormat();
+ }
done:
QGridLayout::addWidget(new QWidget(parent), rowCount(), 0, 1, n);
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index 72847d13..c4c071a2 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -62,6 +62,9 @@ extern "C" {
#include <libv4lconvert.h>
+#define SDR_WIDTH 1024
+#define SDR_HEIGHT 512
+
ApplicationWindow::ApplicationWindow() :
m_capture(NULL),
m_pxw(25),
@@ -279,8 +282,7 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
m_tabs->setFocus();
m_convertData = v4lconvert_create(g_fd());
bool canStream = g_fd() >= 0 && v4l_type_is_capture(g_type()) &&
- !has_radio_rx() && !has_radio_tx() &&
- !has_sdr_cap();
+ !has_radio_rx() && !has_radio_tx();
m_capStartAct->setEnabled(canStream);
m_saveRawAct->setEnabled(canStream);
m_snapshotAct->setEnabled(canStream && has_vid_cap());
@@ -425,7 +427,7 @@ bool ApplicationWindow::startCapture()
{
startAudio();
- if (m_genTab->isRadio()) {
+ if (!m_genTab->isSDR() && m_genTab->isRadio()) {
s_priority(m_genTab->usePrio());
return true;
}
@@ -585,6 +587,107 @@ void ApplicationWindow::capVbiFrame()
refresh();
}
+void ApplicationWindow::capSdrFrame()
+{
+ cv4l_buffer buf(m_queue);
+ __u8 *data = NULL;
+ int s = 0;
+
+ switch (m_capMethod) {
+ case methodRead:
+ s = read(m_frameData, m_sdrSize);
+ if (s < 0) {
+ if (errno != EAGAIN) {
+ error("read");
+ m_capStartAct->setChecked(false);
+ }
+ return;
+ }
+ data = m_frameData;
+ break;
+
+ case methodMmap:
+ case methodUser:
+ if (dqbuf(buf)) {
+ if (errno == EAGAIN)
+ return;
+ error("dqbuf");
+ m_capStartAct->setChecked(false);
+ return;
+ }
+ if (buf.g_flags() & V4L2_BUF_FLAG_ERROR) {
+ qbuf(buf);
+ return;
+ }
+ data = (__u8 *)m_queue.g_dataptr(buf.g_index(), 0);
+ s = buf.g_bytesused();
+ break;
+ }
+ if (s != m_sdrSize) {
+ error("incorrect sdr size");
+ m_capStartAct->setChecked(false);
+ return;
+ }
+ if (showFrames()) {
+ unsigned width = m_sdrSize / 2 - 1;
+
+ if (SDR_WIDTH < width)
+ width = SDR_WIDTH;
+
+ m_capImage->fill(0);
+ /*
+ * Draw two waveforms, each consisting of the first 'width + 1' samples
+ * of the buffer, the top is for the I, the bottom is for the Q values.
+ */
+ for (unsigned i = 0; i < 2; i++) {
+ unsigned start = 255 - data[i];
+
+ for (unsigned x = 0; x < width; x++) {
+ unsigned next = 255 - data[2 + 2 * x + i];
+ unsigned low = start < next ? start : next;
+ unsigned high = start > next ? start : next;
+ __u8 *q = m_capImage->bits() + x * 3 +
+ (i * 256 + low) * m_capImage->bytesPerLine();
+
+ while (low++ <= high) {
+ q[0] = 255;
+ q[1] = 255;
+ q[2] = 255;
+ q += m_capImage->bytesPerLine();
+ }
+ start = next;
+ }
+ }
+ }
+
+ if (m_capMethod != methodRead)
+ qbuf(buf);
+
+ 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 (showFrames())
+ m_capture->setFrame(m_capImage->width(), m_capImage->height(),
+ m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), NULL, status);
+
+ 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);
@@ -728,7 +831,7 @@ void ApplicationWindow::stopCapture()
s_priority(V4L2_PRIORITY_DEFAULT);
- if (m_genTab->isRadio())
+ if (!m_genTab->isSDR() && m_genTab->isRadio())
return;
v4l2_encoder_cmd cmd;
@@ -864,7 +967,7 @@ void ApplicationWindow::closeCaptureWin()
void ApplicationWindow::capStart(bool start)
{
- if (m_genTab->isRadio()) {
+ if (!m_genTab->isSDR() && m_genTab->isRadio()) {
if (start)
startCapture();
else
@@ -958,6 +1061,35 @@ void ApplicationWindow::capStart(bool start)
return;
}
+ if (m_genTab->isSDR()) {
+ cv4l_fmt fmt;
+
+ if (g_fmt(fmt)) {
+ error("could not obtain an VBI format\n");
+ return;
+ }
+ if (fmt.fmt.sdr.pixelformat != V4L2_SDR_FMT_CU8) {
+ error("only CU8 is supported for SDR\n");
+ return;
+ }
+ m_sdrSize = fmt.fmt.sdr.buffersize;
+ m_frameData = new unsigned char[m_sdrSize];
+ m_capImage = new QImage(SDR_WIDTH, SDR_HEIGHT, dstFmt);
+ m_capImage->fill(0);
+ m_capture->setWindowSize(QSize(SDR_WIDTH, SDR_HEIGHT));
+ m_capture->setFrame(m_capImage->width(), m_capImage->height(),
+ m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), NULL, "No frame");
+ if (showFrames())
+ m_capture->show();
+
+ statusBar()->showMessage("No frame");
+ if (startCapture()) {
+ m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
+ connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capSdrFrame()));
+ }
+ return;
+ }
+
m_capSrcFormat.s_type(g_type());
g_fmt(m_capSrcFormat);
s_fmt(m_capSrcFormat);
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index d8ab2316..46a72651 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -127,6 +127,7 @@ private slots:
void ctrlEvent();
void snapshot();
void capVbiFrame();
+ void capSdrFrame();
void saveRaw(bool);
void setRenderMethod(bool);
void setBlending(bool);
@@ -229,6 +230,7 @@ private:
unsigned m_vbiWidth;
unsigned m_vbiHeight;
struct vbi_handle m_vbiHandle;
+ int m_sdrSize;
unsigned m_frame;
unsigned m_lastFrame;
unsigned m_fps;

Privacy Policy