From 5849910b8804f840d4b9ed485cfc8d26e6221974 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2014 17:48:15 +0200 Subject: [PATCH] qv4l2: correctly resubscribe events after a reopen. The reopen() call closes the original filehandle and at the same time any subscribed events. So resubscribe the events. In addition both the ApplicationWindow and the GeneralTab had a cv4l_fd instance with the same fd. With reopen that means that those fd's are no longer in sync. GeneralTab now has a pointer to the cv4l_fd of the ApplicationWindow, so they remain synchronized. Signed-off-by: Hans Verkuil --- utils/qv4l2/ctrl-tab.cpp | 20 +++++++--- utils/qv4l2/general-tab.cpp | 48 +++++++++++++---------- utils/qv4l2/general-tab.h | 92 ++++++++++++++++++++++++++++++++++++++++++++- utils/qv4l2/qv4l2.cpp | 7 +++- utils/qv4l2/qv4l2.h | 1 + 5 files changed, 141 insertions(+), 27 deletions(-) diff --git a/utils/qv4l2/ctrl-tab.cpp b/utils/qv4l2/ctrl-tab.cpp index a1d34e9..c264394 100644 --- a/utils/qv4l2/ctrl-tab.cpp +++ b/utils/qv4l2/ctrl-tab.cpp @@ -404,11 +404,6 @@ void ApplicationWindow::addCtrl(QGridLayout *grid, const v4l2_queryctrl &qctrl) default: return; } - struct v4l2_event_subscription sub; - memset(&sub, 0, sizeof(sub)); - sub.type = V4L2_EVENT_CTRL; - sub.id = qctrl.id; - subscribe_event(sub); m_sigMapper->setMapping(m_widgetMap[qctrl.id], qctrl.id); if (qctrl.flags & CTRL_FLAG_DISABLED) { @@ -673,6 +668,21 @@ void ApplicationWindow::updateCtrlRange(unsigned id, __s32 new_val) } } +void ApplicationWindow::subscribeCtrlEvents() +{ + for (ClassMap::iterator iter = m_classMap.begin(); iter != m_classMap.end(); ++iter) { + for (unsigned i = 0; i < m_classMap[iter->first].size(); i++) { + unsigned id = m_classMap[iter->first][i]; + struct v4l2_event_subscription sub; + + memset(&sub, 0, sizeof(sub)); + sub.type = V4L2_EVENT_CTRL; + sub.id = id; + subscribe_event(sub); + } + } +} + void ApplicationWindow::refresh(unsigned ctrl_class) { if (!m_haveExtendedUserCtrls && ctrl_class == V4L2_CTRL_CLASS_USER) { diff --git a/utils/qv4l2/general-tab.cpp b/utils/qv4l2/general-tab.cpp index 84eabf8..8b865ee 100644 --- a/utils/qv4l2/general-tab.cpp +++ b/utils/qv4l2/general-tab.cpp @@ -55,9 +55,9 @@ static QString pixfmt2s(unsigned id) return pixfmt; } -GeneralTab::GeneralTab(const QString &device, cv4l_fd *_fd, int n, QWidget *parent) : +GeneralTab::GeneralTab(const QString &device, cv4l_fd *fd, int n, QWidget *parent) : QGridLayout(parent), - cv4l_fd(_fd), + m_fd(fd), m_row(0), m_col(0), m_cols(n), @@ -128,7 +128,7 @@ GeneralTab::GeneralTab(const QString &device, cv4l_fd *_fd, int n, QWidget *pare addTitle("General Information"); addLabel("Device"); - addLabel(device + (g_direct() ? "" : " (wrapped)")); + addLabel(device + (m_fd->g_direct() ? "" : " (wrapped)")); addLabel("Driver"); addLabel((char *)m_querycap.driver); @@ -225,7 +225,7 @@ GeneralTab::GeneralTab(const QString &device, cv4l_fd *_fd, int n, QWidget *pare capture_method: addLabel("Capture Method"); m_capMethods = new QComboBox(parent); - if (g_caps() & V4L2_CAP_STREAMING) { + if (has_streaming()) { cv4l_queue q; // Yuck. The videobuf framework does not accept a reqbufs count of 0. @@ -235,23 +235,24 @@ capture_method: // 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) { + if (q.reqbufs(m_fd, 1) == 0) { m_capMethods->addItem("User pointer I/O", QVariant(methodUser)); - reopen(true); + m_fd->reopen(true); } q.init(g_type(), V4L2_MEMORY_MMAP); - if (q.reqbufs(this, 1) == 0) { + if (q.reqbufs(m_fd, 1) == 0) { m_capMethods->addItem("Memory mapped I/O", QVariant(methodMmap)); - reopen(true); + m_fd->reopen(true); } } - if (g_caps() & V4L2_CAP_READWRITE) { - m_capMethods->addItem("read()", QVariant(methodRead)); + if (has_rw()) { + if (v4l_type_is_output(g_type())) + m_capMethods->addItem("write()", QVariant(methodRead)); + else + m_capMethods->addItem("read()", QVariant(methodRead)); } addWidget(m_capMethods); - - if (!isRadio() && !isVbi() && !m_isOutput && (has_crop() || has_compose())) { addTitle("Cropping & Compose Settings"); cropSection(); @@ -271,6 +272,19 @@ done: fixWidth(); } +void GeneralTab::sourceChangeSubscribe() +{ + v4l2_input vin; + + if (!enum_input(vin, true)) { + struct v4l2_event_subscription sub = { + V4L2_EVENT_SOURCE_CHANGE, vin.index + }; + + subscribe_event(sub); + } while (!enum_input(vin)); +} + void GeneralTab::inputSection(bool needsStd, bool needsTimings, v4l2_input vin) { if (!isRadio() && !enum_input(vin, true)) { @@ -282,12 +296,6 @@ void GeneralTab::inputSection(bool needsStd, bool needsTimings, v4l2_input vin) needsStd = true; if (vin.capabilities & V4L2_IN_CAP_DV_TIMINGS) needsTimings = true; - - struct v4l2_event_subscription sub = { - V4L2_EVENT_SOURCE_CHANGE, vin.index - }; - - subscribe_event(sub); } while (!enum_input(vin)); addWidget(m_videoInput); connect(m_videoInput, SIGNAL(activated(int)), SLOT(inputChanged(int))); @@ -542,7 +550,7 @@ void GeneralTab::audioSection(v4l2_audio vaudio, v4l2_audioout vaudout) setAudioDeviceBufferSize(75); } else { v4l2_fract fract; - if (cv4l_fd::get_interval(fract)) { + if (m_fd->get_interval(fract)) { // Default values are for 30 FPS fract.numerator = 33; fract.denominator = 1000; @@ -2070,7 +2078,7 @@ void GeneralTab::updateFrameInterval() m_frameInterval->setEnabled(m_has_interval); if (m_has_interval) { m_interval = frmival.discrete; - curr_ok = !cv4l_fd::get_interval(curr); + curr_ok = !m_fd->get_interval(curr); do { m_frameInterval->addItem(QString("%1 fps") .arg((double)frmival.discrete.denominator / frmival.discrete.numerator)); diff --git a/utils/qv4l2/general-tab.h b/utils/qv4l2/general-tab.h index 48109f7..2f50d22 100644 --- a/utils/qv4l2/general-tab.h +++ b/utils/qv4l2/general-tab.h @@ -47,7 +47,7 @@ class QSpinBox; class QToolButton; class QSlider; -class GeneralTab: public QGridLayout, public cv4l_fd +class GeneralTab: public QGridLayout { Q_OBJECT @@ -73,6 +73,7 @@ public: bool isPlanar() const { return m_isPlanar; } void setHaveBuffers(bool haveBuffers); void sourceChange(const v4l2_event &ev); + void sourceChangeSubscribe(); unsigned getDisplayColorspace() const; unsigned getColorspace() const; int getWidth(); @@ -175,7 +176,96 @@ private: { g_mw->error(error); } + v4l_fd *g_v4l_fd() { return m_fd->g_v4l_fd(); } + __u32 g_type() const { return m_fd->g_type(); } + void s_type(__u32 type) { m_fd->s_type(type); } + __u32 g_selection_type() const { return m_fd->g_selection_type(); } + __u32 g_caps() const { return m_fd->g_caps(); } + + bool has_vid_cap() const { return m_fd->has_vid_cap(); } + bool has_vid_out() const { return m_fd->has_vid_out(); } + bool has_vid_m2m() const { return m_fd->has_vid_m2m(); } + bool has_vid_mplane() const { return m_fd->has_vid_mplane(); } + bool has_overlay_cap() const { return m_fd->has_overlay_cap(); } + bool has_overlay_out() const { return m_fd->has_overlay_out(); } + bool has_raw_vbi_cap() const { return m_fd->has_raw_vbi_cap(); } + bool has_sliced_vbi_cap() const { return m_fd->has_sliced_vbi_cap(); } + bool has_vbi_cap() const { return m_fd->has_vbi_cap(); } + bool has_raw_vbi_out() const { return m_fd->has_raw_vbi_out(); } + bool has_sliced_vbi_out() const { return m_fd->has_sliced_vbi_out(); } + bool has_vbi_out() const { return m_fd->has_vbi_out(); } + bool has_vbi() const { return m_fd->has_vbi(); } + bool has_radio_rx() const { return m_fd->has_radio_rx(); } + bool has_radio_tx() const { return m_fd->has_radio_tx(); } + bool has_rds_cap() const { return m_fd->has_rds_cap(); } + bool has_rds_out() const { return m_fd->has_rds_out(); } + bool has_sdr_cap() const { return m_fd->has_sdr_cap(); } + bool has_hwseek() const { return m_fd->has_hwseek(); } + bool has_rw() const { return m_fd->has_rw(); } + bool has_streaming() const { return m_fd->has_streaming(); } + bool has_ext_pix_format() const { return m_fd->has_ext_pix_format(); } + + bool g_direct() const { return m_fd->g_direct(); } + void s_direct(bool direct) { m_fd->s_direct(direct); } + int queryctrl(v4l2_queryctrl &qc) { return m_fd->queryctrl(qc); } + int querymenu(v4l2_querymenu &qm) { return m_fd->querymenu(qm); } + int g_fmt(v4l2_format &fmt, unsigned type = 0) { return m_fd->g_fmt(fmt); } + int try_fmt(v4l2_format &fmt) { return m_fd->try_fmt(fmt); } + int s_fmt(v4l2_format &fmt) { return m_fd->s_fmt(fmt); } + int g_tuner(v4l2_tuner &tuner, unsigned index = 0) { return m_fd->g_tuner(tuner, index); } + int s_tuner(v4l2_tuner &tuner) { return m_fd->g_tuner(tuner); } + int g_modulator(v4l2_modulator &modulator) { return m_fd->g_modulator(modulator); } + int s_modulator(v4l2_modulator &modulator) { return m_fd->s_modulator(modulator); } + int enum_input(v4l2_input &in, bool init = false, int index = 0) { return m_fd->enum_input(in, init, index); } + int enum_output(v4l2_output &out, bool init = false, int index = 0) { return m_fd->enum_output(out, init, index); } + int enum_audio(v4l2_audio &audio, bool init = false, int index = 0) { return m_fd->enum_audio(audio, init, index); } + int enum_audout(v4l2_audioout &audout, bool init = false, int index = 0) { return m_fd->enum_audout(audout, init, index); } + int subscribe_event(v4l2_event_subscription &sub) { return m_fd->subscribe_event(sub); } + int dqevent(v4l2_event &ev) { return m_fd->dqevent(ev); } + int g_input(int &input) { return m_fd->g_input(input); } + int s_input(int input) { return m_fd->s_input(input); } + int g_output(int &output) { return m_fd->g_output(output); } + int s_output(int output) { return m_fd->s_output(output); } + int g_audio(v4l2_audio &audio) { return m_fd->g_audio(audio); } + int s_audio(int input) { return m_fd->s_audio(input); } + int g_audout(v4l2_audioout &audout) { return m_fd->g_audout(audout); } + int s_audout(int output) { return m_fd->s_audout(output); } + int g_std(v4l2_std_id &std) { return m_fd->g_std(std); } + int s_std(v4l2_std_id std) { return m_fd->s_std(std); } + int query_std(v4l2_std_id &std) { return m_fd->query_std(std); } + int g_dv_timings(v4l2_dv_timings &timings) { return m_fd->g_dv_timings(timings); } + int s_dv_timings(v4l2_dv_timings &timings) { return m_fd->s_dv_timings(timings); } + int query_dv_timings(v4l2_dv_timings &timings) { return m_fd->query_dv_timings(timings); } + int g_frequency(v4l2_frequency &freq, unsigned index = 0) { return m_fd->g_frequency(freq, index); } + int s_frequency(v4l2_frequency &freq) { return m_fd->s_frequency(freq); } + int streamon(__u32 type = 0) { return m_fd->streamon(type); } + int streamoff(__u32 type = 0) { return m_fd->streamoff(type); } + int querybuf(v4l_buffer &buf, unsigned index) { return m_fd->querybuf(buf, index); } + int dqbuf(v4l_buffer &buf) { return m_fd->dqbuf(buf); } + int qbuf(v4l_buffer &buf) { return m_fd->qbuf(buf); } + int prepare_buf(v4l_buffer &buf) { return m_fd->prepare_buf(buf); } + int enum_std(v4l2_standard &std, bool init = false, int index = 0) { return m_fd->enum_std(std, init, index); } + int enum_dv_timings(v4l2_enum_dv_timings &timings, bool init = false, int index = 0) { return m_fd->enum_dv_timings(timings, init, index); } + int enum_fmt(v4l2_fmtdesc &fmt, bool init = false, int index = 0, unsigned type = 0) { return m_fd->enum_fmt(fmt, init, index, type); } + int enum_framesizes(v4l2_frmsizeenum &frm, __u32 init_pixfmt = 0, int index = 0) { return m_fd->enum_framesizes(frm, init_pixfmt, index); } + int enum_frameintervals(v4l2_frmivalenum &frm, __u32 init_pixfmt = 0, __u32 w = 0, __u32 h = 0, int index = 0) { return m_fd->enum_frameintervals(frm, init_pixfmt, w, h, index); } + int set_interval(v4l2_fract interval, unsigned type = 0) { return m_fd->set_interval(interval, type); } + v4l2_fract g_pixel_aspect(unsigned &width, unsigned &height, unsigned type = 0) + { + return m_fd->g_pixel_aspect(width, height, type); + } + bool has_crop() { return m_fd->has_crop(); } + bool has_compose() { return m_fd->has_compose(); } + bool input_has_crop() { return m_fd->input_has_crop(); } + bool input_has_compose() { return m_fd->input_has_compose(); } + bool ioctl_exists(int ret) + { + return ret == 0 || errno != ENOTTY; + } + + + cv4l_fd *m_fd; int m_row; int m_col; int m_cols; diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp index 7fd5753..b0e5d4f 100644 --- a/utils/qv4l2/qv4l2.cpp +++ b/utils/qv4l2/qv4l2.cpp @@ -287,6 +287,8 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen) #ifdef HAVE_QTGL m_useGLAct->setEnabled(CaptureWinGL::isSupported()); #endif + m_genTab->sourceChangeSubscribe(); + subscribeCtrlEvents(); m_ctrlNotifier = new QSocketNotifier(g_fd(), QSocketNotifier::Exception, m_tabs); connect(m_ctrlNotifier, SIGNAL(activated(int)), this, SLOT(ctrlEvent())); } @@ -474,6 +476,8 @@ bool ApplicationWindow::startCapture() m_queue.free(this); reopen(true); + m_genTab->sourceChangeSubscribe(); + subscribeCtrlEvents(); m_capStartAct->setChecked(false); #ifdef HAVE_QTGL m_useGLAct->setEnabled(CaptureWinGL::isSupported()); @@ -739,6 +743,8 @@ void ApplicationWindow::stopCapture() break; } reopen(true); + m_genTab->sourceChangeSubscribe(); + subscribeCtrlEvents(); m_genTab->setHaveBuffers(false); refresh(); } @@ -757,7 +763,6 @@ bool ApplicationWindow::showFrames() void ApplicationWindow::traceIoctls(bool enable) { s_trace(enable); - m_genTab->s_trace(enable); } void ApplicationWindow::enableScaling(bool enable) diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h index dcc7b03..7ebc887 100644 --- a/utils/qv4l2/qv4l2.h +++ b/utils/qv4l2/qv4l2.h @@ -174,6 +174,7 @@ private: void addCtrl(QGridLayout *grid, const struct v4l2_queryctrl &qctrl); void updateCtrl(unsigned id); void updateCtrlRange(unsigned id, __s32 val); + void subscribeCtrlEvents(); void refresh(unsigned ctrl_class); void refresh(); void makeSnapshot(unsigned char *buf, unsigned size); -- 2.7.4