Replace the old v4l2-api.cpp/.h files by the cv4l-helpers.h.
It's a major change, but without any functional changes involved,
just refactoring.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
bin_PROGRAMS = qv4l2
man_MANS = qv4l2.1
-qv4l2_SOURCES = qv4l2.cpp general-tab.cpp ctrl-tab.cpp vbi-tab.cpp v4l2-api.cpp capture-win.cpp \
+qv4l2_SOURCES = qv4l2.cpp general-tab.cpp ctrl-tab.cpp vbi-tab.cpp capture-win.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 v4l2-api.h raw2sliced.h
+ raw2sliced.cpp qv4l2.h capture-win.h general-tab.h vbi-tab.h raw2sliced.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
if WITH_QTGL
-qv4l2_CPPFLAGS = $(QTGL_CFLAGS)
+qv4l2_CPPFLAGS += $(QTGL_CFLAGS)
qv4l2_LDFLAGS = $(QTGL_LIBS)
else
-qv4l2_CPPFLAGS = $(QT_CFLAGS)
+qv4l2_CPPFLAGS += $(QT_CFLAGS)
qv4l2_LDFLAGS = $(QT_LIBS)
endif
memset(&qctrl, 0, sizeof(qctrl));
qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
- while (queryctrl(qctrl)) {
+ while (!queryctrl(qctrl)) {
if (is_valid_type(qctrl.type) &&
(qctrl.flags & V4L2_CTRL_FLAG_DISABLED) == 0) {
m_ctrlMap[qctrl.id] = qctrl;
m_classMap[V4L2_CTRL_CLASS_USER].push_back(qctrl.id);
}
for (qctrl.id = V4L2_CID_PRIVATE_BASE;
- queryctrl(qctrl); qctrl.id++) {
+ !queryctrl(qctrl); qctrl.id++) {
if (!is_valid_type(qctrl.type))
continue;
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED)
for (int i = qctrl.minimum; i <= qctrl.maximum; i++) {
qmenu.id = qctrl.id;
qmenu.index = i;
- if (!querymenu(qmenu))
+ if (querymenu(qmenu))
continue;
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
combo->addItem((char *)qmenu.name);
ctrls.count = idx;
ctrls.ctrl_class = ctrl_class;
ctrls.controls = c;
- if (ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) {
+ if (cv4l_ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) {
if (ctrls.error_idx >= ctrls.count) {
error(errno);
}
for (i = qctrl.minimum; i <= qctrl.maximum; i++) {
qmenu.id = qctrl.id;
qmenu.index = i;
- if (!querymenu(qmenu))
+ if (querymenu(qmenu))
continue;
if (idx-- == 0)
break;
c.id = id;
c.value = getVal(id);
- if (ioctl(VIDIOC_S_CTRL, &c)) {
+ if (cv4l_ioctl(VIDIOC_S_CTRL, &c)) {
errorCtrl(id, errno, c.value);
}
else if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE)
ctrls.count = 1;
ctrls.ctrl_class = ctrl_class;
ctrls.controls = &c;
- if (ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) {
+ if (cv4l_ioctl(VIDIOC_S_EXT_CTRLS, &ctrls)) {
errorCtrl(id, errno, c.value);
}
else if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_UPDATE)
if (m_ctrlMap[id].flags & V4L2_CTRL_FLAG_WRITE_ONLY)
continue;
c.id = id;
- if (ioctl(VIDIOC_G_CTRL, &c)) {
+ if (cv4l_ioctl(VIDIOC_G_CTRL, &c)) {
errorCtrl(id, errno);
}
setVal(id, c.value);
ctrls.count = cnt;
ctrls.ctrl_class = ctrl_class;
ctrls.controls = c;
- if (ioctl(VIDIOC_G_EXT_CTRLS, &ctrls)) {
+ if (cv4l_ioctl(VIDIOC_G_EXT_CTRLS, &ctrls)) {
if (ctrls.error_idx >= ctrls.count) {
error(errno);
}
for (i = qctrl.minimum; i <= v; i++) {
qmenu.id = id;
qmenu.index = i;
- if (!querymenu(qmenu))
+ if (querymenu(qmenu))
continue;
idx++;
}
AUDIO_ADD_READWRITE
};
-GeneralTab::GeneralTab(const QString &device, v4l2 &fd, int n, QWidget *parent) :
+static QString pixfmt2s(unsigned id)
+{
+ QString pixfmt;
+
+ pixfmt += (char)(id & 0xff);
+ pixfmt += (char)((id >> 8) & 0xff);
+ pixfmt += (char)((id >> 16) & 0xff);
+ pixfmt += (char)((id >> 24) & 0xff);
+ return pixfmt;
+}
+
+GeneralTab::GeneralTab(const QString &device, cv4l_fd *_fd, int n, QWidget *parent) :
QGridLayout(parent),
- v4l2(fd),
+ cv4l_fd(_fd),
m_row(0),
m_col(0),
m_cols(n),
{
m_device.append(device);
setSizeConstraint(QLayout::SetMinimumSize);
+
for (int i = 0; i < n; i++) {
m_maxw[i] = 0;
}
+ cv4l_ioctl(VIDIOC_QUERYCAP, &m_querycap);
- if (querycap(m_querycap)) {
- addTitle("General Information");
+ addTitle("General Information");
- addLabel("Device");
- addLabel(device + (useWrapper() ? " (wrapped)" : ""));
+ addLabel("Device");
+ addLabel(device + (g_direct() ? "" : " (wrapped)"));
- addLabel("Driver");
- addLabel((char *)m_querycap.driver);
+ addLabel("Driver");
+ addLabel((char *)m_querycap.driver);
- addLabel("Card");
- addLabel((char *)m_querycap.card);
+ addLabel("Card");
+ addLabel((char *)m_querycap.card);
- addLabel("Bus");
- addLabel((char *)m_querycap.bus_info);
- }
+ addLabel("Bus");
+ addLabel((char *)m_querycap.bus_info);
g_tuner(m_tuner);
g_tuner(m_tuner_rf, 1);
(m_modulator.capability & (V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_1HZ)))
m_isRadio = true;
if (m_querycap.capabilities & V4L2_CAP_DEVICE_CAPS) {
- m_isVbi = caps() & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE);
- m_isSDR = caps() & V4L2_CAP_SDR_CAPTURE;
+ m_isVbi = g_caps() & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE);
+ m_isSDR = g_caps() & V4L2_CAP_SDR_CAPTURE;
if (m_isSDR)
m_isRadio = true;
- if (caps() & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))
+ if (g_caps() & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))
m_isOutput = true;
}
if (m_querycap.capabilities &
(V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE))
m_isPlanar = true;
- if (isSlicedVbi())
- m_buftype = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- else if (isVbi())
- m_buftype = V4L2_BUF_TYPE_VBI_CAPTURE;
- else if (m_isOutput)
- m_buftype = isPlanar() ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
- V4L2_BUF_TYPE_VIDEO_OUTPUT;
- else
- m_buftype = isPlanar() ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
- V4L2_BUF_TYPE_VIDEO_CAPTURE;
m_stackedStandards = new QStackedWidget;
m_stackedFrameSettings = new QStackedWidget;
m_stackedFrequency = new QStackedWidget;
- if (enum_input(vin, true) || m_tuner.capability) {
+ if (!enum_input(vin, true) || m_tuner.capability) {
addTitle("Input Settings");
inputSection(needsStd, needsTimings, vin);
}
- if (m_tuner_rf.capability || m_modulator.capability || (!isRadio() && enum_output(vout, true))) {
+ if (m_tuner_rf.capability || m_modulator.capability || (!isRadio() && !enum_output(vout, true))) {
addTitle("Output Settings");
outputSection(vout, fmt);
}
m_audioOutDevice = new QComboBox(parent);
}
- if (!isVbi() && (createAudioDeviceList() || (!isRadio() && enum_audio(vaudio, true)) ||
- (!isSDR() && m_tuner.capability) || (!isRadio() && enum_audout(vaudout, true)))) {
+ if (!isVbi() && (createAudioDeviceList() || (!isRadio() && !enum_audio(vaudio, true)) ||
+ (!isSDR() && m_tuner.capability) || (!isRadio() && !enum_audout(vaudout, true)))) {
addTitle("Audio Settings");
audioSection(vaudio, vaudout);
}
if (isVbi()) {
addLabel("VBI Capture Method");
m_vbiMethods = new QComboBox(parent);
- if (caps() & V4L2_CAP_VBI_CAPTURE)
+ if (g_caps() & V4L2_CAP_VBI_CAPTURE)
m_vbiMethods->addItem("Raw");
- if (caps() & V4L2_CAP_SLICED_VBI_CAPTURE)
+ if (g_caps() & V4L2_CAP_SLICED_VBI_CAPTURE)
m_vbiMethods->addItem("Sliced");
addWidget(m_vbiMethods);
connect(m_vbiMethods, SIGNAL(activated(int)), SLOT(vbiMethodsChanged(int)));
+ vbiMethodsChanged(0);
updateVideoInput();
goto capture_method;
}
capture_method:
addLabel("Capture Method");
m_capMethods = new QComboBox(parent);
- if (caps() & V4L2_CAP_STREAMING) {
- v4l2_requestbuffers reqbuf;
+ if (g_caps() & V4L2_CAP_STREAMING) {
+ cv4l_queue q;
- // Yuck. The videobuf framework does not accept a count of 0.
+ // Yuck. The videobuf framework does not accept a reqbufs count of 0.
// This is out-of-spec, but it means that the only way to test which
- // method is supported is to give it a non-zero count. But non-videobuf
- // drivers like uvc do not allow e.g. S_FMT calls after a REQBUFS call
- // with non-zero counts unless there is a REQBUFS call with count == 0
- // in between. This is actual proper behavior, although somewhat
- // 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(reqbuf, 1)) {
+ // method is supported is to give it a non-zero count. But after that
+ // we have to reopen the device to clear the fact that there were
+ // buffers allocated. This is the only really portable way as long
+ // as there are still drivers around that do not support reqbufs(0).
+ q.init(g_type(), V4L2_MEMORY_USERPTR);
+ if (q.reqbufs(this, 1) == 0) {
m_capMethods->addItem("User pointer I/O", QVariant(methodUser));
- reqbufs_user(reqbuf, 0);
+ reopen(true);
}
- if (reqbufs_mmap(reqbuf, 1)) {
+ q.init(g_type(), V4L2_MEMORY_MMAP);
+ if (q.reqbufs(this, 1) == 0) {
m_capMethods->addItem("Memory mapped I/O", QVariant(methodMmap));
- reqbufs_mmap(reqbuf, 0);
+ reopen(true);
}
}
- if (caps() & V4L2_CAP_READWRITE) {
+ if (g_caps() & V4L2_CAP_READWRITE) {
m_capMethods->addItem("read()", QVariant(methodRead));
}
addWidget(m_capMethods);
void GeneralTab::inputSection(bool needsStd, bool needsTimings, v4l2_input vin)
{
- if (!isRadio() && enum_input(vin, true)) {
+ if (!isRadio() && !enum_input(vin, true)) {
addLabel("Input");
m_videoInput = new QComboBox(parentWidget());
do {
};
subscribe_event(sub);
- } while (enum_input(vin));
+ } while (!enum_input(vin));
addWidget(m_videoInput);
connect(m_videoInput, SIGNAL(activated(int)), SLOT(inputChanged(int)));
m_row++;
m_stdRow->addWidget(m_tvStandard, 0, 1, Qt::AlignLeft);
connect(m_tvStandard, SIGNAL(activated(int)), SLOT(standardChanged(int)));
refreshStandards();
- if (ioctl_exists(VIDIOC_QUERYSTD, &tmp)) {
+ if (ioctl_exists(cv4l_ioctl(VIDIOC_QUERYSTD, &tmp))) {
m_qryStandard = new QToolButton(parentWidget());
m_qryStandard->setIcon(QIcon(":/enterbutt.png"));
m_stdRow->addWidget(new QLabel("Query Standard", parentWidget()), 0, 2, Qt::AlignLeft);
void GeneralTab::outputSection(v4l2_output vout, v4l2_fmtdesc fmt)
{
- if (!isRadio() && enum_output(vout, true)) {
+ if (!isRadio() && !enum_output(vout, true)) {
addLabel("Output");
m_videoOutput = new QComboBox(parentWidget());
do {
m_videoOutput->addItem((char *)vout.name);
- } while (enum_output(vout));
+ } while (!enum_output(vout));
addWidget(m_videoOutput);
connect(m_videoOutput, SIGNAL(activated(int)), SLOT(outputChanged(int)));
updateVideoOutput();
addLabel("Output Image Formats");
m_vidOutFormats = new QComboBox(parentWidget());
m_vidOutFormats->setMinimumContentsLength(20);
- if (enum_fmt(fmt, m_buftype, true)) {
+ if (!enum_fmt(fmt, true)) {
do {
m_vidOutFormats->addItem(pixfmt2s(fmt.pixelformat) +
" - " + (const char *)fmt.description);
- } while (enum_fmt(fmt, m_buftype));
+ } while (!enum_fmt(fmt));
}
addWidget(m_vidOutFormats);
connect(m_vidOutFormats, SIGNAL(activated(int)), SLOT(vidOutFormatChanged(int)));
setAudioDeviceBufferSize(75);
} else {
v4l2_fract fract;
- if (!v4l2::get_interval(m_buftype, fract)) {
+ if (cv4l_fd::get_interval(fract)) {
// Default values are for 30 FPS
fract.numerator = 33;
fract.denominator = 1000;
}
}
- if (!isRadio() && enum_audio(vaudio, true)) {
+ if (!isRadio() && !enum_audio(vaudio, true)) {
addLabel("Input Audio");
m_audioInput = new QComboBox(parentWidget());
m_audioInput->setMinimumContentsLength(10);
do {
m_audioInput->addItem((char *)vaudio.name);
- } while (enum_audio(vaudio));
+ } while (!enum_audio(vaudio));
addWidget(m_audioInput);
connect(m_audioInput, SIGNAL(activated(int)), SLOT(inputAudioChanged(int)));
updateAudioInput();
connect(m_audioMode, SIGNAL(activated(int)), SLOT(audioModeChanged(int)));
}
- if (!isRadio() && enum_audout(vaudout, true)) {
+ if (!isRadio() && !enum_audout(vaudout, true)) {
addLabel("Output Audio");
m_audioOutput = new QComboBox(parentWidget());
m_audioOutput->setMinimumContentsLength(10);
do {
m_audioOutput->addItem((char *)vaudout.name);
- } while (enum_audout(vaudout));
+ } while (!enum_audout(vaudout));
addWidget(m_audioOutput);
connect(m_audioOutput, SIGNAL(activated(int)), SLOT(outputAudioChanged(int)));
updateAudioOutput();
addLabel("Capture Image Formats");
m_vidCapFormats = new QComboBox(parentWidget());
m_vidCapFormats->setMinimumContentsLength(20);
- if (enum_fmt(fmt, m_buftype, true)) {
+ if (!enum_fmt(fmt, true)) {
do {
QString s(pixfmt2s(fmt.pixelformat) + " (");
m_vidCapFormats->addItem(s + "Emulated)");
else
m_vidCapFormats->addItem(s + (const char *)fmt.description + ")");
- } while (enum_fmt(fmt, m_buftype));
+ } while (!enum_fmt(fmt));
}
addWidget(m_vidCapFormats);
connect(m_vidCapFormats, SIGNAL(activated(int)), SLOT(vidCapFormatChanged(int)));
{
v4l2_input in;
enum_input(in, true, input);
- if (!g_input(input) || m_isRadio) {
+ if (g_input(input) || m_isRadio) {
m_stackedFrameSettings->hide();
return;
}
{
v4l2_fmtdesc desc;
- enum_fmt(desc, m_buftype, true, idx);
+ enum_fmt(desc, true, idx);
- v4l2_format fmt;
+ cv4l_fmt fmt;
- g_fmt(m_buftype, fmt);
- if (isPlanar())
- fmt.fmt.pix_mp.pixelformat = desc.pixelformat;
- else
- fmt.fmt.pix.pixelformat = desc.pixelformat;
- if (try_fmt(fmt))
+ g_fmt(fmt);
+ fmt.s_pixelformat(desc.pixelformat);
+ if (try_fmt(fmt) == 0)
s_fmt(fmt);
updateVidCapFormat();
void GeneralTab::vidFieldChanged(int idx)
{
- v4l2_format fmt;
+ cv4l_fmt fmt;
- g_fmt(m_buftype, fmt);
+ g_fmt(fmt);
for (__u32 f = V4L2_FIELD_NONE; f <= V4L2_FIELD_INTERLACED_BT; f++) {
if (m_vidFields->currentText() == QString(field2s(f))) {
- if (isPlanar())
- fmt.fmt.pix_mp.field = f;
- else
- fmt.fmt.pix.field = f;
+ fmt.s_field(f);
s_fmt(fmt);
break;
}
void GeneralTab::frameWidthChanged()
{
- v4l2_format fmt;
+ cv4l_fmt fmt;
int val = m_frameWidth->value();
if (m_frameWidth->isEnabled()) {
- g_fmt(m_buftype, fmt);
- if (isPlanar())
- fmt.fmt.pix_mp.width = val;
- else
- fmt.fmt.pix.width = val;
- if (try_fmt(fmt))
+ g_fmt(fmt);
+ fmt.s_width(val);
+ if (try_fmt(fmt) == 0)
s_fmt(fmt);
}
void GeneralTab::frameHeightChanged()
{
- v4l2_format fmt;
+ cv4l_fmt fmt;
int val = m_frameHeight->value();
if (m_frameHeight->isEnabled()) {
- g_fmt(m_buftype, fmt);
- if (isPlanar())
- fmt.fmt.pix_mp.height = val;
- else
- fmt.fmt.pix.height = val;
- if (try_fmt(fmt))
+ g_fmt(fmt);
+ fmt.s_height(val);
+ if (try_fmt(fmt) == 0)
s_fmt(fmt);
}
void GeneralTab::frameSizeChanged(int idx)
{
- v4l2_frmsizeenum frmsize;
+ v4l2_frmsizeenum frmsize = { 0 };
- if (enum_framesizes(frmsize, m_pixelformat, idx)) {
- v4l2_format fmt;
+ if (!enum_framesizes(frmsize, m_pixelformat, idx)) {
+ cv4l_fmt fmt;
- g_fmt(m_buftype, fmt);
- if (isPlanar()) {
- fmt.fmt.pix_mp.width = frmsize.discrete.width;
- fmt.fmt.pix_mp.height = frmsize.discrete.height;
- } else {
- fmt.fmt.pix.width = frmsize.discrete.width;
- fmt.fmt.pix.height = frmsize.discrete.height;
- }
- if (try_fmt(fmt))
+ g_fmt(fmt);
+ fmt.s_width(frmsize.discrete.width);
+ fmt.s_height(frmsize.discrete.height);
+ if (try_fmt(fmt) == 0)
s_fmt(fmt);
}
updateVidFormat();
void GeneralTab::frameIntervalChanged(int idx)
{
- v4l2_frmivalenum frmival;
+ v4l2_frmivalenum frmival = { 0 };
- if (enum_frameintervals(frmival, m_pixelformat, m_width, m_height, idx)
+ if (!enum_frameintervals(frmival, m_pixelformat, m_width, m_height, idx)
&& frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
- if (set_interval(m_buftype, frmival.discrete))
+ if (!set_interval(frmival.discrete))
m_interval = frmival.discrete;
}
}
{
v4l2_fmtdesc desc;
- enum_fmt(desc, m_buftype, true, idx);
+ enum_fmt(desc, true, idx);
- v4l2_format fmt;
+ cv4l_fmt fmt;
- g_fmt(m_buftype, fmt);
- fmt.fmt.pix.pixelformat = desc.pixelformat;
- if (try_fmt(fmt))
+ g_fmt(fmt);
+ fmt.s_pixelformat(desc.pixelformat);
+ if (try_fmt(fmt) == 0)
s_fmt(fmt);
updateVidOutFormat();
}
void GeneralTab::vbiMethodsChanged(int idx)
{
- m_buftype = isSlicedVbi() ? V4L2_BUF_TYPE_SLICED_VBI_CAPTURE :
- V4L2_BUF_TYPE_VBI_CAPTURE;
+ s_type(isSlicedVbi() ? V4L2_BUF_TYPE_SLICED_VBI_CAPTURE :
+ V4L2_BUF_TYPE_VBI_CAPTURE);
}
void GeneralTab::cropChanged()
crop.c.left = m_cropLeft->value();
crop.c.height = m_cropHeight->value();
crop.c.top = m_cropTop->value();
- ioctl("Set Crop Rectangle", VIDIOC_S_CROP, &crop);
+ cv4l_ioctl(VIDIOC_S_CROP, &crop);
updateVidCapFormat();
}
sel.r.left = m_composeLeft->value();
sel.r.height = m_composeHeight->value();
sel.r.top = m_composeTop->value();
- ioctl("Set Compose Rectangle", VIDIOC_S_SELECTION, &sel);
+ cv4l_ioctl(VIDIOC_S_SELECTION, &sel);
updateVidCapFormat();
}
int input;
v4l2_input in;
- if (!g_input(input))
+ if (g_input(input))
return;
enum_input(in, true, input);
m_videoInput->setCurrentIndex(input);
int output;
v4l2_output out;
- if (!g_output(output))
+ if (g_output(output))
return;
enum_output(out, true, output);
m_videoOutput->setCurrentIndex(output);
{
v4l2_standard vs;
m_tvStandard->clear();
- if (enum_std(vs, true)) {
+ if (!enum_std(vs, true)) {
do {
m_tvStandard->addItem((char *)vs.name);
- } while (enum_std(vs));
+ } while (!enum_std(vs));
}
}
QString what;
g_std(std);
- if (enum_std(vs, true)) {
+ if (!enum_std(vs, true)) {
do {
if (vs.id == std)
break;
- } while (enum_std(vs));
+ } while (!enum_std(vs));
}
if (vs.id != std) {
- if (enum_std(vs, true)) {
+ if (!enum_std(vs, true)) {
do {
if (vs.id & std)
break;
- } while (enum_std(vs));
+ } while (!enum_std(vs));
}
}
if ((vs.id & std) == 0)
{
v4l2_enum_dv_timings timings;
m_videoTimings->clear();
- if (enum_dv_timings(timings, true)) {
+ if (!enum_dv_timings(timings, true)) {
do {
v4l2_bt_timings &bt = timings.timings.bt;
double tot_height = bt.height +
sprintf(buf, "%dx%dp%.2f", bt.width, bt.height,
(double)bt.pixelclock / (tot_width * tot_height));
m_videoTimings->addItem(buf);
- } while (enum_dv_timings(timings));
+ } while (!enum_dv_timings(timings));
}
}
QString what;
g_dv_timings(timings);
- if (enum_dv_timings(p, true)) {
+ if (!enum_dv_timings(p, true)) {
do {
if (!memcmp(&timings, &p.timings, sizeof(timings)))
break;
- } while (enum_dv_timings(p));
+ } while (!enum_dv_timings(p));
}
if (memcmp(&timings, &p.timings, sizeof(timings)))
return;
{
v4l2_dv_timings timings;
- if (query_dv_timings(timings)) {
+ if (!query_dv_timings(timings)) {
s_dv_timings(timings);
updateTimings();
}
void GeneralTab::updateVidCapFormat()
{
v4l2_fmtdesc desc;
- v4l2_format fmt;
+ cv4l_fmt fmt;
if (isVbi())
return;
- g_fmt(m_buftype, fmt);
- if (isPlanar()) {
- m_pixelformat = fmt.fmt.pix_mp.pixelformat;
- m_width = fmt.fmt.pix_mp.width;
- m_height = fmt.fmt.pix_mp.height;
- } else {
- m_pixelformat = fmt.fmt.pix.pixelformat;
- m_width = fmt.fmt.pix.width;
- m_height = fmt.fmt.pix.height;
- }
+ g_fmt(fmt);
+ m_pixelformat = fmt.g_pixelformat();
+ m_width = fmt.g_width();
+ m_height = fmt.g_height();
updateFrameSize();
updateFrameInterval();
- if (enum_fmt(desc, m_buftype, true)) {
+ if (!enum_fmt(desc, true)) {
do {
- if (isPlanar()) {
- if (desc.pixelformat == fmt.fmt.pix_mp.pixelformat)
- break;
- } else {
- if (desc.pixelformat == fmt.fmt.pix.pixelformat)
- break;
- }
- } while (enum_fmt(desc, m_buftype));
- }
- if (isPlanar()) {
- if (desc.pixelformat != fmt.fmt.pix_mp.pixelformat)
- return;
- } else {
- if (desc.pixelformat != fmt.fmt.pix.pixelformat)
- return;
+ if (desc.pixelformat == m_pixelformat)
+ break;
+ } while (!enum_fmt(desc));
}
+ if (desc.pixelformat != m_pixelformat)
+ return;
m_vidCapFormats->setCurrentIndex(desc.index);
updateVidFields();
updateCrop();
void GeneralTab::updateVidOutFormat()
{
v4l2_fmtdesc desc;
- v4l2_format fmt;
+ cv4l_fmt fmt;
- g_fmt(m_buftype, fmt);
- if (isPlanar()) {
- m_pixelformat = fmt.fmt.pix_mp.pixelformat;
- m_width = fmt.fmt.pix_mp.width;
- m_height = fmt.fmt.pix_mp.height;
- } else {
- m_pixelformat = fmt.fmt.pix.pixelformat;
- m_width = fmt.fmt.pix.width;
- m_height = fmt.fmt.pix.height;
- }
+ g_fmt(fmt);
+ m_pixelformat = fmt.g_pixelformat();
+ m_width = fmt.g_width();
+ m_height = fmt.g_height();
updateFrameSize();
updateFrameInterval();
- if (enum_fmt(desc, m_buftype, true)) {
+ if (!enum_fmt(desc, true)) {
do {
- if (isPlanar()) {
- if (desc.pixelformat == fmt.fmt.pix_mp.pixelformat)
- break;
- } else {
- if (desc.pixelformat == fmt.fmt.pix.pixelformat)
- break;
- }
- } while (enum_fmt(desc, m_buftype));
- }
- if (isPlanar()) {
- if (desc.pixelformat != fmt.fmt.pix_mp.pixelformat)
- return;
- } else {
- if (desc.pixelformat != fmt.fmt.pix.pixelformat)
- return;
+ if (desc.pixelformat == m_pixelformat)
+ break;
+ } while (!enum_fmt(desc));
}
+ if (desc.pixelformat == m_pixelformat)
+ return;
m_vidOutFormats->setCurrentIndex(desc.index);
updateVidFields();
}
void GeneralTab::updateVidFields()
{
- v4l2_format fmt;
- v4l2_format tmp;
+ cv4l_fmt fmt;
+ cv4l_fmt tmp;
bool first = true;
- g_fmt(m_buftype, fmt);
+ g_fmt(fmt);
for (__u32 f = V4L2_FIELD_NONE; f <= V4L2_FIELD_INTERLACED_BT; f++) {
tmp = fmt;
- if (isPlanar()) {
- tmp.fmt.pix_mp.field = f;
- if (!try_fmt(tmp) || tmp.fmt.pix_mp.field != f)
- continue;
- if (first) {
- m_vidFields->clear();
- first = false;
- }
- m_vidFields->addItem(field2s(f));
- if (fmt.fmt.pix_mp.field == f)
- m_vidFields->setCurrentIndex(m_vidFields->count() - 1);
- } else {
- tmp.fmt.pix.field = f;
- if (!try_fmt(tmp) || tmp.fmt.pix.field != f)
- continue;
- if (first) {
- m_vidFields->clear();
- first = false;
- }
- m_vidFields->addItem(field2s(f));
- if (fmt.fmt.pix.field == f)
- m_vidFields->setCurrentIndex(m_vidFields->count() - 1);
+ tmp.s_field(f);
+ if (try_fmt(tmp) || tmp.g_field() != f)
+ continue;
+ if (first) {
+ m_vidFields->clear();
+ first = false;
}
+ m_vidFields->addItem(field2s(f));
+ if (fmt.g_field() == f)
+ m_vidFields->setCurrentIndex(m_vidFields->count() - 1);
}
}
v4l2_rect &c = crop.c;
cropcap.type = crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (ioctl(VIDIOC_CROPCAP, &cropcap) ||
- ioctl(VIDIOC_G_CROP, &crop))
+ if (cv4l_ioctl(VIDIOC_CROPCAP, &cropcap) ||
+ cv4l_ioctl(VIDIOC_G_CROP, &crop))
return;
m_cropWidth->blockSignals(true);
sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
sel.target = V4L2_SEL_TGT_COMPOSE;
- if (ioctl(VIDIOC_G_SELECTION, &sel))
+ if (cv4l_ioctl(VIDIOC_G_SELECTION, &sel))
return;
m_composeWidth->blockSignals(true);
m_frameSize->clear();
- ok = enum_framesizes(frmsize, m_pixelformat);
+ ok = !enum_framesizes(frmsize, m_pixelformat);
if (ok && frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
do {
m_frameSize->addItem(QString("%1x%2")
if (frmsize.discrete.width == m_width &&
frmsize.discrete.height == m_height)
m_frameSize->setCurrentIndex(frmsize.index);
- } while (enum_framesizes(frmsize));
+ } while (!enum_framesizes(frmsize));
m_discreteSizes = true;
m_frameWidth->setEnabled(false);
v4l2_fract ratio = { 1, 1 };
unsigned w = 0, h = 0;
- ratio = g_pixel_aspect(m_buftype, w, h);
+ ratio = g_pixel_aspect(w, h);
switch (m_pixelAspectRatio->currentIndex()) {
// override ratio if hardcoded, but keep w and h
case 1:
.arg(ratio.numerator).arg(ratio.denominator));
m_pixelAspectRatio->setStatusTip(m_pixelAspectRatio->whatsThis());
- v4l2_format fmt;
+ cv4l_fmt fmt;
unsigned cur_width, cur_height;
unsigned cur_field;
- g_fmt(m_buftype, fmt);
+ g_fmt(fmt);
- if (isPlanar()) {
- cur_width = fmt.fmt.pix_mp.width;
- cur_height = fmt.fmt.pix_mp.height;
- cur_field = fmt.fmt.pix_mp.field;
- } else {
- cur_width = fmt.fmt.pix.width;
- cur_height = fmt.fmt.pix.height;
- cur_field = fmt.fmt.pix.field;
- }
+ cur_width = fmt.g_width();
+ cur_height = fmt.g_height();
+ cur_field = fmt.g_field();
if (w == 0)
w = cur_width;
if (cur_field == V4L2_FIELD_TOP ||
void GeneralTab::updateFrameInterval()
{
- v4l2_frmivalenum frmival;
- v4l2_fract curr;
+ v4l2_frmivalenum frmival = { 0 };
+ v4l2_fract curr = { 1, 1 };
bool curr_ok, ok;
m_frameInterval->clear();
- ok = enum_frameintervals(frmival, m_pixelformat, m_width, m_height);
+ ok = !enum_frameintervals(frmival, m_pixelformat, m_width, m_height);
m_has_interval = ok && frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE;
m_frameInterval->setEnabled(m_has_interval);
if (m_has_interval) {
m_interval = frmival.discrete;
- curr_ok = v4l2::get_interval(m_buftype, curr);
+ curr_ok = !cv4l_fd::get_interval(curr);
do {
m_frameInterval->addItem(QString("%1 fps")
.arg((double)frmival.discrete.denominator / frmival.discrete.numerator));
m_frameInterval->setCurrentIndex(frmival.index);
m_interval = frmival.discrete;
}
- } while (enum_frameintervals(frmival));
+ } while (!enum_frameintervals(frmival));
}
}
#include <map>
#include "qv4l2.h"
-#include "v4l2-api.h"
#include "capture-win.h"
#ifdef HAVE_ALSA
class QToolButton;
class QSlider;
-class GeneralTab: public QGridLayout, public v4l2
+class GeneralTab: public QGridLayout, cv4l_fd
{
Q_OBJECT
public:
- GeneralTab(const QString &device, v4l2 &fd, int n, QWidget *parent = 0);
+ GeneralTab(const QString &device, cv4l_fd *fd, int n, QWidget *parent = 0);
virtual ~GeneralTab() {}
CapMethod capMethod();
bool isVbi() const { return m_isVbi; }
bool isSlicedVbi() const;
bool isPlanar() const { return m_isPlanar; }
- __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 streamon() { return v4l2::streamon(m_buftype); }
- inline bool streamoff() { return v4l2::streamoff(m_buftype); }
void setHaveBuffers(bool haveBuffers);
void sourceChange(const v4l2_event &ev);
unsigned getDisplayColorspace() const;
bool m_isPlanar;
bool m_haveBuffers;
bool m_discreteSizes;
- __u32 m_buftype;
__u32 m_audioModes[5];
QString m_device;
struct v4l2_tuner m_tuner;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "qv4l2.h"
-#include "general-tab.h"
-#include "vbi-tab.h"
-#include "capture-win.h"
-#include "capture-win-qt.h"
-#include "capture-win-gl.h"
-
#ifdef ENABLE_ASLA
extern "C" {
#include "alsa_stream.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <dirent.h>
-#include <libv4l2.h>
+
+#include "qv4l2.h"
+#include "general-tab.h"
+#include "vbi-tab.h"
+#include "capture-win.h"
+#include "capture-win-qt.h"
+#include "capture-win-gl.h"
+
+#include <libv4lconvert.h>
ApplicationWindow::ApplicationWindow() :
m_capture(NULL),
m_capImage = NULL;
m_frameData = NULL;
m_nbuffers = 0;
- m_buffers = NULL;
m_makeSnapshot = false;
+ for (unsigned b = 0; b < sizeof(m_clear); b++)
+ m_clear[b] = false;
QAction *openAct = new QAction(QIcon(":/fileopen.png"), "&Open Device", this);
openAct->setStatusTip("Open a v4l device, use libv4l2 wrapper if possible");
closeDevice();
}
-
void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
{
closeDevice();
m_sigMapper = new QSignalMapper(this);
connect(m_sigMapper, SIGNAL(mapped(int)), this, SLOT(ctrlAction(int)));
- if (!open(device, !rawOpen)) {
+ s_direct(rawOpen);
+
+ if (open(device.toLatin1(), true) < 0) {
#ifdef HAVE_ALSA
m_showAllAudioAct->setEnabled(false);
m_audioBufferAct->setEnabled(false);
newCaptureWin();
QWidget *w = new QWidget(m_tabs);
- m_genTab = new GeneralTab(device, *this, 4, w);
+ m_genTab = new GeneralTab(device, this, 4, w);
int size[2];
size[0] = m_genTab->getWidth();
size[1] = m_genTab->getHeight();
connect(m_genTab, SIGNAL(clearBuffers()), this, SLOT(clearBuffers()));
m_tabs->addTab(w, "General Settings");
addTabs(size);
- if (caps() & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)) {
+ m_vbiTab = NULL;
+ if (has_vbi_cap()) {
w = new QWidget(m_tabs);
m_vbiTab = new VbiTab(w);
m_tabs->addTab(w, "VBI");
statusBar()->clearMessage();
m_tabs->show();
m_tabs->setFocus();
- m_convertData = v4lconvert_create(fd());
- m_capStartAct->setEnabled(fd() >= 0);
- m_saveRawAct->setEnabled(fd() >= 0);
+ m_convertData = v4lconvert_create(g_fd());
+ m_capStartAct->setEnabled(g_fd() >= 0);
+ m_saveRawAct->setEnabled(g_fd() >= 0);
#ifdef HAVE_QTGL
m_useGLAct->setEnabled(CaptureWinGL::isSupported());
#endif
- m_ctrlNotifier = new QSocketNotifier(fd(), QSocketNotifier::Exception, m_tabs);
+ m_ctrlNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Exception, m_tabs);
connect(m_ctrlNotifier, SIGNAL(activated(int)), this, SLOT(ctrlEvent()));
}
{
v4l2_event ev;
- while (dqevent(ev)) {
+ while (dqevent(ev) == 0) {
if (ev.type == V4L2_EVENT_SOURCE_CHANGE) {
m_genTab->sourceChange(ev);
continue;
ctrls.count = 1;
ctrls.ctrl_class = 0;
ctrls.controls = &c;
- if (!ioctl(VIDIOC_G_EXT_CTRLS, &ctrls))
+ if (!cv4l_ioctl(VIDIOC_G_EXT_CTRLS, &ctrls))
setString(ev.id, c.string);
free(c.string);
}
connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
}
+bool ApplicationWindow::startCapture()
+{
+ startAudio();
+
+ if (m_genTab->isRadio())
+ return true;
+
+ m_queue.init(g_type(), m_capMethod);
+
+#ifdef HAVE_QTGL
+ m_useGLAct->setEnabled(false);
+#endif
+
+ switch (m_capMethod) {
+ case methodRead:
+ m_snapshotAct->setEnabled(true);
+ m_genTab->setHaveBuffers(true);
+ /* Nothing to do. */
+ return true;
+
+ case methodMmap:
+ case methodUser:
+ if (m_queue.reqbufs(this, 4)) {
+ error("Cannot capture");
+ break;
+ }
+
+ if (m_queue.g_buffers() < 2) {
+ error("Too few buffers");
+ break;
+ }
+
+ if (m_queue.obtain_bufs(this)) {
+ error("Get buffers");
+ break;
+ }
+
+ for (unsigned i = 0; i < m_queue.g_buffers(); i++) {
+ cv4l_buffer buf;
+
+ m_queue.buffer_init(buf, i);
+ qbuf(buf);
+ }
+
+ if (streamon()) {
+ perror("VIDIOC_STREAMON");
+ break;
+ }
+ m_snapshotAct->setEnabled(true);
+ m_genTab->setHaveBuffers(true);
+ return true;
+ }
+
+ m_queue.free(this);
+ reopen(true);
+ m_capStartAct->setChecked(false);
+#ifdef HAVE_QTGL
+ m_useGLAct->setEnabled(CaptureWinGL::isSupported());
+#endif
+ return false;
+}
+
void ApplicationWindow::capVbiFrame()
{
- __u32 buftype = m_genTab->bufType();
- v4l2_buffer buf;
+ cv4l_buffer buf(m_queue);
__u8 *data = NULL;
int s = 0;
- bool again;
switch (m_capMethod) {
case methodRead:
break;
case methodMmap:
- if (!dqbuf_mmap(buf, buftype, again)) {
- error("dqbuf");
- m_capStartAct->setChecked(false);
- return;
- }
- if (again)
- return;
- if (buf.flags & V4L2_BUF_FLAG_ERROR) {
- qbuf(buf);
- return;
- }
- data = (__u8 *)m_buffers[buf.index].start[0];
- s = buf.bytesused;
- break;
-
case methodUser:
- if (!dqbuf_user(buf, buftype, again)) {
+ if (dqbuf(buf)) {
+ if (errno == EAGAIN)
+ return;
error("dqbuf");
m_capStartAct->setChecked(false);
return;
}
- if (again)
- return;
- if (buf.flags & V4L2_BUF_FLAG_ERROR) {
+ if (buf.g_flags() & V4L2_BUF_FLAG_ERROR) {
qbuf(buf);
return;
}
- data = (__u8 *)buf.m.userptr;
- s = buf.bytesused;
+ data = (__u8 *)m_queue.g_dataptr(buf.g_index(), 0);
+ s = buf.g_bytesused();
break;
}
- if (buftype == V4L2_BUF_TYPE_VBI_CAPTURE && s != m_vbiSize) {
+ if (g_type() == V4L2_BUF_TYPE_VBI_CAPTURE && s != m_vbiSize) {
error("incorrect vbi size");
m_capStartAct->setChecked(false);
return;
}
- if (showFrames() && buftype == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (showFrames() && g_type() == V4L2_BUF_TYPE_VBI_CAPTURE) {
for (unsigned y = 0; y < m_vbiHeight; y++) {
__u8 *p = data + y * m_vbiWidth;
__u8 *q = m_capImage->bits() + y * m_capImage->bytesPerLine();
struct v4l2_sliced_vbi_data sdata[m_vbiHandle.count[0] + m_vbiHandle.count[1]];
struct v4l2_sliced_vbi_data *p;
- if (buftype == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ if (g_type() == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
p = (struct v4l2_sliced_vbi_data *)data;
} else {
vbi_parse(&m_vbiHandle, data, &sfmt, sdata);
m_tv = tv;
}
status = QString("Frame: %1 Fps: %2").arg(++m_frame).arg(m_fps);
- if (showFrames() && buftype == V4L2_BUF_TYPE_VBI_CAPTURE)
+ if (showFrames() && g_type() == V4L2_BUF_TYPE_VBI_CAPTURE)
m_capture->setFrame(m_capImage->width(), m_capImage->height(),
m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), NULL, status);
void ApplicationWindow::capFrame()
{
- __u32 buftype = m_genTab->bufType();
- v4l2_plane planes[VIDEO_MAX_PLANES];
- v4l2_buffer buf;
+ cv4l_buffer buf(m_queue);
+ unsigned char *plane[2];
+ unsigned bytesused[2];
int s = 0;
int err = 0;
- bool again;
#ifdef HAVE_ALSA
struct timeval tv_alsa;
#endif
- unsigned char *displaybuf = NULL;
- unsigned char *displaybuf2 = NULL;
-
+ plane[0] = plane[1] = NULL;
switch (m_capMethod) {
case methodRead:
- s = read(m_frameData, m_capSrcFormat.fmt.pix.sizeimage);
+ s = read(m_frameData, m_capSrcFormat.g_sizeimage(0));
#ifdef HAVE_ALSA
alsa_thread_timestamp(&tv_alsa);
#endif
if (m_saveRaw.openMode())
m_saveRaw.write((const char *)m_frameData, s);
- if (!showFrames())
- break;
- if (m_mustConvert)
+ plane[0] = m_frameData;
+ if (showFrames() && m_mustConvert) {
err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
m_frameData, s,
m_capImage->bits(), m_capDestFormat.fmt.pix.sizeimage);
- if (m_mustConvert && err != -1)
- displaybuf = m_capImage->bits();
- if (!m_mustConvert)
- displaybuf = m_frameData;
+ if (err != -1)
+ plane[0] = m_capImage->bits();
+ }
break;
case methodMmap:
- memset(planes, 0, sizeof(planes));
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
- if (!dqbuf_mmap(buf, buftype, again)) {
+ case methodUser:
+ if (dqbuf(buf)) {
+ if (errno == EAGAIN)
+ return;
error("dqbuf");
m_capStartAct->setChecked(false);
return;
}
-
- if (again)
- return;
- if (buf.flags & V4L2_BUF_FLAG_ERROR) {
+ if (buf.g_flags() & V4L2_BUF_FLAG_ERROR) {
qbuf(buf);
return;
}
alsa_thread_timestamp(&tv_alsa);
#endif
- if (showFrames()) {
- if (m_mustConvert)
- err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
- (unsigned char *)m_buffers[buf.index].start[0], buf.bytesused,
- m_capImage->bits(), m_capDestFormat.fmt.pix.sizeimage);
- if (m_mustConvert && err != -1)
- displaybuf = m_capImage->bits();
- if (!m_mustConvert) {
- displaybuf = (unsigned char *)m_buffers[buf.index].start[0];
- displaybuf2 = (unsigned char *)m_buffers[buf.index].start[1];
- if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
- displaybuf += planes[0].data_offset;
- displaybuf2 += planes[1].data_offset;
- }
- }
+ plane[0] = (__u8 *)m_queue.g_dataptr(buf.g_index(), 0);
+ plane[1] = (__u8 *)m_queue.g_dataptr(buf.g_index(), 1);
+ plane[0] += buf.g_data_offset(0);
+ bytesused[0] = buf.g_bytesused(0) - buf.g_data_offset(0);
+ if (plane[1]) {
+ plane[1] += buf.g_data_offset(1);
+ bytesused[1] = buf.g_bytesused(1) - buf.g_data_offset(1);
}
- if (m_makeSnapshot)
- makeSnapshot((unsigned char *)m_buffers[buf.index].start[0], buf.bytesused);
- if (m_saveRaw.openMode())
- m_saveRaw.write((const char *)m_buffers[buf.index].start[0], buf.bytesused);
-
- break;
-
- case methodUser:
- memset(planes, 0, sizeof(planes));
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
- if (!dqbuf_user(buf, buftype, again)) {
- error("dqbuf1");
- m_capStartAct->setChecked(false);
- return;
- }
- if (again)
- return;
- if (buf.flags & V4L2_BUF_FLAG_ERROR) {
- qbuf(buf);
- return;
- }
-#ifdef HAVE_ALSA
- alsa_thread_timestamp(&tv_alsa);
-#endif
- if (buf.flags & V4L2_BUF_FLAG_ERROR) {
- qbuf(buf);
- return;
- }
-
- if (showFrames()) {
- if (m_mustConvert)
- err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
- (unsigned char *)buf.m.userptr, buf.bytesused,
- m_capImage->bits(), m_capDestFormat.fmt.pix.sizeimage);
- if (m_mustConvert && err != -1)
- displaybuf = m_capImage->bits();
- if (!m_mustConvert) {
- displaybuf = (unsigned char *)m_buffers[buf.index].start[0];
- displaybuf2 = (unsigned char *)m_buffers[buf.index].start[1];
- if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
- displaybuf += planes[0].data_offset;
- displaybuf2 += planes[1].data_offset;
- }
+ if (showFrames() && m_mustConvert) {
+ err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
+ plane[0], bytesused[0], m_capImage->bits(),
+ m_capDestFormat.fmt.pix.sizeimage);
+ if (err != -1) {
+ plane[0] = m_capImage->bits();
+ bytesused[0] = m_capDestFormat.fmt.pix.sizeimage;
}
}
if (m_makeSnapshot)
- makeSnapshot((unsigned char *)buf.m.userptr, buf.bytesused);
+ makeSnapshot(plane[0], bytesused[0]);
if (m_saveRaw.openMode())
- m_saveRaw.write((const char *)buf.m.userptr, buf.bytesused);
+ m_saveRaw.write((const char *)plane[0], bytesused[0]);
break;
}
#ifdef HAVE_ALSA
if (alsa_thread_is_running()) {
if (tv_alsa.tv_sec || tv_alsa.tv_usec) {
- m_totalAudioLatency.tv_sec += buf.timestamp.tv_sec - tv_alsa.tv_sec;
- m_totalAudioLatency.tv_usec += buf.timestamp.tv_usec - tv_alsa.tv_usec;
+ m_totalAudioLatency.tv_sec += buf.g_timestamp().tv_sec - tv_alsa.tv_sec;
+ m_totalAudioLatency.tv_usec += buf.g_timestamp().tv_usec - tv_alsa.tv_usec;
}
status.append(QString(" Average A-V: %3 ms")
.arg((m_totalAudioLatency.tv_sec * 1000 + m_totalAudioLatency.tv_usec / 1000) / m_frame));
}
#endif
- if (displaybuf == NULL && showFrames())
+ if (plane[0] == NULL && showFrames())
status.append(" Error: Unsupported format.");
if (showFrames())
m_capture->setFrame(m_capImage->width(), m_capImage->height(),
- m_capDestFormat.fmt.pix.pixelformat, displaybuf, displaybuf2, status);
+ m_capDestFormat.g_pixelformat(), plane[0], plane[1], status);
if (m_capMethod == methodMmap || m_capMethod == methodUser) {
- if (m_buffers[buf.index].clear) {
- memset(m_buffers[buf.index].start[0], 0, m_buffers[buf.index].length[0]);
- if (V4L2_TYPE_IS_MULTIPLANAR(buf.type))
- memset(m_buffers[buf.index].start[1], 0, m_buffers[buf.index].length[1]);
- m_buffers[buf.index].clear = false;
+ if (m_clear[buf.g_index()]) {
+ memset(m_queue.g_dataptr(buf.g_index(), 0), 0, buf.g_length());
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf.g_type()))
+ memset(m_queue.g_dataptr(buf.g_index(), 1), 0, buf.g_length(1));
+ m_clear[buf.g_index()] = false;
}
qbuf(buf);
refresh();
}
-bool ApplicationWindow::startCapture(unsigned buffer_size)
-{
- startAudio();
-
- if (m_genTab->isRadio())
- return true;
-
- __u32 buftype = m_genTab->bufType();
- v4l2_requestbuffers req;
- unsigned int i;
-
- memset(&req, 0, sizeof(req));
-
- m_useGLAct->setEnabled(false);
-
- switch (m_capMethod) {
- case methodRead:
- m_snapshotAct->setEnabled(true);
- m_genTab->setHaveBuffers(true);
- /* Nothing to do. */
- return true;
-
- case methodMmap:
- if (!reqbufs_mmap(req, buftype, 3)) {
- error("Cannot capture");
- break;
- }
-
- if (req.count < 2) {
- error("Too few buffers");
- reqbufs_mmap(req, buftype);
- break;
- }
-
- m_buffers = (buffer *)calloc(req.count, sizeof(*m_buffers));
-
- if (!m_buffers) {
- error("Out of memory");
- reqbufs_mmap(req, buftype);
- break;
- }
-
- for (m_nbuffers = 0; m_nbuffers < req.count; ++m_nbuffers) {
- v4l2_plane planes[VIDEO_MAX_PLANES];
- v4l2_buffer buf;
-
- memset(&buf, 0, sizeof(buf));
-
- buf.type = buftype;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = m_nbuffers;
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
-
- if (-1 == ioctl(VIDIOC_QUERYBUF, &buf)) {
- perror("VIDIOC_QUERYBUF");
- goto error;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
- m_buffers[m_nbuffers].planes = buf.length;
- for (unsigned p = 0; p < buf.length; p++) {
- m_buffers[m_nbuffers].length[p] = planes[p].length;
- m_buffers[m_nbuffers].start[p] = mmap(planes[p].length, planes[p].m.mem_offset);
- if (MAP_FAILED == m_buffers[m_nbuffers].start[p]) {
- perror("mmap");
- goto error;
- }
- memset(m_buffers[m_nbuffers].start[p], 0,
- m_buffers[m_nbuffers].length[p]);
- }
- } else {
- m_buffers[m_nbuffers].planes = 1;
- m_buffers[m_nbuffers].length[0] = buf.length;
- m_buffers[m_nbuffers].start[0] = mmap(buf.length, buf.m.offset);
- if (MAP_FAILED == m_buffers[m_nbuffers].start[0]) {
- perror("mmap");
- goto error;
- }
- memset(m_buffers[m_nbuffers].start[0], 0,
- m_buffers[m_nbuffers].length[0]);
- }
- }
- for (i = 0; i < m_nbuffers; ++i) {
- if (!qbuf_mmap(i, buftype)) {
- perror("VIDIOC_QBUF");
- goto error;
- }
- }
- if (!streamon(buftype)) {
- perror("VIDIOC_STREAMON");
- goto error;
- }
- m_snapshotAct->setEnabled(true);
- m_genTab->setHaveBuffers(true);
- return true;
-
- case methodUser:
- if (!reqbufs_user(req, buftype, 3)) {
- error("Cannot capture");
- break;
- }
-
- if (req.count < 2) {
- error("Too few buffers");
- reqbufs_user(req, buftype);
- break;
- }
-
- m_buffers = (buffer *)calloc(req.count, sizeof(*m_buffers));
-
- if (!m_buffers) {
- error("Out of memory");
- break;
- }
-
- for (m_nbuffers = 0; m_nbuffers < req.count; ++m_nbuffers) {
- v4l2_plane planes[VIDEO_MAX_PLANES];
- v4l2_buffer buf;
-
- memset(&buf, 0, sizeof(buf));
-
- buf.type = buftype;
- buf.memory = V4L2_MEMORY_USERPTR;
- buf.index = m_nbuffers;
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
-
- if (-1 == ioctl(VIDIOC_QUERYBUF, &buf)) {
- perror("VIDIOC_QUERYBUF");
- goto error;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
- m_buffers[m_nbuffers].planes = buf.length;
- for (unsigned p = 0; p < buf.length; p++) {
- m_buffers[m_nbuffers].length[p] = planes[p].length;
- m_buffers[m_nbuffers].start[p] = calloc(1, planes[p].length);
- if (m_buffers[m_nbuffers].start[p] == NULL) {
- error("Out of memory");
- goto error;
- }
- }
- } else {
- m_buffers[m_nbuffers].planes = 1;
- m_buffers[m_nbuffers].length[0] = buffer_size;
- m_buffers[m_nbuffers].start[0] = calloc(1, buffer_size);
-
- if (!m_buffers[m_nbuffers].start[0]) {
- error("Out of memory");
- goto error;
- }
- }
- }
- for (i = 0; i < m_nbuffers; ++i)
- if (!qbuf_user(i, buftype, m_buffers[i].start, m_buffers[i].length)) {
- perror("VIDIOC_QBUF");
- goto error;
- }
- if (!streamon(buftype)) {
- perror("VIDIOC_STREAMON");
- goto error;
- }
- m_snapshotAct->setEnabled(true);
- m_genTab->setHaveBuffers(true);
- return true;
- }
-
-error:
- m_capStartAct->setChecked(false);
- m_useGLAct->setEnabled(CaptureWinGL::isSupported());
- return false;
-}
-
void ApplicationWindow::stopCapture()
{
stopAudio();
if (m_genTab->isRadio())
return;
- __u32 buftype = m_genTab->bufType();
- v4l2_requestbuffers reqbufs;
v4l2_encoder_cmd cmd;
- unsigned i;
m_capture->stop();
m_snapshotAct->setDisabled(true);
case methodRead:
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = V4L2_ENC_CMD_STOP;
- ioctl(VIDIOC_ENCODER_CMD, &cmd);
+ cv4l_ioctl(VIDIOC_ENCODER_CMD, &cmd);
break;
case methodMmap:
- if (m_buffers == NULL)
- break;
- if (!streamoff(buftype))
- perror("VIDIOC_STREAMOFF");
- for (i = 0; i < m_nbuffers; ++i)
- for (unsigned p = 0; p < m_buffers[i].planes; p++)
- if (-1 == munmap(m_buffers[i].start[p], m_buffers[i].length[p]))
- perror("munmap");
- // Free all buffers.
- reqbufs_mmap(reqbufs, buftype, 1); // videobuf workaround
- reqbufs_mmap(reqbufs, buftype, 0);
- break;
-
case methodUser:
- if (!streamoff(buftype))
- perror("VIDIOC_STREAMOFF");
- // Free all buffers.
- reqbufs_user(reqbufs, buftype, 1); // videobuf workaround
- reqbufs_user(reqbufs, buftype, 0);
- for (i = 0; i < m_nbuffers; ++i)
- for (unsigned p = 0; p < m_buffers[i].planes; p++)
- free(m_buffers[i].start[p]);
+ m_queue.free(this);
break;
}
- free(m_buffers);
- m_buffers = NULL;
+ reopen(true);
m_genTab->setHaveBuffers(false);
refresh();
}
return m_showFramesAct->isChecked();
}
-void ApplicationWindow::startOutput(unsigned)
-{
-}
-
-void ApplicationWindow::stopOutput()
-{
-}
-
void ApplicationWindow::enableScaling(bool enable)
{
if (m_capture != NULL)
unsigned colorspace = m_genTab->getColorspace();
if (colorspace == 0) {
- v4l2_format fmt;
+ cv4l_fmt fmt;
- fmt.type = m_genTab->bufType();
+ g_fmt(fmt);
// don't use the wrapped ioctl since it doesn't
// update colorspace correctly.
- ::ioctl(fd(), VIDIOC_G_FMT, &fmt);
- if (m_genTab->isPlanar())
- colorspace = fmt.fmt.pix_mp.colorspace;
- else
- colorspace = fmt.fmt.pix.colorspace;
+ ::ioctl(g_fd(), VIDIOC_G_FMT, &fmt);
+ colorspace = fmt.g_colorspace();
}
m_capture->setColorspace(colorspace);
}
void ApplicationWindow::clearBuffers()
{
- if (m_capture && m_buffers)
- for (unsigned b = 0; b < m_nbuffers; b++)
- m_buffers[b].clear = true;
+ if (m_capture)
+ for (unsigned b = 0; b < sizeof(m_clear); b++)
+ m_clear[b] = true;
}
void ApplicationWindow::startAudio()
{
if (m_genTab->isRadio()) {
if (start)
- startCapture(0);
+ startCapture();
else
stopCapture();
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;
- v4l2_pix_format_mplane &srcMPix = m_capSrcFormat.fmt.pix_mp;
- v4l2_pix_format_mplane &dstMPix = m_capDestFormat.fmt.pix_mp;
- __u32 buftype = m_genTab->bufType();
- bool isPlanar = m_genTab->isPlanar();
__u32 width, height, pixfmt;
unsigned colorspace, field;
m_capMethod = m_genTab->capMethod();
if (m_genTab->isSlicedVbi()) {
- v4l2_format fmt;
+ cv4l_fmt fmt;
v4l2_std_id std;
- g_fmt_sliced_vbi(fmt);
- g_std(std);
- fmt.fmt.sliced.service_set = (std & V4L2_STD_625_50) ?
- V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ s_type(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
+ if (g_std(std)) {
+ error("this input isn't suitable for VBI\n");
+ return;
+ }
+ if (g_fmt(fmt)) {
+ error("could not obtain an VBI format\n");
+ return;
+ }
+ fmt.fmt.sliced.service_set = (std & V4L2_STD_525_60) ?
+ V4L2_SLICED_VBI_525 : V4L2_SLICED_VBI_625;
s_fmt(fmt);
memset(&m_vbiHandle, 0, sizeof(m_vbiHandle));
m_vbiTab->slicedFormat(fmt.fmt.sliced);
m_vbiSize = fmt.fmt.sliced.io_size;
m_frameData = new unsigned char[m_vbiSize];
- if (startCapture(m_vbiSize)) {
- m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
+ if (startCapture()) {
+ m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capVbiFrame()));
}
return;
}
if (m_genTab->isVbi()) {
- v4l2_format fmt;
+ cv4l_fmt fmt;
v4l2_std_id std;
- if (!g_std(std)) {
+ s_type(V4L2_BUF_TYPE_VBI_CAPTURE);
+ if (g_std(std)) {
error("this input isn't suitable for VBI\n");
return;
}
- if (!g_fmt_vbi(fmt)) {
- error("could not obtain a VBI format\n");
+ if (g_fmt(fmt)) {
+ error("could not obtain an VBI format\n");
return;
}
if (fmt.fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
return;
}
s_fmt(fmt);
- g_std(std);
if (!vbi_prepare(&m_vbiHandle, &fmt.fmt.vbi, std)) {
error("no services possible\n");
return;
m_capture->show();
statusBar()->showMessage("No frame");
- if (startCapture(m_vbiSize)) {
- m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
+ if (startCapture()) {
+ m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capVbiFrame()));
}
return;
}
- g_fmt(buftype, m_capSrcFormat);
+ m_capSrcFormat.s_type(g_type());
+ g_fmt(m_capSrcFormat);
s_fmt(m_capSrcFormat);
- if (m_genTab->get_interval(interval))
- set_interval(buftype, interval);
+ if (!m_genTab->get_interval(interval))
+ set_interval(interval);
- if (!isPlanar)
- m_frameData = new unsigned char[srcPix.sizeimage];
- else
- m_frameData = new unsigned char[srcMPix.plane_fmt[0].sizeimage + srcMPix.plane_fmt[1].sizeimage];
+ m_frameData = new unsigned char[m_capSrcFormat.g_sizeimage(0) +
+ m_capSrcFormat.g_sizeimage(1)];
m_capDestFormat = m_capSrcFormat;
- if (isPlanar) {
- dstMPix.pixelformat = srcMPix.pixelformat;
- width = srcMPix.width;
- height = srcMPix.height;
- pixfmt = srcMPix.pixelformat;
- colorspace = srcMPix.colorspace;
- field = srcMPix.field;
- m_mustConvert = false;
- } else if (m_capture->hasNativeFormat(srcPix.pixelformat)) {
- dstPix.pixelformat = srcPix.pixelformat;
- width = srcPix.width;
- height = srcPix.height;
- pixfmt = srcPix.pixelformat;
- colorspace = srcPix.colorspace;
- field = srcPix.field;
+ if (m_capture->hasNativeFormat(m_capSrcFormat.g_pixelformat())) {
+ width = m_capSrcFormat.g_width();
+ height = m_capSrcFormat.g_height();
+ pixfmt = m_capSrcFormat.g_pixelformat();
+ colorspace = m_capSrcFormat.g_colorspace();
+ field = m_capSrcFormat.g_field();
m_mustConvert = false;
} else {
m_mustConvert = true;
- dstPix.pixelformat = V4L2_PIX_FMT_RGB24;
+ m_capDestFormat.s_pixelformat(V4L2_PIX_FMT_RGB24);
// Make sure sizeimage is large enough. This is necessary if the mplane
// plugin is in use since v4lconvert_try_format() bypasses the plugin.
- dstPix.sizeimage = dstPix.width * dstPix.height * 3;
- v4l2_format copy = m_capSrcFormat;
+ m_capDestFormat.s_sizeimage(m_capDestFormat.g_width() *
+ m_capDestFormat.g_height() * 3);
+ cv4l_fmt 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.
m_capSrcFormat = copy;
- width = dstPix.width;
- height = dstPix.height;
- pixfmt = dstPix.pixelformat;
- colorspace = dstPix.colorspace;
- field = dstPix.field;
+ width = m_capDestFormat.g_width();
+ height = m_capDestFormat.g_height();
+ pixfmt = m_capDestFormat.g_pixelformat();
+ colorspace = m_capDestFormat.g_colorspace();
+ field = m_capDestFormat.g_field();
}
// Ensure that the initial image is large enough for native 32 bit per pixel formats
m_capture->show();
statusBar()->showMessage("No frame");
- if (startCapture(srcPix.sizeimage)) {
- m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
+ if (startCapture()) {
+ m_capNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capFrame()));
}
}
m_capStartAct->setEnabled(false);
m_capStartAct->setChecked(false);
m_saveRawAct->setEnabled(false);
- if (fd() >= 0) {
+ if (g_fd() >= 0) {
if (m_capNotifier) {
delete m_capNotifier;
delete m_capImage;
delete m_frameData;
m_frameData = NULL;
v4lconvert_destroy(m_convertData);
- v4l2::close();
+ cv4l_fd::close();
delete m_capture;
m_capture = NULL;
}
#include <map>
#include <vector>
-#include "v4l2-api.h"
+// Must come before cv4l-helpers.h
+#include <libv4l2.h>
+
+#include "cv4l-helpers.h"
#include "raw2sliced.h"
#include "capture-win.h"
class CaptureWin;
-class ApplicationWindow: public QMainWindow, public v4l2
+class ApplicationWindow: public QMainWindow, cv4l_fd
{
Q_OBJECT
private:
CaptureWin *m_capture;
- bool startCapture(unsigned buffer_size);
+ bool startCapture();
void stopCapture();
- void startOutput(unsigned buffer_size);
- void stopOutput();
void newCaptureWin();
void startAudio();
void stopAudio();
- struct buffer *m_buffers;
- struct v4l2_format m_capSrcFormat;
- struct v4l2_format m_capDestFormat;
+ bool m_clear[64];
+ cv4l_fmt m_capSrcFormat;
+ cv4l_fmt m_capDestFormat;
unsigned char *m_frameData;
unsigned m_nbuffers;
struct v4lconvert_data *m_convertData;
void updateFreqChannel();
bool showFrames();
+ cv4l_queue m_queue;
+
const double m_pxw;
const int m_minWidth;
const int m_vMargin;
CONFIG += debug
# Input
-HEADERS += qv4l2.h general-tab.h v4l2-api.h capture-win.h
-SOURCES += qv4l2.cpp general-tab.cpp ctrl-tab.cpp v4l2-api.cpp capture-win.cpp
+HEADERS += qv4l2.h general-tab.h capture-win.h
+SOURCES += qv4l2.cpp general-tab.cpp ctrl-tab.cpp capture-win.cpp
LIBS += -L../../lib/libv4l2 -lv4l2 -L../../lib/libv4lconvert -lv4lconvert -lrt -L../libv4l2util -lv4l2util -ldl -ljpeg
RESOURCES += qv4l2.qrc
+++ /dev/null
-/* v4l2-api: low-level wrapper around v4l2 devices
- *
- * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <limits.h>
-#include <libv4l2.h>
-#include "v4l2-api.h"
-
-bool v4l2::open(const QString &device, bool useWrapper)
-{
- m_device = device;
- m_useWrapper = useWrapper;
- m_fd = ::open(device.toAscii(), O_RDWR | O_NONBLOCK);
- if (m_fd < 0) {
- error("Cannot open " + device);
- return false;
- }
- if (!querycap(m_capability)) {
- ::close(m_fd);
- m_fd = -1;
- error(device + " is not a V4L2 device");
- return false;
- }
-
- if (m_useWrapper) {
- int fd = ::v4l2_fd_open(m_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
-
- if (fd < 0) {
- m_useWrapper = false;
- error("Cannot use libv4l2 wrapper for " + device);
- }
- }
- return true;
-}
-
-void v4l2::close()
-{
- if (useWrapper())
- ::v4l2_close(m_fd);
- else
- ::close(m_fd);
- m_fd = -1;
-}
-
-int v4l2::ioctl(unsigned cmd, void *arg)
-{
- if (useWrapper())
- return v4l2_ioctl(m_fd, cmd, arg);
- return ::ioctl(m_fd, cmd, arg);
-}
-
-bool v4l2::ioctl(const QString &descr, unsigned cmd, void *arg)
-{
- clear();
- int err = ioctl(cmd, arg);
-
- if (err < 0) {
- QString s = strerror(errno);
- error(descr + ": " + s);
- }
- return err >= 0;
-}
-
-bool v4l2::ioctl_exists(unsigned cmd, void *arg)
-{
- int err;
-
- if (useWrapper())
- err = v4l2_ioctl(m_fd, cmd, arg);
- else
- err = ::ioctl(m_fd, cmd, arg);
- return !err || errno != ENOTTY;
-}
-
-int v4l2::read(unsigned char *p, int size)
-{
- if (useWrapper())
- return v4l2_read(m_fd, p, size);
- return ::read(m_fd, p, size);
-}
-
-void *v4l2::mmap(size_t length, int64_t offset)
-{
- if (useWrapper())
- return v4l2_mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, offset);
- return ::mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, offset);
-}
-
-int v4l2::munmap(void *start, size_t length)
-{
- if (useWrapper())
- return v4l2_munmap(start, length);
- return ::munmap(start, length);
-}
-
-void v4l2::error(const QString &error)
-{
- if (!error.isEmpty())
- fprintf(stderr, "%s\n", error.toAscii().data());
-}
-
-QString v4l2::pixfmt2s(unsigned id)
-{
- QString pixfmt;
-
- pixfmt += (char)(id & 0xff);
- pixfmt += (char)((id >> 8) & 0xff);
- pixfmt += (char)((id >> 16) & 0xff);
- pixfmt += (char)((id >> 24) & 0xff);
- return pixfmt;
-}
-
-bool v4l2::querycap(v4l2_capability &cap)
-{
- memset(&cap, 0, sizeof(cap));
- return ioctl(VIDIOC_QUERYCAP, &cap) >= 0;
-}
-
-bool v4l2::queryctrl(v4l2_queryctrl &qc)
-{
- return ioctl(VIDIOC_QUERYCTRL, &qc) >= 0;
-}
-
-bool v4l2::querymenu(v4l2_querymenu &qm)
-{
- return ioctl(VIDIOC_QUERYMENU, &qm) >= 0;
-}
-
-bool v4l2::g_tuner(v4l2_tuner &tuner, unsigned index)
-{
- memset(&tuner, 0, sizeof(tuner));
- tuner.index = index;
- if (ioctl(VIDIOC_G_TUNER, &tuner) < 0)
- return false;
- if (tuner.rangehigh > INT_MAX)
- tuner.rangehigh = INT_MAX;
- return true;
-}
-
-bool v4l2::s_tuner(v4l2_tuner &tuner)
-{
- return ioctl("Set Tuner", VIDIOC_S_TUNER, &tuner);
-}
-
-bool v4l2::g_modulator(v4l2_modulator &modulator)
-{
- memset(&modulator, 0, sizeof(modulator));
- return ioctl(VIDIOC_G_MODULATOR, &modulator) >= 0;
-}
-
-bool v4l2::s_modulator(v4l2_modulator &modulator)
-{
- return ioctl("Set Modulator", VIDIOC_S_MODULATOR, &modulator);
-}
-
-bool v4l2::g_input(int &input)
-{
- return ioctl(VIDIOC_G_INPUT, &input) >= 0;
-}
-
-bool v4l2::s_input(int input)
-{
- return ioctl("Set Input", VIDIOC_S_INPUT, &input);
-}
-
-bool v4l2::g_output(int &output)
-{
- return ioctl(VIDIOC_G_OUTPUT, &output) >= 0;
-}
-
-bool v4l2::s_output(int output)
-{
- return ioctl("Set Output", VIDIOC_S_OUTPUT, &output);
-}
-
-bool v4l2::g_audio(v4l2_audio &audio)
-{
- memset(&audio, 0, sizeof(audio));
- return ioctl(VIDIOC_G_AUDIO, &audio) >= 0;
-}
-
-bool v4l2::s_audio(int input)
-{
- v4l2_audio audio;
-
- memset(&audio, 0, sizeof(audio));
- audio.index = input;
- return ioctl("Set Audio Input", VIDIOC_S_AUDIO, &audio);
-}
-
-bool v4l2::g_audout(v4l2_audioout &audout)
-{
- memset(&audout, 0, sizeof(audout));
- return ioctl(VIDIOC_G_AUDOUT, &audout) >= 0;
-}
-
-bool v4l2::s_audout(int output)
-{
- v4l2_audioout audout;
-
- memset(&audout, 0, sizeof(audout));
- audout.index = output;
- return ioctl("Set Audio Output", VIDIOC_S_AUDOUT, &audout);
-}
-
-bool v4l2::g_std(v4l2_std_id &std)
-{
- return ioctl(VIDIOC_G_STD, &std) >= 0;
-}
-
-bool v4l2::s_std(v4l2_std_id std)
-{
- return ioctl("Set TV Standard", VIDIOC_S_STD, &std);
-}
-
-bool v4l2::query_std(v4l2_std_id &std)
-{
- return ioctl("Query TV Standard", VIDIOC_QUERYSTD, &std);
-}
-
-bool v4l2::g_dv_timings(v4l2_dv_timings &timings)
-{
- int err = ioctl(VIDIOC_G_DV_TIMINGS, &timings);
- return err >= 0;
-}
-
-bool v4l2::s_dv_timings(v4l2_dv_timings &timings)
-{
- return ioctl("Set Timings", VIDIOC_S_DV_TIMINGS, &timings);
-}
-
-bool v4l2::query_dv_timings(v4l2_dv_timings &timings)
-{
- return ioctl("Query Timings", VIDIOC_QUERY_DV_TIMINGS, &timings);
-}
-
-
-bool v4l2::g_frequency(v4l2_frequency &freq, unsigned index)
-{
- memset(&freq, 0, sizeof(freq));
- freq.tuner = index;
- freq.type = V4L2_TUNER_ANALOG_TV;
- return ioctl(VIDIOC_G_FREQUENCY, &freq) >= 0;
-}
-
-bool v4l2::s_frequency(v4l2_frequency &freq)
-{
- return ioctl("Set Frequency", VIDIOC_S_FREQUENCY, &freq);
-}
-
-bool v4l2::s_frequency(int val, bool low)
-{
- v4l2_frequency f;
-
- memset(&f, 0, sizeof(f));
- f.type = low ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f.frequency = val;
- return s_frequency(f);
-}
-
-bool v4l2::g_fmt(unsigned type, v4l2_format &fmt)
-{
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = type;
- 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::g_fmt_sliced_vbi(v4l2_format &fmt)
-{
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- return ioctl(VIDIOC_G_FMT, &fmt) >= 0;
-}
-
-bool v4l2::try_fmt(v4l2_format &fmt)
-{
- if (V4L2_TYPE_IS_MULTIPLANAR(fmt.type)) {
- fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
- fmt.fmt.pix_mp.plane_fmt[1].bytesperline = 0;
- } else {
- fmt.fmt.pix.bytesperline = 0;
- }
- return ioctl("Try Capture Format", VIDIOC_TRY_FMT, &fmt);
-}
-
-bool v4l2::s_fmt(v4l2_format &fmt)
-{
- if (V4L2_TYPE_IS_MULTIPLANAR(fmt.type)) {
- fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
- fmt.fmt.pix_mp.plane_fmt[1].bytesperline = 0;
- } else {
- fmt.fmt.pix.bytesperline = 0;
- }
- return ioctl("Set Capture Format", VIDIOC_S_FMT, &fmt);
-}
-
-bool v4l2::enum_input(v4l2_input &in, bool init, int index)
-{
- if (init) {
- memset(&in, 0, sizeof(in));
- in.index = index;
- } else {
- in.index++;
- }
- return ioctl(VIDIOC_ENUMINPUT, &in) >= 0;
-}
-
-bool v4l2::enum_output(v4l2_output &out, bool init, int index)
-{
- if (init) {
- memset(&out, 0, sizeof(out));
- out.index = index;
- } else {
- out.index++;
- }
- return ioctl(VIDIOC_ENUMOUTPUT, &out) >= 0;
-}
-
-bool v4l2::enum_audio(v4l2_audio &audio, bool init)
-{
- if (init)
- memset(&audio, 0, sizeof(audio));
- else
- audio.index++;
- return ioctl(VIDIOC_ENUMAUDIO, &audio) >= 0;
-}
-
-bool v4l2::enum_audout(v4l2_audioout &audout, bool init)
-{
- if (init)
- memset(&audout, 0, sizeof(audout));
- else
- audout.index++;
- return ioctl(VIDIOC_ENUMAUDOUT, &audout) >= 0;
-}
-
-bool v4l2::enum_std(v4l2_standard &std, bool init, int index)
-{
- if (init) {
- memset(&std, 0, sizeof(std));
- std.index = index;
- } else {
- std.index++;
- }
- return ioctl(VIDIOC_ENUMSTD, &std) >= 0;
-}
-
-bool v4l2::enum_dv_timings(v4l2_enum_dv_timings &timings, bool init, int index)
-{
- if (init) {
- memset(&timings, 0, sizeof(timings));
- timings.index = index;
- } else {
- timings.index++;
- }
- return ioctl(VIDIOC_ENUM_DV_TIMINGS, &timings) >= 0;
-}
-
-bool v4l2::enum_fmt(v4l2_fmtdesc &fmt, unsigned type, bool init, int index)
-{
- if (init) {
- memset(&fmt, 0, sizeof(fmt));
- fmt.index = index;
- } else {
- fmt.index++;
- }
- fmt.type = type;
- return ioctl(VIDIOC_ENUM_FMT, &fmt) >= 0;
-}
-
-bool v4l2::enum_framesizes(v4l2_frmsizeenum &frm, __u32 init_pixfmt, int index)
-{
- if (init_pixfmt) {
- memset(&frm, 0, sizeof(frm));
- frm.pixel_format = init_pixfmt;
- frm.index = index;
- } else {
- frm.index++;
- }
- return ioctl(VIDIOC_ENUM_FRAMESIZES, &frm) >= 0;
-}
-
-bool v4l2::enum_frameintervals(v4l2_frmivalenum &frm, __u32 init_pixfmt, __u32 w, __u32 h, int index)
-{
- if (init_pixfmt) {
- memset(&frm, 0, sizeof(frm));
- frm.pixel_format = init_pixfmt;
- frm.width = w;
- frm.height = h;
- frm.index = index;
- } else {
- frm.index++;
- }
- return ioctl(VIDIOC_ENUM_FRAMEINTERVALS, &frm) >= 0;
-}
-
-bool v4l2::reqbufs_user(v4l2_requestbuffers &reqbuf, __u32 buftype, int count)
-{
- memset(&reqbuf, 0, sizeof (reqbuf));
- reqbuf.type = buftype;
- reqbuf.memory = V4L2_MEMORY_USERPTR;
- reqbuf.count = count;
-
- return ioctl(VIDIOC_REQBUFS, &reqbuf) >= 0;
-}
-
-bool v4l2::reqbufs_mmap(v4l2_requestbuffers &reqbuf, __u32 buftype, int count)
-{
- memset(&reqbuf, 0, sizeof (reqbuf));
- reqbuf.type = buftype;
- reqbuf.memory = V4L2_MEMORY_MMAP;
- reqbuf.count = count;
-
- return ioctl(VIDIOC_REQBUFS, &reqbuf) >= 0;
-}
-
-bool v4l2::dqbuf_mmap(v4l2_buffer &buf, __u32 buftype, bool &again)
-{
- v4l2_plane *planes = buf.m.planes;
- unsigned length = buf.length;
- int res;
-
- memset(&buf, 0, sizeof(buf));
- buf.length = length;
- buf.m.planes = planes;
- 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(v4l2_buffer &buf, __u32 buftype, bool &again)
-{
- v4l2_plane *planes = buf.m.planes;
- unsigned length = buf.length;
- int res;
-
- memset(&buf, 0, sizeof(buf));
- buf.length = length;
- buf.m.planes = planes;
- buf.type = buftype;
- buf.memory = V4L2_MEMORY_USERPTR;
- res = ioctl(VIDIOC_DQBUF, &buf);
- again = res < 0 && errno == EAGAIN;
- return res >= 0 || again;
-}
-
-bool v4l2::qbuf(v4l2_buffer &buf)
-{
- return ioctl(VIDIOC_QBUF, &buf) >= 0;
-}
-
-bool v4l2::qbuf_mmap(int index, __u32 buftype)
-{
- v4l2_plane planes[VIDEO_MAX_PLANES];
- v4l2_buffer buf;
-
- memset(&buf, 0, sizeof(buf));
- buf.type = buftype;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = index;
- buf.length = 2;
- buf.m.planes = planes;
- return qbuf(buf);
-}
-
-bool v4l2::qbuf_user(int index, __u32 buftype, void *ptr[], size_t length[])
-{
- v4l2_plane planes[VIDEO_MAX_PLANES];
- v4l2_buffer buf;
-
- memset(&buf, 0, sizeof(buf));
- buf.type = buftype;
- buf.memory = V4L2_MEMORY_USERPTR;
- if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
- buf.length = 2;
- buf.m.planes = planes;
- planes[0].length = length[0];
- planes[0].m.userptr = (unsigned long)ptr[0];
- planes[1].length = length[1];
- planes[1].m.userptr = (unsigned long)ptr[1];
- } else {
- buf.m.userptr = (unsigned long)ptr[0];
- buf.length = length[0];
- }
- buf.index = index;
- return qbuf(buf);
-}
-
-bool v4l2::streamon(__u32 buftype)
-{
- return ioctl("Start Streaming", VIDIOC_STREAMON, &buftype);
-}
-
-bool v4l2::streamoff(__u32 buftype)
-{
- return ioctl("Stop Streaming", VIDIOC_STREAMOFF, &buftype);
-}
-
-bool v4l2::subscribe_event(v4l2_event_subscription &sub)
-{
- return ioctl(VIDIOC_SUBSCRIBE_EVENT, &sub);
-}
-
-bool v4l2::dqevent(v4l2_event &ev)
-{
- return ioctl(VIDIOC_DQEVENT, &ev) >= 0;
-}
-
-bool v4l2::set_interval(unsigned type, v4l2_fract interval)
-{
- v4l2_streamparm parm;
-
- parm.type = type;
- if (ioctl(VIDIOC_G_PARM, &parm) < 0)
- return false;
-
- if (!(parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
- return false;
-
- parm.parm.capture.timeperframe = interval;
-
- return ioctl("Set FPS", VIDIOC_S_PARM, &parm);
-}
-
-bool v4l2::get_interval(unsigned type, v4l2_fract &interval)
-{
- v4l2_streamparm parm;
-
- parm.type = type;
- if (ioctl(VIDIOC_G_PARM, &parm) >= 0 &&
- (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
- interval = parm.parm.capture.timeperframe;
- return true;
- }
-
- return false;
-}
-
-v4l2_fract v4l2::g_pixel_aspect(unsigned type, unsigned &width, unsigned &height)
-{
- v4l2_cropcap ratio;
- v4l2_dv_timings timings;
- v4l2_std_id std;
- static const v4l2_fract square = { 1, 1 };
- static const v4l2_fract hz50 = { 11, 12 };
- static const v4l2_fract hz60 = { 11, 10 };
-
- ratio.type = type;
- if (ioctl(VIDIOC_CROPCAP, &ratio) == 0) {
- width = ratio.defrect.width;
- height = ratio.defrect.height;
- if (ratio.pixelaspect.numerator && ratio.pixelaspect.denominator)
- return ratio.pixelaspect;
- }
-
- width = 720;
- height = 480;
- if (g_std(std)) {
- if (std & V4L2_STD_525_60)
- return hz60;
- if (std & V4L2_STD_625_50) {
- height = 576;
- return hz50;
- }
- }
-
- if (g_dv_timings(timings)) {
- width = timings.bt.width;
- height = timings.bt.height;
- if (width == 720 && height == 480)
- return hz60;
- if (width == 720 && height == 576) {
- height = 576;
- return hz50;
- }
- return square;
- }
- width = 0;
- height = 0;
- return square;
-}
-
-bool v4l2::has_crop()
-{
- v4l2_crop crop;
- v4l2_cropcap cropcap;
-
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- return ioctl_exists(VIDIOC_G_CROP, &crop) &&
- ioctl_exists(VIDIOC_S_CROP, &crop) &&
- ioctl_exists(VIDIOC_CROPCAP, &cropcap);
-}
-
-bool v4l2::input_has_crop()
-{
- v4l2_crop crop;
- v4l2_cropcap cropcap;
-
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- return ioctl(VIDIOC_G_CROP, &crop) == 0 &&
- ioctl(VIDIOC_S_CROP, &crop) == 0 &&
- ioctl(VIDIOC_CROPCAP, &cropcap) == 0 &&
- cropcap.bounds.width && cropcap.bounds.height;
-}
-
-bool v4l2::has_compose()
-{
- v4l2_selection sel;
-
- memset(&sel, 0, sizeof(sel));
- sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- sel.target = V4L2_SEL_TGT_COMPOSE;
- return ioctl_exists(VIDIOC_G_SELECTION, &sel) &&
- ioctl_exists(VIDIOC_S_SELECTION, &sel);
-}
-
-bool v4l2::input_has_compose()
-{
- v4l2_selection sel;
-
- memset(&sel, 0, sizeof(sel));
- sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- sel.target = V4L2_SEL_TGT_COMPOSE;
- return ioctl(VIDIOC_G_SELECTION, &sel) == 0 &&
- ioctl(VIDIOC_S_SELECTION, &sel) == 0;
-}
+++ /dev/null
-/* v4l2-api: low-level wrapper around v4l2 devices
- *
- * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef V4L2_API_H
-#define V4L2_API_H
-
-#include <QString>
-#include <linux/videodev2.h>
-#include <libv4lconvert.h>
-
-class v4l2
-{
-public:
- v4l2() : m_fd(-1) {}
- v4l2(v4l2 &old) :
- m_fd(old.m_fd),
- m_device(old.m_device),
- m_useWrapper(old.m_useWrapper),
- m_capability(old.m_capability)
- {}
-
- bool open(const QString &device, bool useWrapper = true);
- void close();
- int read(unsigned char *p, int size);
- int ioctl(unsigned cmd, void *arg);
- bool ioctl(const QString &descr, unsigned cmd, void *arg);
- bool ioctl_exists(unsigned cmd, void *arg);
- void *mmap(size_t length, int64_t offset);
- int munmap(void *_start, size_t length);
-
- inline int fd() const { return m_fd; }
- inline bool useWrapper() const { return m_useWrapper; }
- inline __u32 caps() const {
- if (m_capability.capabilities & V4L2_CAP_DEVICE_CAPS)
- return m_capability.device_caps;
- return m_capability.capabilities;
- }
- inline const QString &device() const { return m_device; }
- static QString pixfmt2s(unsigned pixelformat);
-
- virtual void error(const QString &text);
-
- bool querycap(v4l2_capability &cap);
- bool queryctrl(v4l2_queryctrl &qc);
- bool querymenu(v4l2_querymenu &qm);
- bool g_tuner(v4l2_tuner &tuner, unsigned index = 0);
- bool s_tuner(v4l2_tuner &tuner);
- bool g_modulator(v4l2_modulator &modulator);
- bool s_modulator(v4l2_modulator &modulator);
- bool g_input(int &input);
- bool s_input(int input);
- bool g_output(int &output);
- bool s_output(int output);
- bool g_audio(v4l2_audio &audio);
- bool s_audio(int input);
- bool g_audout(v4l2_audioout &audout);
- bool s_audout(int output);
- bool s_std(v4l2_std_id std);
- bool g_std(v4l2_std_id &std);
- bool query_std(v4l2_std_id &std);
- bool s_dv_timings(v4l2_dv_timings &timings);
- bool g_dv_timings(v4l2_dv_timings &timings);
- bool query_dv_timings(v4l2_dv_timings &timings);
- bool g_frequency(v4l2_frequency &freq, unsigned index = 0);
- bool s_frequency(v4l2_frequency &freq);
- bool s_frequency(int freq, bool low = false);
- bool g_fmt(unsigned type, v4l2_format &fmt);
- bool g_fmt_vbi(v4l2_format &fmt);
- bool g_fmt_sliced_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_output(v4l2_output &out, bool init = false, int index = 0);
- bool enum_audio(v4l2_audio &audio, bool init = false);
- bool enum_audout(v4l2_audioout &audout, bool init = false);
- bool enum_std(v4l2_standard &std, bool init = false, int index = 0);
- bool enum_dv_timings(v4l2_enum_dv_timings &timings, bool init = false, int index = 0);
- bool enum_fmt(v4l2_fmtdesc &std, unsigned type, 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(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(int index, __u32 buftype);
- bool qbuf_user(int index, __u32 buftype, void *ptr[], size_t length[]);
- bool streamon(__u32 buftype);
- bool streamoff(__u32 buftype);
- v4l2_fract g_pixel_aspect(unsigned type, unsigned &width, unsigned &height);
- bool has_crop();
- bool input_has_crop();
- bool has_compose();
- bool input_has_compose();
-
- bool subscribe_event(v4l2_event_subscription &sub);
- bool dqevent(v4l2_event &ev);
-
- bool set_interval(unsigned type, v4l2_fract interval);
- bool get_interval(unsigned type, v4l2_fract &interval);
-private:
- void clear() { error(QString()); }
-
-private:
- int m_fd;
- QString m_device;
- bool m_useWrapper; // true if using the libv4l2 wrappers
- v4l2_capability m_capability;
-};
-
-#endif
#define VBI_TAB_H
#include "qv4l2.h"
-#include "v4l2-api.h"
class QTableWidget;