Just show the VBI data as a greyscale picture.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
m_col(0),
m_cols(n),
m_isRadio(false),
+ m_isVbi(false),
m_audioInput(NULL),
m_tvStandard(NULL),
m_qryStandard(NULL),
m_isRadio = true;
if (m_modulator.capability && m_modulator.capability & V4L2_TUNER_CAP_LOW)
m_isRadio = true;
+ if (m_querycap.capabilities & V4L2_CAP_DEVICE_CAPS)
+ m_isVbi = caps() & V4L2_CAP_VBI_CAPTURE;
if (!isRadio() && enum_input(vin, true)) {
addLabel("Input");
if (isRadio())
goto done;
+ if (isVbi())
+ goto capture_method;
+
v4l2_fmtdesc fmt;
addLabel("Capture Image Formats");
m_vidCapFormats = new QComboBox(parent);
connect(m_vidOutFormats, SIGNAL(activated(int)), SLOT(vidOutFormatChanged(int)));
}
+capture_method:
addLabel("Capture Method");
m_capMethods = new QComboBox(parent);
+ m_buftype = isVbi() ? V4L2_BUF_TYPE_VBI_CAPTURE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (caps() & V4L2_CAP_STREAMING) {
v4l2_requestbuffers reqbuf;
// unexpected. So the only way at the moment to do this that works
// everywhere is to call REQBUFS with a count of 1, and then again with
// a count of 0.
- if (reqbufs_user_cap(reqbuf, 1)) {
+ if (reqbufs_user(reqbuf, 1)) {
m_capMethods->addItem("User pointer I/O", QVariant(methodUser));
- reqbufs_user_cap(reqbuf, 0);
+ reqbufs_user(reqbuf, 0);
}
- if (reqbufs_mmap_cap(reqbuf, 1)) {
+ if (reqbufs_mmap(reqbuf, 1)) {
m_capMethods->addItem("Memory mapped I/O", QVariant(methodMmap));
- reqbufs_mmap_cap(reqbuf, 0);
+ reqbufs_mmap(reqbuf, 0);
}
}
if (caps() & V4L2_CAP_READWRITE) {
int width() const { return m_width; }
int height() const { return m_height; }
bool isRadio() const { return m_isRadio; }
+ bool isVbi() const { return m_isVbi; }
+ __u32 bufType() const { return m_buftype; }
+ inline bool reqbufs_mmap(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return v4l2::reqbufs_mmap(reqbuf, m_buftype, count);
+ }
+ inline bool reqbufs_user(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return v4l2::reqbufs_user(reqbuf, m_buftype, count);
+ }
+ inline bool dqbuf_mmap(v4l2_buffer &buf, bool &again) {
+ return v4l2::dqbuf_mmap(buf, m_buftype, again);
+ }
+ inline bool dqbuf_user(v4l2_buffer &buf, bool &again) {
+ return v4l2::dqbuf_user(buf, m_buftype, again);
+ }
+ inline bool qbuf_mmap(int index) {
+ return v4l2::qbuf_mmap(index, m_buftype);
+ }
+ inline bool qbuf_user(int index, void *ptr, int length) {
+ return v4l2::qbuf_user(index, m_buftype, ptr, length);
+ }
+ inline bool streamon() { return v4l2::streamon(m_buftype); }
+ inline bool streamoff() { return v4l2::streamoff(m_buftype); }
private slots:
void inputChanged(int);
int m_col;
int m_cols;
bool m_isRadio;
+ bool m_isVbi;
+ __u32 m_buftype;
__u32 m_audioModes[5];
struct v4l2_tuner m_tuner;
struct v4l2_modulator m_modulator;
void ApplicationWindow::capFrame()
{
+ __u32 buftype = m_genTab->bufType();
v4l2_buffer buf;
int s = 0;
int err = 0;
break;
case methodMmap:
- if (!dqbuf_mmap_cap(buf, again)) {
+ if (!dqbuf_mmap(buf, buftype, again)) {
error("dqbuf");
m_capStartAct->setChecked(false);
return;
break;
case methodUser:
- if (!dqbuf_user_cap(buf, again)) {
+ if (!dqbuf_user(buf, buftype, again)) {
error("dqbuf");
m_capStartAct->setChecked(false);
return;
bool ApplicationWindow::startCapture(unsigned buffer_size)
{
- unsigned int i;
+ __u32 buftype = m_genTab->bufType();
v4l2_requestbuffers req;
+ unsigned int i;
memset(&req, 0, sizeof(req));
return true;
case methodMmap:
- if (!reqbufs_mmap_cap(req, 3)) {
+ if (!reqbufs_mmap(req, buftype, 3)) {
error("Cannot capture");
break;
}
if (req.count < 2) {
error("Too few buffers");
- reqbufs_mmap_cap(req);
+ reqbufs_mmap(req, buftype);
break;
}
if (!m_buffers) {
error("Out of memory");
- reqbufs_mmap_cap(req);
+ reqbufs_mmap(req, buftype);
break;
}
memset(&buf, 0, sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = buftype;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = m_nbuffers;
}
}
for (i = 0; i < m_nbuffers; ++i) {
- if (!qbuf_mmap_cap(i)) {
+ if (!qbuf_mmap(i, buftype)) {
perror("VIDIOC_QBUF");
goto error;
}
}
- if (!streamon_cap()) {
+ if (!streamon(buftype)) {
perror("VIDIOC_STREAMON");
goto error;
}
return true;
case methodUser:
- if (!reqbufs_user_cap(req, 3)) {
+ if (!reqbufs_user(req, buftype, 3)) {
error("Cannot capture");
break;
}
if (req.count < 2) {
error("Too few buffers");
- reqbufs_user_cap(req);
+ reqbufs_user(req, buftype);
break;
}
}
}
for (i = 0; i < m_nbuffers; ++i)
- if (!qbuf_user_cap(i, m_buffers[i].start, m_buffers[i].length)) {
+ if (!qbuf_user(i, buftype, m_buffers[i].start, m_buffers[i].length)) {
perror("VIDIOC_QBUF");
goto error;
}
- if (!streamon_cap()) {
+ if (!streamon(buftype)) {
perror("VIDIOC_STREAMON");
goto error;
}
void ApplicationWindow::stopCapture()
{
+ __u32 buftype = m_genTab->bufType();
v4l2_requestbuffers reqbufs;
v4l2_encoder_cmd cmd;
unsigned i;
case methodMmap:
if (m_buffers == NULL)
break;
- if (!streamoff_cap())
+ if (!streamoff(buftype))
perror("VIDIOC_STREAMOFF");
for (i = 0; i < m_nbuffers; ++i)
if (-1 == munmap(m_buffers[i].start, m_buffers[i].length))
perror("munmap");
// Free all buffers.
- reqbufs_mmap_cap(reqbufs, 1); // videobuf workaround
- reqbufs_mmap_cap(reqbufs, 0);
+ reqbufs_mmap(reqbufs, buftype, 1); // videobuf workaround
+ reqbufs_mmap(reqbufs, buftype, 0);
break;
case methodUser:
- if (!streamoff_cap())
+ if (!streamoff(buftype))
perror("VIDIOC_STREAMOFF");
// Free all buffers.
- reqbufs_user_cap(reqbufs, 1); // videobuf workaround
- reqbufs_user_cap(reqbufs, 0);
+ reqbufs_user(reqbufs, buftype, 1); // videobuf workaround
+ reqbufs_user(reqbufs, buftype, 0);
for (i = 0; i < m_nbuffers; ++i)
free(m_buffers[i].start);
break;
};
QImage::Format dstFmt = QImage::Format_RGB888;
struct v4l2_fract interval;
+ v4l2_pix_format &srcPix = m_capSrcFormat.fmt.pix;
+ v4l2_pix_format &dstPix = m_capDestFormat.fmt.pix;
if (!start) {
stopCapture();
m_showFrames = m_showFramesAct->isChecked();
m_frame = m_lastFrame = m_fps = 0;
m_capMethod = m_genTab->capMethod();
- g_fmt_cap(m_capSrcFormat);
- s_fmt(m_capSrcFormat);
- if (m_genTab->get_interval(interval))
- set_interval(interval);
+
+ if (m_genTab->isVbi()) {
+ v4l2_format fmt;
+
+ g_fmt_vbi(fmt);
+ srcPix.pixelformat = fmt.fmt.vbi.sample_format;
+ srcPix.width = srcPix.bytesperline =
+ fmt.fmt.vbi.samples_per_line;
+ if (fmt.fmt.vbi.flags & V4L2_VBI_INTERLACED) {
+ srcPix.height = fmt.fmt.vbi.count[0];
+ srcPix.field = V4L2_FIELD_INTERLACED;
+ } else {
+ srcPix.height = fmt.fmt.vbi.count[0] + fmt.fmt.vbi.count[1];
+ srcPix.field = V4L2_FIELD_NONE;
+ }
+ srcPix.sizeimage = srcPix.bytesperline * srcPix.height;
+ } else {
+ g_fmt_cap(m_capSrcFormat);
+ s_fmt(m_capSrcFormat);
+ if (m_genTab->get_interval(interval))
+ set_interval(interval);
+ }
m_mustConvert = m_showFrames;
if (m_showFrames) {
- m_frameData = new unsigned char[m_capSrcFormat.fmt.pix.sizeimage];
+ m_frameData = new unsigned char[srcPix.sizeimage];
m_capDestFormat = m_capSrcFormat;
- m_capDestFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ dstPix.pixelformat = V4L2_PIX_FMT_RGB24;
for (int i = 0; supported_fmts[i].v4l2_pixfmt; i++) {
- if (supported_fmts[i].v4l2_pixfmt == m_capSrcFormat.fmt.pix.pixelformat) {
- m_capDestFormat.fmt.pix.pixelformat = supported_fmts[i].v4l2_pixfmt;
+ if (supported_fmts[i].v4l2_pixfmt == srcPix.pixelformat) {
+ dstPix.pixelformat = supported_fmts[i].v4l2_pixfmt;
dstFmt = supported_fmts[i].qt_pixfmt;
m_mustConvert = false;
break;
}
}
if (m_mustConvert) {
+ v4l2_format copy = m_capSrcFormat;
+
v4lconvert_try_format(m_convertData, &m_capDestFormat, &m_capSrcFormat);
// v4lconvert_try_format sometimes modifies the source format if it thinks
// that there is a better format available. Restore our selected source
// format since we do not want that happening.
- g_fmt_cap(m_capSrcFormat);
+ m_capSrcFormat = copy;
}
- m_capture->setMinimumSize(m_capDestFormat.fmt.pix.width, m_capDestFormat.fmt.pix.height);
- m_capImage = new QImage(m_capDestFormat.fmt.pix.width, m_capDestFormat.fmt.pix.height, dstFmt);
+ if (m_genTab->isVbi()) {
+ dstPix.bytesperline = (dstPix.bytesperline + 3) & ~3;
+ dstPix.sizeimage = dstPix.bytesperline * dstPix.height * 3;
+ }
+ m_capture->setMinimumSize(dstPix.width, dstPix.height);
+ m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
m_capImage->fill(0);
m_capture->setImage(*m_capImage, "No frame");
m_capture->show();
}
+
statusBar()->showMessage("No frame");
- if (startCapture(m_capSrcFormat.fmt.pix.sizeimage)) {
+ if (startCapture(srcPix.sizeimage)) {
m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capFrame()));
}
return ioctl(VIDIOC_G_FMT, &fmt) >= 0;
}
+bool v4l2::g_fmt_vbi(v4l2_format &fmt)
+{
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ return ioctl(VIDIOC_G_FMT, &fmt) >= 0;
+}
+
bool v4l2::try_fmt(v4l2_format &fmt)
{
fmt.fmt.pix.field = V4L2_FIELD_ANY;
return ioctl(VIDIOC_ENUM_FRAMEINTERVALS, &frm) >= 0;
}
-bool v4l2::reqbufs_user_cap(v4l2_requestbuffers &reqbuf, int count)
+bool v4l2::reqbufs_user(v4l2_requestbuffers &reqbuf, __u32 buftype, int count)
{
memset(&reqbuf, 0, sizeof (reqbuf));
- reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ reqbuf.type = buftype;
reqbuf.memory = V4L2_MEMORY_USERPTR;
reqbuf.count = count;
return ioctl(VIDIOC_REQBUFS, &reqbuf) >= 0;
}
-bool v4l2::reqbufs_mmap_cap(v4l2_requestbuffers &reqbuf, int count)
+bool v4l2::reqbufs_mmap(v4l2_requestbuffers &reqbuf, __u32 buftype, int count)
{
memset(&reqbuf, 0, sizeof (reqbuf));
- reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ reqbuf.type = buftype;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = count;
return ioctl(VIDIOC_REQBUFS, &reqbuf) >= 0;
}
-bool v4l2::dqbuf_mmap_cap(v4l2_buffer &buf, bool &again)
+bool v4l2::dqbuf_mmap(v4l2_buffer &buf, __u32 buftype, bool &again)
{
int res;
memset(&buf, 0, sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = buftype;
buf.memory = V4L2_MEMORY_MMAP;
res = ioctl(VIDIOC_DQBUF, &buf);
again = res < 0 && errno == EAGAIN;
return res >= 0 || again;
}
-bool v4l2::dqbuf_user_cap(v4l2_buffer &buf, bool &again)
+bool v4l2::dqbuf_user(v4l2_buffer &buf, __u32 buftype, bool &again)
{
int res;
memset(&buf, 0, sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = buftype;
buf.memory = V4L2_MEMORY_USERPTR;
res = ioctl(VIDIOC_DQBUF, &buf);
again = res < 0 && errno == EAGAIN;
return ioctl(VIDIOC_QBUF, &buf) >= 0;
}
-bool v4l2::qbuf_mmap_cap(int index)
+bool v4l2::qbuf_mmap(int index, __u32 buftype)
{
v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = buftype;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = index;
return qbuf(buf);
}
-bool v4l2::qbuf_user_cap(int index, void *ptr, int length)
+bool v4l2::qbuf_user(int index, __u32 buftype, void *ptr, int length)
{
v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = buftype;
buf.memory = V4L2_MEMORY_USERPTR;
buf.m.userptr = (unsigned long)ptr;
buf.length = length;
return qbuf(buf);
}
-bool v4l2::streamon_cap()
+bool v4l2::streamon(__u32 buftype)
{
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return ioctl("Start Capture", VIDIOC_STREAMON, &type);
+ return ioctl("Start Streaming", VIDIOC_STREAMON, &buftype);
}
-bool v4l2::streamoff_cap()
+bool v4l2::streamoff(__u32 buftype)
{
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return ioctl("Stop Capture", VIDIOC_STREAMOFF, &type);
+ return ioctl("Stop Streaming", VIDIOC_STREAMOFF, &buftype);
}
bool v4l2::reqbufs_user_out(v4l2_requestbuffers &reqbuf)
bool s_frequency(int freq, bool low = false);
bool g_fmt_cap(v4l2_format &fmt);
bool g_fmt_out(v4l2_format &fmt);
+ bool g_fmt_vbi(v4l2_format &fmt);
bool try_fmt(v4l2_format &fmt);
bool s_fmt(v4l2_format &fmt);
bool enum_input(v4l2_input &in, bool init = false, int index = 0);
bool enum_framesizes(v4l2_frmsizeenum &frm, __u32 init_pixfmt = 0, int index = 0);
bool enum_frameintervals(v4l2_frmivalenum &frm, __u32 init_pixfmt = 0, __u32 w = 0, __u32 h = 0, int index = 0);
- bool reqbufs_mmap_cap(v4l2_requestbuffers &reqbuf, int count = 0);
- bool reqbufs_user_cap(v4l2_requestbuffers &reqbuf, int count = 0);
- bool dqbuf_mmap_cap(v4l2_buffer &buf, bool &again);
- bool dqbuf_user_cap(v4l2_buffer &buf, bool &again);
+ bool reqbufs_mmap(v4l2_requestbuffers &reqbuf, __u32 buftype, int count = 0);
+ bool reqbufs_user(v4l2_requestbuffers &reqbuf, __u32 buftype, int count = 0);
+ bool dqbuf_mmap(v4l2_buffer &buf, __u32 buftype, bool &again);
+ bool dqbuf_user(v4l2_buffer &buf, __u32 buftype, bool &again);
bool qbuf(v4l2_buffer &buf);
- bool qbuf_mmap_cap(int index);
- bool qbuf_user_cap(int index, void *ptr, int length);
- bool streamon_cap();
- bool streamoff_cap();
+ bool qbuf_mmap(int index, __u32 buftype);
+ bool qbuf_user(int index, __u32 buftype, void *ptr, int length);
+ bool streamon(__u32 buftype);
+ bool streamoff(__u32 buftype);
+
+ inline bool reqbufs_mmap_cap(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return reqbufs_mmap(reqbuf, V4L2_BUF_TYPE_VIDEO_CAPTURE, count);
+ }
+ inline bool reqbufs_user_cap(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return reqbufs_user(reqbuf, V4L2_BUF_TYPE_VIDEO_CAPTURE, count);
+ }
+ inline bool dqbuf_mmap_cap(v4l2_buffer &buf, bool &again) {
+ return dqbuf_mmap(buf, V4L2_BUF_TYPE_VIDEO_CAPTURE, again);
+ }
+ inline bool dqbuf_user_cap(v4l2_buffer &buf, bool &again) {
+ return dqbuf_user(buf, V4L2_BUF_TYPE_VIDEO_CAPTURE, again);
+ }
+ inline bool qbuf_mmap_cap(int index) {
+ return qbuf_mmap(index, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ }
+ inline bool qbuf_user_cap(int index, void *ptr, int length) {
+ return qbuf_user(index, V4L2_BUF_TYPE_VIDEO_CAPTURE, ptr, length);
+ }
+ inline bool streamon_cap() { return streamon(V4L2_BUF_TYPE_VIDEO_CAPTURE); }
+ inline bool streamoff_cap() { return streamoff(V4L2_BUF_TYPE_VIDEO_CAPTURE); }
+
+ inline bool reqbufs_mmap_vbi(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return reqbufs_mmap(reqbuf, V4L2_BUF_TYPE_VBI_CAPTURE, count);
+ }
+ inline bool reqbufs_user_vbi(v4l2_requestbuffers &reqbuf, int count = 0) {
+ return reqbufs_user(reqbuf, V4L2_BUF_TYPE_VBI_CAPTURE, count);
+ }
+ inline bool dqbuf_mmap_vbi(v4l2_buffer &buf, bool &again) {
+ return dqbuf_mmap(buf, V4L2_BUF_TYPE_VBI_CAPTURE, again);
+ }
+ inline bool dqbuf_user_vbi(v4l2_buffer &buf, bool &again) {
+ return dqbuf_user(buf, V4L2_BUF_TYPE_VBI_CAPTURE, again);
+ }
+ inline bool qbuf_mmap_vbi(int index) {
+ return qbuf_mmap(index, V4L2_BUF_TYPE_VBI_CAPTURE);
+ }
+ inline bool qbuf_user_vbi(int index, void *ptr, int length) {
+ return qbuf_user(index, V4L2_BUF_TYPE_VBI_CAPTURE, ptr, length);
+ }
+ inline bool streamon_vbi() { return streamon(V4L2_BUF_TYPE_VBI_CAPTURE); }
+ inline bool streamoff_vbi() { return streamoff(V4L2_BUF_TYPE_VBI_CAPTURE); }
bool reqbufs_mmap_out(v4l2_requestbuffers &reqbuf, int count = 0);
bool reqbufs_user_out(v4l2_requestbuffers &reqbuf);