[Kwintv] Re: V4L Plugin - new success

Koos Vriezen koos.vriezen at xs4all.nl
Mon Dec 15 19:27:58 CET 2003


On Mon, Dec 15, 2003 at 12:06:15AM +0100, Koos Vriezen wrote:
> Dirk wrote:
> > Could we use QThread::terminate()? Yes, it's not very clean, but we now the 
> > grabber thread is not holding the qApp lock since we are in the event loop, 
> > and we don't care about the thread holding the devMutex since we won't be 
> > using it any more. To be sure, we could also acquire the devMutex before 
> > killing the thread. Find attached a patch for it. What do you think, Koos?
> 
> Makes sense to acquire the devMutex so it's not grabbing. Reading the man page
> of pthread_cancel, it doesn't mention pthread_mutex_lock as a cancellation point,
> so I don't know. Sound like a hack too :-)
> 
> The only reason for my hack was closing qtvision. So if we are in stopVideo and
> we have the devMutex lock, then we know the thread is either trying to get the 
> devMutex or qApp lock. Now if we add the stop condition check inside these
> locks and let the thread destroy itself outside the while loop (like qtvision4.diff)
> With the addition to sleep for a second or so after qApp->exec() returns and
> before qApp is destroyed and of course V4LGrabber should own the devMutex.
> (now I realize what qtvision4.diff was missing).

Ok, here it is based on qtvision4.diff. Also removed the ring buffer as it
makes no sense anymore afaics.
Note the changes for main(), it's necessary for V4LGrabber do obtain the lock
and exit the run() method (although the destructor will not be called of course),
otherwise it will try to obtain a lock from qApp that's destroyed already.

> 
> Koos
-------------- next part --------------
Index: qtvision/plugins/video/v4l/qtvision_v4l.h
===================================================================
RCS file: /home/kde/kdenonbeta/kwintv3/qtvision/plugins/video/v4l/qtvision_v4l.h,v
retrieving revision 1.24
diff -u -3 -p -r1.24 qtvision_v4l.h
--- qtvision/plugins/video/v4l/qtvision_v4l.h	13 Dec 2003 13:50:03 -0000	1.24
+++ qtvision/plugins/video/v4l/qtvision_v4l.h	15 Dec 2003 18:12:29 -0000
@@ -130,7 +130,6 @@ private:
     V4LDev *dev;
     bool _useOverlay;
     V4LGrabber *g;
-    QMutex _devMtx;
     QMap<QString,QString> _devNames;
     bool _probed;
     QVideoStream *_vs;
Index: qtvision/plugins/video/v4l/qtvision_v4l.cpp
===================================================================
RCS file: /home/kde/kdenonbeta/kwintv3/qtvision/plugins/video/v4l/qtvision_v4l.cpp,v
retrieving revision 1.65
diff -u -3 -p -r1.65 qtvision_v4l.cpp
--- qtvision/plugins/video/v4l/qtvision_v4l.cpp	14 Dec 2003 21:30:57 -0000	1.65
+++ qtvision/plugins/video/v4l/qtvision_v4l.cpp	15 Dec 2003 18:12:29 -0000
@@ -94,33 +94,40 @@ public:
 };
 
 
-class V4LGrabber : public QThread {
+class V4LGrabber : public QObject, public QThread {
 public:
-	V4LGrabber(QObject *owner, V4LDev *dev, QMutex& devMtx, int gsn);
+	V4LGrabber(QObject *owner, V4LDev *dev, int gsn);
 	virtual ~V4LGrabber();
         virtual void run();
 	void stop() { _stopSem.tryAccess(1); }
+        QMutex & mutex() { return _devMtx; }
 
 private:
 	QObject *_owner;
 	V4LDev *_d;
 	QSemaphore _stopSem;
-	QMutex& _devMtx;
-	V4LImage _buf[32];  // ring buffer of images
+	QMutex _devMtx;
+	V4LImage _image;
 	int _errors;
         int _gsn;
 };
 
-V4LGrabber::V4LGrabber(QObject *owner, V4LDev *dev, QMutex& devMtx, int gsn) 
-: _owner(owner), _d(dev), _stopSem(1), _devMtx(devMtx), _errors(0), _gsn(gsn)
+struct V4LGrabberLocker {
+    V4LGrabberLocker(V4LGrabber * g) : _g(g) { if (_g) _g->mutex().lock(); }
+    ~V4LGrabberLocker() { if (_g) _g->mutex().unlock(); }
+    V4LGrabber * _g;
+};
+
+V4LGrabber::V4LGrabber(QObject *owner, V4LDev *dev, int gsn) 
+: _owner(owner), _d(dev), _stopSem(1), _devMtx(true),_errors(0), _gsn(gsn)
 {
 }
 
 V4LGrabber::~V4LGrabber() {
+    //kdDebug() << "V4LGrabber::~V4LGrabber" << endl;
 }
 
 void V4LGrabber::run() {
-int bl = 0;  // buffer location
 int skip = 10;   // number of frames to drop at startup (for sync purposes)
 _errors = 0;
 	if (!_d)
@@ -135,9 +142,13 @@ _errors = 0;
 	
 	while (_stopSem.available() != 0) {
 		_devMtx.lock();
+                if (_stopSem.available() == 0) {
+                    _devMtx.unlock();
+                    break;
+                }
 		//struct timeval tv, tv2;
 		//gettimeofday(&tv, 0);
-		int rc = _d->grab(&_buf[bl], false);
+		int rc = _d->grab(&_image, false);
 		/*gettimeofday(&tv2, 0);
 		struct timeval tv3;
 		tv3.tv_sec = tv2.tv_sec - tv.tv_sec;
@@ -157,12 +168,9 @@ _errors = 0;
                             qApp->unlock();
                             break;
                         }
-                        BLTEvent event(BLTEvent::BLTImage,_buf[bl],_gsn);
+                        BLTEvent event(BLTEvent::BLTImage,_image,_gsn);
                         QApplication::sendEvent(_owner, &event);
                         qApp->unlock();
-                        if (bl == 31)
-				bl = 0;
-			else bl++;
 			_errors = 0;
 		} else if (++_errors < 100) {
 			continue;
@@ -175,13 +183,12 @@ _errors = 0;
 			break;
 		}
 	}
+        deleteLater();
 }
 
-
 QtVisionV4L::QtVisionV4L(QtVision *qtv, QWidget *parent, const char *name)
 : QVSourcePlugin(qtv, "v4l", parent, name), _w(parent), 
-	_dtReg(new KDWidget), _winReg(parent), dev(0), 
-	_devMtx(true), _gsn(0)
+	_dtReg(new KDWidget), _winReg(parent), dev(0), _gsn(0)
 {
     g = 0;
     _probed = false;
@@ -236,56 +243,56 @@ QtVisionV4L::~QtVisionV4L()
 
 bool QtVisionV4L::isTuner()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->isTuner() : false;
 }
 
 
 int QtVisionV4L::brightness()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->brightness() : -1;
 }
 
 
 QColor QtVisionV4L::colourKey()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->colourKey() : QColor();
 }
 
 
 int QtVisionV4L::colour()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->colour() : -1;
 }
 
 
 int QtVisionV4L::hue()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->hue() : -1;
 }
 
 
 int QtVisionV4L::contrast()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->contrast() : -1;
 }
 
 
 int QtVisionV4L::whiteness()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->contrast() : -1;
 }
 
 
 int QtVisionV4L::signal()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     return dev ? dev->signal() : -1;
 }
 
@@ -293,7 +300,7 @@ QMutexLocker l(&_devMtx);
 /* ARGH, this doesn't work on my card.  It always returns 0! */
 bool QtVisionV4L::muted()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if (dev)
         return dev->audioEnabled();
     return false;
@@ -331,7 +338,7 @@ int QtVisionV4L::setDevice( const QStrin
 
 int QtVisionV4L::setSource( const QString &src )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return -1;
     
@@ -343,7 +350,7 @@ QMutexLocker l(&_devMtx);
 
 int QtVisionV4L::setEncoding( const QString &encoding )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
         return -1;
 
@@ -355,7 +362,7 @@ QMutexLocker l(&_devMtx);
 
 int QtVisionV4L::frequency()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if (dev && dev->isTuner())
         return 125 * static_cast<V4LTuner*>(dev)->freq() / 2;
     return -1;
@@ -364,7 +371,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setFrequency( int freq )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev || !dev->isTuner() )
 	return;
     static_cast<V4LTuner*>(dev)->setFreq( freq * 2 / 125);
@@ -372,7 +379,7 @@ QMutexLocker l(&_devMtx);
 
 const QStringList& QtVisionV4L::broadcastedAudioModes()
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     static QStringList empty;
 
     if ( !dev )
@@ -399,7 +406,7 @@ const QString& QtVisionV4L::defaultAudio
 
 int QtVisionV4L::setAudioMode( const QString& audioMode )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return -1;
 
@@ -408,7 +415,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setMuted( bool muted )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
 
@@ -421,7 +428,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setBrightness(int val)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
     dev->setBrightness( val );
@@ -430,7 +437,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setColour(int val)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
     dev->setColour( val );
@@ -439,7 +446,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setHue(int val)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
     dev->setHue( val );
@@ -447,7 +454,7 @@ QMutexLocker l(&_devMtx);
 
 
 void QtVisionV4L::setContrast(int val) {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
     dev->setContrast( val );
@@ -456,7 +463,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::setWhiteness(int val)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if ( !dev )
 	return;
     dev->setWhiteness( val );
@@ -465,7 +472,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::viewMoved(int x, int y)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
 //kdDebug() << "View moved!" << endl;
     if (dev->overlayOn()) {
         int scn = QApplication::desktop()->screenNumber(_w->mapToGlobal(_w->geometry().center()));
@@ -483,7 +490,7 @@ QMutexLocker l(&_devMtx);
 
 void QtVisionV4L::viewResized(int w, int h)
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if (dev)
         dev->setImageSize(w, h);
 
@@ -598,7 +605,7 @@ int rc = 0;
         connect(_clipper, SIGNAL(updateClipping()), this, SLOT(updateClipping()));
         rc = dev->startCapture(qp.x(), qp.y());
     } else {
-        g = new V4LGrabber(this, dev, _devMtx, ++_gsn);
+        g = new V4LGrabber(this, dev, ++_gsn);
         g->start();
         _vs->setSize(_w->size());
         _doRefresh = true;
@@ -618,6 +625,7 @@ return rc;
 
 int QtVisionV4L::stopVideo()
 {
+V4LGrabberLocker l(g);
     if (!_capturing)
         return -1;
 
@@ -625,13 +633,8 @@ int QtVisionV4L::stopVideo()
 
     if (g) {
         g->stop();
-	V4LGrabber *t = g;
-	qApp->unlock(); // unbelievable hack
-        g->wait();
-	qApp->lock();
 	g = 0;
-        delete t;
-	_w->erase();
+        _w->erase();
     } else {  // overlay
         dev->stopCapture();
         delete _clipper;
@@ -653,7 +656,7 @@ int QtVisionV4L::setVideoDesktop(bool on
     if (!dev)
         return -1;
 
-    QMutexLocker l(&_devMtx);
+    V4LGrabberLocker l(g);
     if (on) {
         _wReg = _vs->width();
         _hReg = _vs->height();
@@ -698,7 +701,7 @@ bool QtVisionV4L::canGrabStill() const
 
 bool QtVisionV4L::grabStill( QPixmap *pix )
 {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
     if (dev && dev->canGrab()) {
         V4LImage im;
         int fmt = dev->inputFormat();
@@ -726,7 +729,7 @@ QMutexLocker l(&_devMtx);
 
 
 void QtVisionV4L::updateClipping() {
-QMutexLocker l(&_devMtx);
+V4LGrabberLocker l(g);
 Display *dpy = qt_xdisplay();
 Window win = _w->winId();
 Window root;
Index: qtvision/clients/main.cpp
===================================================================
RCS file: /home/kde/kdenonbeta/kwintv3/qtvision/clients/main.cpp,v
retrieving revision 1.12
diff -u -3 -p -r1.12 main.cpp
--- qtvision/clients/main.cpp	14 Dec 2003 19:04:24 -0000	1.12
+++ qtvision/clients/main.cpp	15 Dec 2003 18:12:29 -0000
@@ -54,6 +54,8 @@ int main(int argc, char **argv) {
     a.setMainWidget( &mw );
     mw.show();
 
-    return a.exec();
+    int retval = a.exec();
+    usleep(250000);
+    return retval;
 }
 


More information about the kwintv mailing list