src/qvcameras/qvmplayercamera.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <fcntl.h>
00030 #include <stdio.h>
00031 
00032 #include <QApplication>
00033 #include <QDebug>
00034 #include <QObject>
00035 #include <QStringList>
00036 #include <QRegExp>
00037 #include <QMutex>
00038 
00039 #include <qvcore/qvworker.h>
00040 #include <qvcameras/qvmplayercamera.h>
00041 
00042 /******************* Auxiliary QVCheckOKMPlayerCamera Class *******************/
00043 QVCheckOKMplayerCamera::QVCheckOKMplayerCamera(QFile & fifo_file,int max_time_ms_to_wait_for_open) : QThread(), _fifo_file(fifo_file), _max_time_ms_to_wait_for_open(max_time_ms_to_wait_for_open)
00044         {
00045         qDebug() << "QVCheckOKMplayerCamera::QVCheckOKMplayerCamera()";
00046         qDebug() << "QVCheckOKMplayerCamera::QVCheckOKMplayerCamera() <- return";
00047         }
00048 
00049 QVCheckOKMplayerCamera::~QVCheckOKMplayerCamera()
00050         {
00051         qDebug() << "QVCheckOKMplayerCamera::~QVCheckOKMplayerCamera()";
00052         quit();
00053         wait();
00054         qDebug() << "QVCheckOKMplayerCamera::~QVCheckOKMplayerCamera: thread finished";
00055         qDebug() << "QVCheckOKMplayerCamera::~QVCheckOKMplayerCamera() <- return";
00056         }
00057 
00058 void QVCheckOKMplayerCamera::run()
00059         {
00060         qDebug() << "QVCheckOKMplayerCamera::run()";
00061         QTimer::singleShot(_max_time_ms_to_wait_for_open, this, SLOT(writeErrorInFifo()));
00062         qDebug() << "QVCheckOKMplayerCamera::run() <- entering event loop";
00063         exec();
00064         qDebug() << "QVCheckOKMplayerCamera::run() <- back from event loop";
00065         qDebug() << "QVCheckOKMplayerCamera::run() <- return";
00066         }
00067 
00068 
00069 void QVCheckOKMplayerCamera::writeErrorInFifo()
00070         {
00071         qDebug() << "QVCheckOKMplayerCamera::writeErrorInFifo()";
00072         _fifo_file.write("MPLAYER ERROR\n"); 
00073         qDebug() << "QVCheckOKMplayerCamera::writeErrorInFifo() -> return";
00074         };
00075 
00076 /********************* Auxiliary QVCameraThread Class *************************/
00077 //QVCameraThread::QVCameraThread(): QThread(), objectList(), slotList(), timer(NULL)
00078 QVCameraThread::QVCameraThread(QObject *object,char *slot): QThread(), _object(object), _slot(slot)
00079         {
00080         qDebug() << "QVCameraThread::QVCameraThread()";
00081         _object->moveToThread(this);
00082         qDebug() << "QVCameraThread::QVCameraThread(): object moved to thread";
00083         qDebug() << "QVCameraThread::QVCameraThread() <- return";
00084         }
00085 
00086 QVCameraThread::~QVCameraThread()
00087         {
00088         qDebug() << "QVCameraThread::~QVCameraThread()";
00089         disconnect();
00090         quit();
00091         qDebug() << "QVCameraThread::~QVCameraThread(): sent quit to thread";
00092         wait();
00093         qDebug() << "QVCameraThread::~QVCameraThread(): thread finished";
00094         qDebug() << "QVCameraThread::~QVCameraThread() <- return";
00095         }
00096 
00097 void QVCameraThread::run()
00098         {
00099         qDebug() << "QVCameraThread::run()";
00100         QTimer *timer = new QTimer();
00101         timer->start(0);
00102         connect(timer, SIGNAL(timeout()),_object,_slot);
00103         qDebug() << "QVCameraThread::run(): timer created, started and connected";
00104         qDebug() << "QVCameraThread::run(): entering event processing loop";
00105         exec();
00106         qDebug() << "QVCameraThread::run(): back from event processing loop";
00107         delete timer;
00108         qDebug() << "QVCameraThread::run(): timer deleted";
00109         qDebug() << "QVCameraThread::run() <- return";
00110         }
00111 
00112 /********************* Auxiliary QVMPlayerIOProcessor class *******************/
00113 QVMPlayerIOProcessor::QVMPlayerIOProcessor(QProcess * mplayer): QObject(), command_queue(), command_queue_mutex()
00114         {
00115         qDebug() << "QVMPlayerIOProcessor::QVMPlayerIOProcessor()";
00116         rows = cols = 0;
00117         fps = time_length = time_pos = 0;
00118         speed = 1;
00119         this->mplayer = mplayer;
00120         mplayer->waitForReadyRead();
00121         qDebug() << "QVMPlayerIOProcessor::QVMPlayerIOProcessor() <- return";
00122         }
00123 
00124 QVMPlayerIOProcessor::~QVMPlayerIOProcessor()
00125         {
00126         qDebug() << "QVMPlayerIOProcessor::~QVMPlayerIOProcessor()";
00127         qDebug() << "QVMPlayerIOProcessor::~QVMPlayerIOProcessor() <- return";
00128         }
00129 
00130 void QVMPlayerIOProcessor::queueCommandToMPlayer(const QString &com_str, bool ifEmpty)
00131         {
00132         qDebug() << "QVMPlayerIOProcessor::queueCommand("<< com_str <<")";
00133         qDebug() << "QVMPlayerIOProcessor::queueCommand(): command_queue.size() = "
00134                 << command_queue.size();
00135         command_queue_mutex.lock();
00136         if(!ifEmpty || command_queue.size()==0)
00137                 command_queue << com_str + '\n';
00138         command_queue_mutex.unlock();
00139         qDebug() << "QVMPlayerIOProcessor::queueCommand() <- return";
00140         }
00141 
00142 void QVMPlayerIOProcessor::sendCommandToMPlayer()
00143         {
00144         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer()";
00145         command_queue_mutex.lock();
00146         if (command_queue.size() > 0)
00147                 {
00148                 qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer(): sending command:" << command_queue.head();
00149                 mplayer->write(qPrintable(command_queue.dequeue()));
00150                 }
00151         command_queue_mutex.unlock();
00152         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer(): wait for bytes written";
00153         // BUG: In Windows this hangs?
00154         #ifdef unix
00155         mplayer->waitForBytesWritten();
00156         #endif
00157         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer() <- return";
00158         }
00159 
00160 int QVMPlayerIOProcessor::interpretMPlayerOutput()
00161         {
00162         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput()";
00163         int length = -1;
00164         char buf[1024];
00165 
00166         length = mplayer->readLine(buf, sizeof(buf));
00167 
00168         if (length == -1)
00169                 qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): length == -1";
00170         else    {
00171                 QString str(buf);
00172                 QStringList variables = str.simplified().split("=");
00173                 QStringList palabras = str.simplified().split(" ");
00174 
00175                 if(variables[0] == "ANS_speed")
00176                         {
00177                         speed = variables[1].toDouble();
00178                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating speed =" << speed;
00179                         }
00180                 else if(variables[0] == "ANS_LENGTH")
00181                         {
00182                         time_length = variables[1].toDouble();
00183                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating time_length =" << time_length;
00184                         }
00185                 else if(variables[0] == "ANS_TIME_POSITION")
00186                         {
00187                         time_pos = variables[1].toDouble();
00188                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating time_pos =" << time_pos;
00189                         }
00190                 else if (palabras[0] == "VIDEO:")
00191                         {
00192                         // ya tenemos las especificaciones de fps
00193                         for (int i = 0; i < palabras.size(); ++i)
00194                                 if (palabras[i] == "fps")
00195                                         fps = palabras[i-1].toDouble();
00196 
00197                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating fps" << fps;
00198                         }
00199                 else if (palabras[0] == "VO:")
00200                         {
00201                         // ya tenemos las especificaciones del video y dimensiones
00202                         QStringList dimensiones = palabras[2].split("x");
00203                         cols = dimensiones[0].toInt();
00204                         rows = dimensiones[1].toInt();
00205                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating cols" << cols;
00206                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating rows" << rows;
00207                         }
00208                 else
00209                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): uninterpreted mplayer output:" << str;
00210                 }
00211         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput() <- return" << length;
00212         return length;
00213         }
00214 
00215 /******************* Auxiliary QVMPlayerFrameGrabber Class ********************/
00216 QVMPlayerFrameGrabber::QVMPlayerFrameGrabber(QVMPlayerIOProcessor *mplayerIOProcessor, QFile *fifoInput, uInt rows, uInt cols, bool isRGB, bool realTime): QObject()
00217         {
00218         qDebug() << "QVMPlayerFrameGrabber::QVMPlayerFrameGrabber(fifoInput," << mplayerIOProcessor->rows << "," << mplayerIOProcessor->cols << "," << isRGB << "," << realTime <<")";
00219         
00220         this->mplayerIOProcessor = mplayerIOProcessor;
00221         this->fifoInput = fifoInput;
00222         this->realTime = realTime;
00223         this->isYUV = not isRGB;
00224         this->finished = false;
00225         this->frames_read = 0;
00226 
00227         debug_in_memcpy = debug_in_updateSlot = false;
00228 
00229         if(isYUV)
00230                 {
00231                 imgY = QVImage<uChar>(cols, rows, cols);
00232                 img_auxY = QVImage<uChar>(cols, rows, cols);
00233                 img_auxU = QVImage<uChar>(cols/2, rows/2, cols/2);
00234                 img_auxV = QVImage<uChar>(cols/2, rows/2, cols/2);
00235                 // ...a YUV420 rows x cols image:
00236                 buf_size = rows*cols + rows*cols/4 + rows*cols/4;
00237                 }
00238         else    {
00239                 imgRGB = QVImage<uChar,3>(cols, rows, 3*cols);
00240                 img_auxRGB = QVImage<uChar,3>(cols, rows, 3*cols);
00241                 // ...or a RGB rows x cols image:
00242                 buf_size = 3*rows*cols;
00243                 }
00244 
00245         if (realTime)
00246                 {
00247                 qvcamerathread = new QVCameraThread(this,SLOT(updateSlot()));
00248                 qvcamerathread->start(QThread::NormalPriority);
00249                 }
00250 
00251         qDebug() << "QVMPlayerFrameGrabber::QVMPlayerFrameGrabber() <- return";
00252         };
00253 
00254 QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber()
00255         {
00256         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber()";
00257         finished = true;
00258         if (realTime) delete qvcamerathread;
00259         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber(): thread deleted.";
00260         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber() <- return";
00261         }
00262 
00263 void QVMPlayerFrameGrabber::getNewFrame(QVImage<uChar,3> &img)
00264         {
00265         readToBuffer(img.getWriteData(), buf_size);
00266         }
00267 
00268 void QVMPlayerFrameGrabber::getNewFrame(QVImage<uChar> &imgY, QVImage<uChar> &imgU, QVImage<uChar> &imgV)
00269         {
00270         qDebug() << "QVMPlayerFrameGrabber::getNewFrame(): reading YUV header";
00271         char buf[1024];
00272         fifoInput->readLine(buf, sizeof(buf));
00273         readToBuffer(imgY.getWriteData(), 2*buf_size/3);
00274         readToBuffer(imgU.getWriteData(), buf_size/6);
00275         readToBuffer(imgV.getWriteData(), buf_size/6);
00276         qDebug() << "QVMPlayerFrameGrabber::getNewFrame() <- return";
00277         }
00278 
00279 void QVMPlayerFrameGrabber::updateSlot()
00280         {
00281         qDebug() << "QVMPlayerFrameGrabber::updateSlot()";
00282 
00283         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): sent command to mplayer: get_time_pos";
00284         mplayerIOProcessor->queueCommandToMPlayer("pausing_keep get_time_pos\n",true);
00285 
00286         // Avoid QSocketNotifier annoying message, by deferring call:
00287         emit sendCommandSignal(); // NOT mplayerIOProcessor->sendCommandToMPlayer();
00288 
00289         // New frame read:
00290         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): reading frame";
00291         QVImage<uChar, 1> tempY;
00292         QVImage<uChar, 1> tempU;
00293         QVImage<uChar, 1> tempV;
00294         QVImage<uChar, 3> tempRGB;
00295 
00296         // We always read in temporal images, that are later safely copied:
00297         // There is no copy overhead because QVImage uses QSharedData (reference
00298         // counting).
00299         if (isYUV)
00300                 getNewFrame(tempY = img_auxY, tempU = img_auxU, tempV = img_auxV);
00301         else    
00302                 getNewFrame(tempRGB = img_auxRGB);
00303 
00304         // If in real time, we lock, to avoid collision with the thread that is
00305         // grabbing from the camera:
00306         if(realTime)
00307                 {
00308                 mutex.lock();
00309                 debug_in_updateSlot = true;
00310                 if (debug_in_memcpy)
00311                         {
00312                         std::cerr << "(BUG1) entered frameUpdate while memcpying!";
00313                         exit(0);
00314                         }
00315                 }
00316 
00317         if (isYUV)
00318                 {
00319                 img_auxY = tempY;
00320                 img_auxU = tempU;
00321                 img_auxV = tempV;
00322                 }
00323         else
00324                 img_auxRGB = tempRGB;
00325 
00326         // Unlock (if in real time):
00327         if(realTime)
00328                 {
00329                 if (debug_in_memcpy) {
00330                         std::cerr << "(BUG2) entered frameUpdate while memcpying!";
00331                         exit(0);
00332                 }
00333                 debug_in_updateSlot = false;
00334                 condition.wakeAll(); // Wake possible waiting grabs.
00335                 mutex.unlock();
00336                 }
00337 
00338         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): finished" << finished;
00339         frames_read++;
00340         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): frames read" << frames_read;
00341 
00342         mplayerIOProcessor->interpretMPlayerOutput();
00343 
00344         qDebug() << "QVMPlayerFrameGrabber::updateSlot() <- return";
00345 
00346         emit newReadFrameGrabber();
00347         }
00348 
00349 void QVMPlayerFrameGrabber::updateFrameBuffer()
00350         {
00351         qDebug() << "QVMPlayerFrameGrabber::updateFrameBuffer()";
00352 
00353         // Here we come from a grab, so we always lock (if in real time, it is 
00354         // obviously needed, but also if not in real time, to make non-real-cameras
00355         // grabbing also thread-safe (won't be used normally, but who knows...
00356         // maybe the programmer wish to read different frames from different
00357         // threads, without discarding any frame as could happen with real time
00358         // cameras).
00359         mutex.lock();
00360         if (debug_in_updateSlot) 
00361                 {
00362                 std::cerr << "(BUG3) entered memcpy while frameUpdating!";
00363                 exit(0);
00364                 }
00365 
00366         if(realTime)
00367                 condition.wait(&mutex); // If in real time, wait for next fresh frame.
00368         debug_in_memcpy = true;
00369 
00370         // If in real time, updateSlot is asynchronously called by a dedicated
00371         // thread, otherwise we have to call it explicitly.
00372         if(not realTime)
00373                 updateSlot();
00374 
00375         if (isYUV)
00376                 {
00377                 imgY = img_auxY;
00378                 imgU = img_auxU;
00379                 imgV = img_auxV;
00380                 }
00381         else
00382                 imgRGB = img_auxRGB;
00383 
00384         if (debug_in_updateSlot) 
00385                 {
00386                 std::cerr << "(BUG4) entered memcpy while frameUpdating!";
00387                 exit(0);
00388                 }
00389         debug_in_memcpy = false;
00390         mutex.unlock();
00391 
00392         qDebug() << "QVMPlayerFrameGrabber::updateFrameBuffer() <- return";
00393         }
00394 
00395 void QVMPlayerFrameGrabber::getQVImageYUV(QVImage<uChar> &imgY, QVImage<uChar> &imgU, QVImage<uChar> &imgV) const
00396         {
00397         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV()";
00398         imgY = this->imgY;
00399         imgU = this->imgU;
00400         imgV = this->imgV;
00401         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV() <- return";
00402         }
00403 
00404 void QVMPlayerFrameGrabber::getQVImageGray(QVImage<uChar> &imgGray) const
00405         {
00406         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV()";
00407         imgGray = imgY;
00408         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV() <- return";
00409         }
00410 
00411 void QVMPlayerFrameGrabber::getQVImageRGB(QVImage<uChar,3> &img) const
00412         {
00413         qDebug() << "QVMPlayerFrameGrabber::getQVImageRGB()";
00414         img = imgRGB;
00415         qDebug() << "QVMPlayerFrameGrabber::getQVImageRGB() <- return";
00416         }
00417 
00418 void QVMPlayerFrameGrabber::readToBuffer(uChar *buf_img_aux, uInt buf_size)
00419         {
00420         uInt totbytes = 0;
00421         while (totbytes != buf_size and not finished)
00422                 {
00423                 int nbytes = fifoInput->read((char *)(buf_img_aux+totbytes), buf_size-totbytes);
00424 
00425                 totbytes += nbytes;
00426                 qDebug() << "QVMPlayerFrameGrabber::readNewFrame(): read" << nbytes << "bytes";
00427 
00428                 if(nbytes == 0)
00429                         {
00430                         finished = TRUE;
00431                         qDebug() << "QVMPlayerFrameGrabber::readNewFrame(): read 0 bytes, finishing" << finished;
00432                         break;
00433                         }
00434 
00435                 if(nbytes == -1)
00436                         {
00437                         // BUG: problem in Windows, suddenly pipe can not be read ?!!?
00438                         // errorString() -> "Device did not accept the command."
00439                         finished = TRUE;
00440                         qDebug() << "QVMPlayerFrameGrabber::readNewFrame(): error -" << fifoInput->errorString();
00441                         break;
00442                         }                       
00443                 }
00444         }
00445 
00446 /***************************** QVMPlayerCamera Class **************************/
00447 QVMPlayerCamera::QVMPlayerCamera(QString name):QVCamera(name), open_options(Default)
00448         {
00449         qDebug() << "QVMPlayerCamera::QVMPlayerCamera()";
00450         frames_grabbed = 0;
00451         rgbMode = false;
00452         setStatus(Closed);
00453         live_camera = FALSE;
00454 
00455         // Properties (to allow reading from argc and argv):
00456         addProperty<int>("Rows", inputFlag, 0, "Rows to open the camera");
00457         addProperty<int>("Cols", inputFlag, 0, "Columns to open the camera");
00458         addProperty<bool>("RealTime", inputFlag, FALSE,"If the camera should be opened in real time mode");
00459         addProperty<bool>("Deinterlaced", inputFlag, FALSE,"If the camera should be opened in deinterlaced mode");
00460         addProperty<bool>("NoLoop", inputFlag, FALSE,"If the camera should be opened in no loop mode");
00461         addProperty<bool>("RGBMEncoder", inputFlag, FALSE,"If the camera should be opened in RGB using mencoder");
00462         addProperty<QString>("URL", inputFlag, QString(""),"URL of the video source");
00463         //addProperty<int>("Count",0,"Test param");
00464 
00465         // QVImage's
00466         addProperty< QVImage<uChar,3> >("RGB image", outputFlag, QVImage<uChar,3>(), "Last grabbed RGB image");
00467         addProperty< QVImage<uChar,1> >("Y channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed Y channel image");
00468         addProperty< QVImage<uChar,1> >("U channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed U channel image");
00469         addProperty< QVImage<uChar,1> >("V channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed V channel image");
00470 
00471         qDebug() << "QVMPlayerCamera::QVMPlayerCamera() <- return";
00472         }
00473 
00474 QVMPlayerCamera::~QVMPlayerCamera()
00475         {
00476         qDebug() << "QVMPlayerCamera::~QVMPlayerCamera()";
00477         if (status != Closed) closeCam();
00478         qDebug() << "QVMPlayerCamera::~QVMPlayerCamera() <- deleting image";
00479         setImageBuffer(NULL);
00480         qDebug() << "QVMPlayerCamera::~QVMPlayerCamera() <- return";
00481         }
00482 
00483 void QVMPlayerCamera::initMPlayerArgs(QString urlString, uInt rows, uInt cols)
00484         {
00485         qDebug() << "QVMPlayerCamera::initMPlayerArgs()";
00486         qDebug() << "QVMPlayerCamera::initMPlayerArgs(): url string =" << urlString;
00487 
00488         QUrl url(urlString);
00489 
00490         if (url.host() != "")
00491                 path = url.host() + "/";
00492 
00493         path += url.path();
00494 
00495         qDebug() << "QVMPlayerCamera::initMPlayerArgs(): path" << path;
00496 
00497         // Here we infer the type of the video source from the url.
00498         // If it is not specified in the schema of it, certain match rules are
00499         // applied to guess it out.
00500         if (url.scheme() != "")                         // schema specified by the user
00501                 schema = url.scheme();
00502         else if (urlString.startsWith("/dev/video"))    // a v4l device
00503                 schema = "v4l";
00504         else if (urlString.startsWith("/dev/dv"))       // a dv device
00505                 schema = "dv";
00506         else if (urlString.contains("*"))               // a multifile
00507                 schema = "mf";
00508         else if (urlString.startsWith("www."))          // a http file
00509                 schema = "http";
00510         else if (urlString.startsWith("ftp."))          // a ftp file
00511                 schema = "ftp";
00512 
00513         qDebug() << "QVMPlayerCamera::initMPlayerArgs(): scheme" << schema;
00514 
00515         live_camera = TRUE;     // default configuration
00516 
00517         // Different mplayer args for different kind of image sources:
00518         if ((schema == "v4l") or (schema == "v4l2") or (schema == "analog"))
00519                 {
00520                 // Video for Linux cameras:
00521                 QString urlQueryValues = QString("driver=%1:device=%2").arg(schema).arg(path);
00522 
00523                 QList<QPair<QString, QString> > queryItems = url.queryItems();
00524                 for (int i = 0; i < queryItems.size(); ++i)
00525                         urlQueryValues += ":" + queryItems.at(i).first + "=" + queryItems.at(i).second;
00526 
00527                 mplayer_args << "tv://" << "-tv" << urlQueryValues;
00528                 }
00529         else if (schema == "dv")
00530                 // DV cameras (connected through firewire):
00531                 mplayer_args << path << "-demuxer" << "rawdv" << "-cache" << "400";
00532         else if (schema == "iidc")
00533                 // IIDC cameras (connected through firewire):
00534                 // For example, iidc:///dev/video1394/0?from=/dev/video0:to=/dev/video1
00535                 qFatal("Currently this driver does not work (apparently with\n"
00536                         "vloopback writing and then reading from a fifo with mplayer\ndoes not work).\n");
00537         else if (schema == "tv")
00538                 // Analog TV input:
00539                 qFatal("tv URL: Still not implemented\n");
00540         else if (schema == "dvb")
00541                 // Digital TV input:
00542                 qFatal("dvb URL: Still not implemented\n");
00543         else    // Format can be rtsp:// http://, ftp://, dvd://, vcd://, mf:// or file://
00544                 { 
00545                 //  We pass the url it directly to mplayer:
00546                 live_camera = FALSE;
00547                 if (schema != "")
00548                         mplayer_args << QString(schema + "://" + path);
00549                 else
00550                         mplayer_args << path;
00551                 }
00552 
00553         // IMPORTANT!! All -vf filters MUST be together, separated by commas, and in
00554         // the right order. By now, we only use deinterlacing and scale, and in that order:
00555         QString aux;
00556 
00557         // Deinterlace option:
00558         if(open_options & Deinterlaced) aux = "pp=md";
00559 
00560         if(rows != 0 or cols != 0)
00561                 {
00562                 if(aux != QString())
00563                         aux += QString(",scale=%1:%2").arg(cols).arg(rows);
00564                 else
00565                         aux = QString("scale=%1:%2").arg(cols).arg(rows);
00566                 }
00567 
00568         if (aux != QString()) mplayer_args << "-vf" << aux;
00569 
00570         // Real time option:
00571         if(not (open_options & RealTime))
00572                 {
00573                 if(not live_camera)
00574                         mplayer_args << "-benchmark";
00575                 else
00576                         // The user attempted to open a live camera in continuous mode.
00577                         // We issue a warning:
00578                         qWarning("Warning: opening live cameras in continuous mode "
00579                                          "wastes less CPU time, but it is prone to delays in "
00580                                          "the pipe of images if your process is slower than "
00581                                          "the camera.");
00582                 }
00583 
00584         // Loop option:
00585         if(not (open_options & NoLoop)) mplayer_args << "-loop" << "0";
00586 
00587         // Additional arguments (slave, quiet, nosound & yuv4mpeg output):
00588         mplayer_args << "-slave" << "-quiet" << "-nosound" << "-vo" << QString("yuv4mpeg:file=%1").arg(namedPipe->getInputFilePath());
00589 
00590         qDebug() << "QVMPlayerCamera::initMPlayerArgs() <- return";
00591         }
00592 
00593 // (Implicit) default open method for a camera (uses introspection to read 
00594 // parameters, allowing initialization from argc and argv):
00595 bool QVMPlayerCamera::openCam()
00596         {
00597         OpenOptions optsProp = Default;
00598 
00599         if (getPropertyValue<bool>("RealTime"))         optsProp |= RealTime;
00600         if (getPropertyValue<bool>("Deinterlaced"))     optsProp |= Deinterlaced;
00601         if (getPropertyValue<bool>("NoLoop"))           optsProp |= NoLoop;
00602         if (rgbMode)                                    optsProp |= RGBMEncoder;
00603 
00604         return openCam(getPropertyValue<QString>("URL"), getPropertyValue<int>("Rows"), getPropertyValue<int>("Cols"), optsProp);
00605         }
00606 
00607 // Explicit open url (and possible options) method:
00608 bool QVMPlayerCamera::openCam(const QString & urlstring,OpenOptions opts)
00609         { return openCam(urlstring,0,0,opts); }
00610 
00611 // Main method to open a camera:
00612 bool QVMPlayerCamera::openCam(const QString & urlstring, uInt rows, uInt cols, OpenOptions opts)
00613         {
00614         qDebug() << "QVMPlayerCamera::openCam(" << urlstring << "," << rows << "," << cols << "," << opts << ")";
00615 
00616         setStatus(Closed);
00617 
00618         open_options = opts;
00619 
00620         // Pipe initialization
00621         namedPipe = new QNamedPipe(QString("mplayer"));
00622         fifo_file.setFileName(namedPipe->getOutputFilePath());
00623 
00624         if(open_options & QVMPlayerCamera::RGBMEncoder)
00625                 {
00626                 namedPipeAux = new QNamedPipe(QString("mplayer-aux"));
00627                 fifo_file_2.setFileName(namedPipeAux->getOutputFilePath());
00628                 }
00629 
00630         initMPlayerArgs(urlstring, rows, cols);
00631 
00632         qDebug() << "QVMPlayerCamera::openCam(): MPlayer args ->" << mplayer_args;
00633         mplayer.start("mplayer",mplayer_args);
00634         qDebug() << "QVMPlayerCamera::openCam(): after mplayer.start()";
00635         if(not mplayer.waitForStarted(1000))
00636                 qFatal("Mplayer failed to start: Are you sure it is installed and in the correct PATH?");
00637         qDebug() << "QVMPlayerCamera::openCam(): after mplayer.waitForstarted()";
00638         
00639         // We create a guarding thread that will unblock the subsequent
00640         // fifo_file.readLine in the case that mplayer does not start OK (due,
00641         // for example, to a wrong URL, an incorrect file format, or whatever).
00642         // If mplayer starts OK before two seconds (for local videos) or ten
00643         // seconds (for DVD, VCD and remote videos), this thread silently stops and
00644         // is deleted.
00645         QVCheckOKMplayerCamera *check_thread;
00646         if (schema == "http" or schema == "ftp" or schema == "rtsp" or schema == "dvd" or schema == "vcd")
00647                 check_thread = new QVCheckOKMplayerCamera(fifo_file, 10000);
00648         else
00649                 check_thread = new QVCheckOKMplayerCamera(fifo_file, 2000);
00650 
00651         check_thread->moveToThread(check_thread);
00652         check_thread->start();
00653         qDebug() << "QVMPlayerCamera::openCam(): after starting QVCheckOKMplayerCamera thread";
00654 
00655         // Important to open in ReadWrite mode, to avoid infinite waiting if
00656         // mplayer did not start OK, and because perhaps the former guarding
00657         // thread will write in the FIFO.
00658         qDebug() << "QVMPlayerCamera::openCam(): opening fifo_file";
00659         if((fifo_file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) == -1)
00660                 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getPipeName()));
00661         qDebug() << "QVMPlayerCamera::openCam(): reading fifo_file";
00662 
00663         // Now we read YUV header:
00664         char buf[1024];
00665         int len;
00666         if ((len = fifo_file.readLine(buf, sizeof(buf))) == -1) return FALSE;
00667         if (QString(buf) == QString("MPLAYER ERROR\n")) { 
00668                 std::cerr << "QVMPlayerCamera::openCam(): Warning: Mplayer could not open the requested video source (" << qPrintable(urlstring) << ") of type " << qPrintable(schema) <<std::endl;
00669                 check_thread->quit();
00670                 check_thread->wait();
00671                 delete check_thread;
00672 
00673                 // Cleaning: mplayer.waitForFinished();
00674                 mplayer.terminate();
00675                 if (not mplayer.waitForFinished(500)) mplayer.kill();   
00676                 fifo_file.close();
00677                 delete namedPipe;
00678                 if(open_options & QVMPlayerCamera::RGBMEncoder)
00679                         delete namedPipeAux;
00680 
00681                 qDebug() << "QVMPlayerCamera::openCam(): QVCheckOKMplayerCamera thread deleted after detecting an error; returning FALSE";
00682                 return FALSE;
00683         }
00684 
00685         // If in RGBMEncoder mode, we also launch mencoder (previously writing
00686         // the read line back to the pipe, because mencoder will need it):
00687         if(open_options & QVMPlayerCamera::RGBMEncoder)
00688                 {
00689                 fifo_file.write(buf,len);
00690                 mencoder.start("mencoder", QStringList() << namedPipe->getOutputFilePath() << "-nosound" << "-o" << namedPipeAux->getInputFilePath() <<
00691                                                         "-ovc" << "raw" << "-of" << "rawvideo" << "-vf" << "format=rgb24");
00692                 qDebug() << "QVMPlayerCamera::openCam(): mencoder started";
00693                 if(not mencoder.waitForStarted(1000))
00694                         qFatal("Mencoder failed to start: Are you sure it is installed and in the correct PATH?");
00695                 qDebug() << "QVMPlayerCamera::openCam(): opening fifo_file_2";
00696                 if((fifo_file_2.open(QIODevice::ReadOnly|QIODevice::Unbuffered))==-1)
00697                         qFatal("Error opening fifo %s\n", qPrintable(namedPipeAux->getPipeName()));
00698                 }
00699 
00700         check_thread->quit();
00701         check_thread->wait();
00702 
00703         delete check_thread;
00704         qDebug() << "QVMPlayerCamera::openCam(): QVCheckOKMplayerCamera thread deleted after correct launch of mplayer";
00705 
00706         qDebug() << "QVMPlayerCamera::openCam(): going to create QVMPlayerIOProcessor...";
00707         mplayerIOProcessor = new QVMPlayerIOProcessor(&mplayer);
00708 
00709         qDebug() << "QVMPlayerCamera::openCam(): waiting for initialization.";
00710         while(getRows() == 0 || getCols() == 0)
00711                 mplayerIOProcessor->interpretMPlayerOutput();
00712 
00713         qDebug() << "QVMPlayerCamera::openCam(): video dims (" << getCols() << "," << getRows() << ")";
00714         qDebug() << "QVMPlayerCamera::openCam(): fps " << getFPS();
00715 
00716         mplayerIOProcessor->queueCommandToMPlayer("get_time_length");
00717 
00718         if (open_options & QVMPlayerCamera::RGBMEncoder)
00719                 {
00720                 setImageBuffer(new QVImage<uChar,3>(getRows(), getCols(), 3*getCols()));
00721                 mplayerFrameGrabber = new QVMPlayerFrameGrabber(mplayerIOProcessor, &fifo_file_2, getRows(), getCols(), true, open_options & QVMPlayerCamera::RealTime);
00722                 }
00723         else    {
00724                 setImageBuffer(new QVImage<uChar,1>(getRows(), getCols(), getCols()));
00725                 mplayerFrameGrabber = new QVMPlayerFrameGrabber(mplayerIOProcessor, &fifo_file, getRows(), getCols(), false, open_options & QVMPlayerCamera::RealTime);
00726                 }
00727 
00728         connect(mplayerFrameGrabber,SIGNAL(newReadFrameGrabber()),this,SIGNAL(newRead()));
00729 
00730         // These signals are to defer the call to sendCommandToMplayer, and avoid
00731         // the "QSocketNotifier:: socket notifier cannot be enabled from another
00732         // thread" warning.
00733         connect(mplayerFrameGrabber,SIGNAL(sendCommandSignal()),mplayerIOProcessor,SLOT(sendCommandToMPlayer()));
00734         connect(this,SIGNAL(sendCommandSignal()),mplayerIOProcessor,SLOT(sendCommandToMPlayer()));
00735 
00736         setStatus(Running);
00737 
00738         qDebug() << "QVMPlayerCamera::openCam() <- return";
00739 
00740         emit camOpened();
00741 
00742         //grab();
00743 
00744         return TRUE;
00745         }
00746 
00747 // Close camera method:
00748 void QVMPlayerCamera::closeCam()
00749         {
00750         qDebug() << "QVMPlayerCamera::closeCam()";
00751 
00752         if (status == Closed)
00753                 {
00754                 qDebug() << "QVMPlayerCamera::closeCam(): camera already closed. Returning";
00755                 qDebug() << "QVMPlayerCamera::closeCam() <- return";
00756                 return;
00757                 }
00758 
00759         setStatus(Closed);
00760 
00761         emit camClosed();
00762 
00763         mplayerIOProcessor->queueCommandToMPlayer("quit");      
00764         // Avoid QSocketNotifier annoying message, by deferring call:
00765         emit sendCommandSignal(); // NOT mplayerIOProcessor->sendCommandToMPlayer();
00766 
00767         delete mplayerFrameGrabber;
00768         qDebug() << "QVMPlayerCamera::closeCam(): mplayerFrameGrabber deleted";
00769 
00770         delete mplayerIOProcessor;
00771         qDebug() << "QVMPlayerCamera::closeCam(): mplayerIOProcessor deleted";
00772 
00773         mplayer.terminate();
00774         while (not mplayer.waitForFinished(500)) mplayer.kill();
00775         qDebug() << "QVMPlayerCamera::closeCam(): mplayer terminated";
00776         
00777         if (open_options & QVMPlayerCamera::RGBMEncoder)
00778                 {
00779                 mencoder.terminate();
00780                 while (not mencoder.waitForFinished(500)) mencoder.kill();
00781                 }
00782 
00783         qDebug() << "QVMPlayerCamera::closeCam(): mencoder terminated";
00784         
00785         fifo_file.close();
00786         qDebug() << "QVMPlayerCamera::closeCam(): closed fifo_file";
00787         
00788         if(open_options & QVMPlayerCamera::RGBMEncoder)
00789                 fifo_file_2.close();
00790         qDebug() << "QVMPlayerCamera::closeCam(): closed fifo_file2";
00791         
00792         delete namedPipe;
00793         qDebug() << "mplayercamera2::closecam(): deleted namedpipe";
00794 
00795         if(open_options & QVMPlayerCamera::RGBMEncoder)
00796                 delete namedPipeAux;
00797         qDebug() << "QVMPlayerCamera::closeCam(): deleted namedPipeAux";
00798 
00799         qDebug() << "QVMPlayerCamera::closeCam() <- return";
00800         }
00801 
00802 bool QVMPlayerCamera::grab()
00803         {
00804         qDebug() << "QVMPlayerCamera::grab()";
00805 
00806         if(!performGrab())
00807                 return false;
00808 
00809         if (open_options & QVMPlayerCamera::RGBMEncoder)
00810                 {
00811                 QVImage<uChar,3> grabbedRGBImage;
00812                 mplayerFrameGrabber->getQVImageRGB(grabbedRGBImage);
00813                 setPropertyValue< QVImage<uChar,3> >("RGB image", grabbedRGBImage);
00814                 }
00815         else    {
00816                 QVImage<uChar> grabbedYImage, grabbedUImage, grabbedVImage;
00817                 mplayerFrameGrabber->getQVImageYUV(grabbedYImage, grabbedUImage, grabbedVImage);
00818 
00819                 setPropertyValue< QVImage<uChar,1> >("Y channel image", grabbedYImage);
00820                 setPropertyValue< QVImage<uChar,1> >("U channel image", grabbedUImage);
00821                 setPropertyValue< QVImage<uChar,1> >("V channel image", grabbedVImage);
00822                 }
00823 
00824         writeOutputProperties();
00825 
00826         qDebug() << "QVMPlayerCamera::grab() <~ return";
00827 
00828         return true;
00829         }
00830 
00831 bool QVMPlayerCamera::grab(QVImage<uChar> &imgY, QVImage<uChar> &imgU, QVImage<uChar> &imgV)
00832         {
00833         qDebug() << "QVMPlayerCamera::grab(imageY, imageU, imageV)";
00834         //QVImage<uChar> grabbedYImage, grabbedUImage, grabbedVImage;
00835         //QVImage<uChar,3> grabbedRGBImage;
00836 
00837         bool newImages = performGrab();
00838 
00839         if (newImages)
00840                 mplayerFrameGrabber->getQVImageYUV(imgY, imgU, imgV);
00841 
00842         setPropertyValue< QVImage<uChar,1> >("Y channel image", imgY);
00843         setPropertyValue< QVImage<uChar,1> >("U channel image", imgU);
00844         setPropertyValue< QVImage<uChar,1> >("V channel image", imgV);
00845 
00846         /*imgY = grabbedYImage;
00847         imgU = grabbedUImage;
00848         imgV = grabbedVImage;*/
00849 
00850         qDebug() << "QVMPlayerCamera::grab() <~ return";
00851 
00852         return newImages;
00853         }
00854 
00855 bool QVMPlayerCamera::grab(QVImage<uChar,3> & imageRGB)
00856         {
00857         qDebug() << "QVMPlayerCamera::grab(imageRGB)";
00858         //QVImage<uChar> grabbedYImage, grabbedUImage, grabbedVImage;
00859         //QVImage<uChar,3> grabbedRGBImage;
00860         bool newImages = performGrab();
00861 
00862         if (newImages)
00863                 mplayerFrameGrabber->getQVImageRGB(imageRGB);
00864 
00865         setPropertyValue< QVImage<uChar,3> >("RGB image", imageRGB);
00866         //imageRGB = grabbedRGBImage;
00867         
00868         qDebug() << "QVMPlayerCamera::grab() <~ return";
00869         return newImages;
00870         }
00871 
00872 bool QVMPlayerCamera::grab(QVImage<uChar,1> & imageGray)
00873         {
00874         qDebug() << "QVMPlayerCamera::grab(imageGray)";
00875         //QVImage<uChar> grabbedYImage, grabbedUImage, grabbedVImage;
00876         //QVImage<uChar,3> grabbedRGBImage;
00877 
00878         bool newImages = performGrab();
00879 
00880         if (newImages)
00881                 mplayerFrameGrabber->getQVImageGray(imageGray);
00882 
00883         //imageGray = grabbedYImage;
00884         setPropertyValue< QVImage<uChar,1> >("Y channel image", imageGray);
00885 
00886         qDebug() << "QVMPlayerCamera::grab() <~ return";
00887         return newImages;
00888         }
00889 
00890 bool QVMPlayerCamera::performGrab()
00891         {
00892         // First, if there are any pending commands, we send them to mplayer:
00893         qDebug() << "QVMPlayerCamera::performGrab()";
00894 
00895         if (isClosed()) return false;
00896 
00897         qDebug() << "QVMPlayerCamera::performGrab(): status != Closed";
00898 
00899         bool newFrameGrabbed = false;
00900         // This is for when the camera is paused; it will return the same frames
00901         // over and over, but not immediately, but at a maximum fps rate (to avoid
00902         // intense CPU usage, that will slow the rest of the application and the
00903         // GUI.
00904 
00905         switch(status)
00906                 {
00907                 case RunningOneStep:
00908                         qDebug() << "QVMPlayerCamera::performGrab(): status == RunningOneStep";
00909                         setStatus(Paused);
00910                 case Running:
00911                         qDebug() << "QVMPlayerCamera::performGrab(): status == Running";
00912                         mplayerFrameGrabber->updateFrameBuffer();
00913                         frames_grabbed++;
00914                         newFrameGrabbed = true;
00915                         qDebug() << "QVMPlayerCamera::performGrab(): frames grabbed" << getFramesGrabbed();
00916                         break;
00917 
00918                 case Paused:
00919                         qDebug() << "QVMPlayerCamera::performGrab(): status == Paused";
00920                         /*
00921                         mutexJustToSleepMiliseconds.lock();
00922                         qDebug() << "QVMPlayerCamera::performGrab(): pausing" << milisecsToWait
00923                                 << "milisecs (video is "<< getFPS() <<" FPS's)";
00924                         conditionJustToSleepMiliseconds.wait(&mutexJustToSleepMiliseconds,milisecsToWait);
00925                         qDebug() << "QVMPlayerCamera::performGrab(): unlocking";
00926                         mutexJustToSleepMiliseconds.unlock(); */
00927                         break;
00928 
00929                 default:
00930                         break;
00931                 }
00932         qDebug() << "QVMPlayerCamera::performGrab(): checking finished";
00933 
00934         if (mplayerFrameGrabber->finished)
00935                 closeCam();
00936         else
00937                 emit newGrab();
00938 
00939         qDebug() << "QVMPlayerCamera::performGrab() <- return";
00940 
00941         return newFrameGrabbed;
00942         }
00943 
00944 // Pause, unpause, next frame, set speed, seek and close camer slots:
00945 // In all of them, the corresponding command is sent to the shared command queue
00946 // data structure, so access is accordingly protected .
00947 void QVMPlayerCamera::pauseCam()
00948         {
00949         qDebug() << "QVMPlayerCamera::pauseCam()";
00950         if(status == Closed) return;
00951         setStatus(Paused);
00952         qDebug() << "QVMPlayerCamera::pauseCam() <- return";
00953         }
00954 
00955 void QVMPlayerCamera::unpauseCam()
00956         {
00957         qDebug() << "QVMPlayerCamera::unpauseCam()";
00958         if(status == Closed) return;
00959         setStatus(Running);
00960         qDebug() << "QVMPlayerCamera::unpauseCam() <~ return";
00961         }
00962 
00963 void QVMPlayerCamera::nextFrameCam()
00964         {
00965         qDebug() << "QVMPlayerCamera::nextFrameCam()";
00966         if(status == Closed) return;
00967         setStatus(RunningOneStep);
00968         qDebug() << "QVMPlayerCamera::nextFrameCam() <~ return";
00969         }
00970 
00971 void QVMPlayerCamera::setSpeedCam(double d)
00972         {
00973         qDebug() << "QVMPlayerCamera::setSpeedCam()";
00974         if(status == Closed) return;
00975         mplayerIOProcessor->queueCommandToMPlayer(QString("pausing_keep speed_set ") + QString::number(d));
00976         mplayerIOProcessor->queueCommandToMPlayer("get_property speed");
00977         qDebug() << "QVMPlayerCamera::setSpeedCam() <~ return";
00978         }
00979 
00980 void QVMPlayerCamera::seekCam(TSeekType seek,double d)
00981         {
00982         qDebug() << "QVMPlayerCamera::seekCam()";
00983         if(status == Closed) return;
00984         if(status == Paused)
00985                 setStatus(RunningOneStep);
00986         QString command = QString("pausing_keep seek ") + QString::number(d) + " " + QString::number(seek);
00987         mplayerIOProcessor->queueCommandToMPlayer(command);
00988         qDebug() << "QVMPlayerCamera::seekCam() <~ return";
00989         }
00990 
00991 bool QVMPlayerCamera::link(QVWorker* worker, const QString imageName)
00992         {
00993         connect(worker, SIGNAL(startIteration()), this, SLOT(grab()), Qt::DirectConnection);
00994 
00995         if(worker->isType<QVImage<uChar,1> >(imageName))
00996                 return this->linkProperty("Y channel image",worker,imageName,AsynchronousLink);
00997         else if(worker->isType<QVImage<uChar,3> >(imageName))
00998                 {
00999                 rgbMode = true;
01000                 return this->linkProperty("RGB image",worker,imageName,AsynchronousLink);
01001                 }
01002         else
01003                 {
01004                 disconnect(worker, SIGNAL(startIteration()), this, SLOT(grab()));
01005                 std::cerr << "Warning: QVMPlayerCamera::link(): unsupported property type: property " << qPrintable(imageName)
01006                         << " in holder " << qPrintable(worker->getName()) << "is not a QVImage<uChar,1> or QVImage<uChar,3>" << std::endl;
01007                 return FALSE; //Should never get here;
01008                 }
01009         }
01010 
01011 bool QVMPlayerCamera::link(QVWorker* worker, const QString imageNameY, const QString imageNameU, const QString imageNameV)
01012         {
01013         if(!worker->isType< QVImage<uChar,1> >(imageNameY))
01014                 {
01015                 std::cerr << "Warning: QVMPlayerCamera::link(): image " << qPrintable(imageNameY) << "is not of type QVImage<uChar,1> in holder "
01016                         << qPrintable(worker->getName()) << std::endl;
01017                 return FALSE;
01018                 }
01019 
01020         if(!worker->isType< QVImage<uChar,1> >(imageNameU))
01021                 {
01022                 std::cerr << "Warning: QVMPlayerCamera::link(): image " << qPrintable(imageNameU) << "is not of type QVImage<uChar,1> in holder "
01023                         << qPrintable(worker->getName()) << std::endl;
01024                 return FALSE;
01025                 }
01026 
01027         if(!worker->isType< QVImage<uChar,1> >(imageNameV))
01028                 {
01029                 std::cerr << "Warning: QVMPlayerCamera::link(): image " << qPrintable(imageNameV) << "is not of type QVImage<uChar,1> in holder "
01030                         << qPrintable(worker->getName()) << std::endl;
01031                 return FALSE;
01032                 }
01033 
01034         connect(worker, SIGNAL(startIteration()), this, SLOT(grab()), Qt::DirectConnection);
01035         return  this->linkProperty("Y channel image", worker, imageNameY, AsynchronousLink) &&
01036                 this->linkProperty("U channel image", worker, imageNameU, AsynchronousLink) &&
01037                 this->linkProperty("V channel image", worker, imageNameV, AsynchronousLink);
01038         }
01039 

Generated on Fri Feb 22 18:26:55 2008 for QVision by  doxygen 1.5.3