PARP Research Group University of Murcia, Spain


src/qvio/qvmplayerproxy.cpp

00001 /*
00002  *      Copyright (C) 2007, 2008. 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 <qvipp.h>
00040 #include <qvio.h>
00041 
00042 #include <QVWorker>
00043 #include <QVMPlayerProxy>
00044 
00045 /******************* Auxiliary QVCheckOKMPlayerCamera Class *******************/
00046 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)
00047         {
00048         qDebug() << "QVCheckOKMplayerCamera::QVCheckOKMplayerCamera()";
00049         moveToThread(this);
00050         start();
00051         qDebug() << "QVCheckOKMplayerCamera::QVCheckOKMplayerCamera() <- return";
00052         }
00053 
00054 void QVCheckOKMplayerCamera::run()
00055         {
00056         qDebug() << "QVCheckOKMplayerCamera::run()";
00057         QTimer::singleShot(_max_time_ms_to_wait_for_open, this, SLOT(writeErrorInFifo()));
00058         qDebug() << "QVCheckOKMplayerCamera::run() <- entering event loop";
00059         exec();
00060         qDebug() << "QVCheckOKMplayerCamera::run() <- back from event loop";
00061         qDebug() << "QVCheckOKMplayerCamera::run() <- return";
00062         }
00063 
00064 
00065 void QVCheckOKMplayerCamera::writeErrorInFifo()
00066         {
00067         qDebug() << "QVCheckOKMplayerCamera::writeErrorInFifo()";
00068         _fifo_file.write("MPLAYER ERROR\n"); 
00069         qDebug() << "QVCheckOKMplayerCamera::writeErrorInFifo() -> return";
00070         };
00071 
00072 /********************* Auxiliary QVCameraThread Class *************************/
00073 QVCameraThread::QVCameraThread(QObject *object,char *slot): QThread(), _object(object), _slot(slot)
00074         {
00075         qDebug() << "QVCameraThread::QVCameraThread()";
00076         _object->moveToThread(this);
00077         qDebug() << "QVCameraThread::QVCameraThread(): object moved to thread";
00078         qDebug() << "QVCameraThread::QVCameraThread() <- return";
00079         }
00080 
00081 QVCameraThread::~QVCameraThread()
00082         {
00083         qDebug() << "QVCameraThread::~QVCameraThread()";
00084         disconnect();
00085         quit();
00086         qDebug() << "QVCameraThread::~QVCameraThread(): sent quit to thread";
00087         wait();
00088         qDebug() << "QVCameraThread::~QVCameraThread(): thread finished";
00089         qDebug() << "QVCameraThread::~QVCameraThread() <- return";
00090         }
00091 
00092 void QVCameraThread::run()
00093         {
00094         qDebug() << "QVCameraThread::run()";
00095         QTimer *timer = new QTimer();
00096         timer->start(0);
00097         connect(timer, SIGNAL(timeout()),_object,_slot);
00098         qDebug() << "QVCameraThread::run(): timer created, started and connected";
00099         qDebug() << "QVCameraThread::run(): entering event processing loop";
00100         exec();
00101         qDebug() << "QVCameraThread::run(): back from event processing loop";
00102         delete timer;
00103         qDebug() << "QVCameraThread::run(): timer deleted";
00104         qDebug() << "QVCameraThread::run() <- return";
00105         }
00106 
00107 /********************* Auxiliary QVMPlayerIOProcessor class *******************/
00108 QVMPlayerIOProcessor::QVMPlayerIOProcessor(QProcess * mplayer): QObject(), command_queue(), command_queue_mutex()
00109         {
00110         qDebug() << "QVMPlayerIOProcessor::QVMPlayerIOProcessor()";
00111         rows = cols = 0;
00112         fps = time_length = time_pos = 0;
00113         speed = 1;
00114         this->mplayer = mplayer;
00115 
00116         queueCommandToMPlayer("get_time_length");
00117 
00118         qDebug() << "QVMPlayerIOProcessor::QVMPlayerIOProcessor() <- return";
00119         }
00120 
00121 QVMPlayerIOProcessor::~QVMPlayerIOProcessor()
00122         {
00123         qDebug() << "QVMPlayerIOProcessor::~QVMPlayerIOProcessor()";
00124         qDebug() << "QVMPlayerIOProcessor::~QVMPlayerIOProcessor() <- return";
00125         }
00126 
00127 void QVMPlayerIOProcessor::queueCommandToMPlayer(const QString &com_str, bool ifEmpty)
00128         {
00129         qDebug() << "QVMPlayerIOProcessor::queueCommand("<< com_str <<")";
00130         qDebug() << "QVMPlayerIOProcessor::queueCommand(): command_queue.size() = "
00131                 << command_queue.size();
00132         command_queue_mutex.lock();
00133         if(!ifEmpty || command_queue.size()==0)
00134                 command_queue << com_str + '\n';
00135         command_queue_mutex.unlock();
00136         qDebug() << "QVMPlayerIOProcessor::queueCommand() <- return";
00137         }
00138 
00139 void QVMPlayerIOProcessor::sendCommandToMPlayer()
00140         {
00141         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer()";
00142         command_queue_mutex.lock();
00143         if (command_queue.size() > 0)
00144                 {
00145                 qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer(): sending command:" << command_queue.head();
00146                 mplayer->write(qPrintable(command_queue.dequeue()));
00147                 }
00148         command_queue_mutex.unlock();
00149         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer(): wait for bytes written";
00150         // BUG: In Windows this hangs?
00151         #ifdef unix
00152         mplayer->waitForBytesWritten();
00153         #endif
00154         qDebug() << "QVMPlayerIOProcessor::sendCommandToMPlayer() <- return";
00155         }
00156 
00157 int QVMPlayerIOProcessor::interpretMPlayerOutput()
00158         {
00159         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput()";
00160         int length = -1;
00161         char buf[1024];
00162 
00163         length = mplayer->readLine(buf, sizeof(buf));
00164 
00165         if (length == -1)
00166                 qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): length == -1";
00167         else    {
00168                 QString str(buf);
00169                 QStringList variables = str.simplified().split("=");
00170                 QStringList palabras = str.simplified().split(" ");
00171 
00172                 if(variables[0] == "ANS_speed")
00173                         {
00174                         speed = variables[1].toDouble();
00175                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating speed =" << speed;
00176                         }
00177                 else if(variables[0] == "ANS_LENGTH")
00178                         {
00179                         time_length = variables[1].toDouble();
00180                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating time_length =" << time_length;
00181                         }
00182                 else if(variables[0] == "ANS_TIME_POSITION")
00183                         {
00184                         time_pos = variables[1].toDouble();
00185                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating time_pos =" << time_pos;
00186                         }
00187                 else if (palabras[0] == "VIDEO:")
00188                         {
00189                         // We have FPS specification
00190                         for (int i = 0; i < palabras.size(); ++i)
00191                                 if (palabras[i] == "fps")
00192                                         fps = palabras[i-1].toDouble();
00193 
00194                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating fps" << fps;
00195                         }
00196                 else if (palabras[0] == "VO:")
00197                         {
00198                         // We have video specifications and image size.
00199                         QStringList dimensiones = palabras[2].split("x");
00200                         cols = dimensiones[0].toInt();
00201                         rows = dimensiones[1].toInt();
00202                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating cols" << cols;
00203                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): updating rows" << rows;
00204                         }
00205                 else
00206                         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput(): uninterpreted mplayer output:" << str;
00207                 }
00208         qDebug() << "QVMPlayerIOProcessor::interpretMPlayerOutput() <- return" << length;
00209         return length;
00210         }
00211 
00212 /******************* Auxiliary QVMPlayerFrameGrabber Class ********************/
00213 QVMPlayerFrameGrabber::QVMPlayerFrameGrabber(QVMPlayerIOProcessor *mplayerIOProcessor, QString pipeName,
00214         bool realTime, const uInt waitMilisecs): QObject()
00215         {
00216         // We create a guarding thread that will unblock the subsequent fifo_file.readLine in the
00217         // case that mplayer does not start OK (due, for example, to a wrong URL, an incorrect
00218         // file format, or whatever). If mplayer starts OK before two seconds (for local videos) or
00219         // ten seconds (for DVD, VCD and remote videos), this thread silently stops and is deleted.
00220         QVCheckOKMplayerCamera check_thread(fifoInput, waitMilisecs);
00221 
00222         // We open the pipeline file with the designated name:
00223         fifoInput.setFileName(pipeName);
00224         if(fifoInput.open(QIODevice::ReadWrite|QIODevice::Unbuffered) == -1)
00225                 qFatal("Error opening fifo %s\n", qPrintable(pipeName));
00226 
00227         // Now we read YUV header:
00228         int cols = 0, rows = 0, fps = 0;
00229         finished = !readYUV4MPEG2Header(fifoInput, cols, rows, fps);
00230 
00231         check_thread.quit();
00232         check_thread.wait();
00233 
00234         // Case the header is incorrect, stop.
00235         if (finished)
00236                 return;
00237 
00238         // If the header was correctly read, proceed to init MPlayer IO processing.
00239         qDebug() << "QVMPlayerFrameGrabber::QVMPlayerFrameGrabber(fifoInput,"
00240                         << mplayerIOProcessor->rows << "x" << mplayerIOProcessor->cols << "," << realTime <<")";
00241         
00242         this->mplayerIOProcessor = mplayerIOProcessor;
00243         this->realTime = realTime;
00244         this->frames_read = 0;
00245 
00246         //debug_in_memcpy = debug_in_updateSlot = false;
00247 
00249         imgY = QVImage<uChar>(cols, rows, cols);
00250 
00251         img_auxY = QVImage<uChar>(cols, rows, cols);
00252         img_auxU = QVImage<uChar>(cols/2, rows/2, cols/2);
00253         img_auxV = QVImage<uChar>(cols/2, rows/2, cols/2);
00254 
00255         if (realTime)
00256                 {
00257                 qvcamerathread = new QVCameraThread(this,SLOT(updateSlot()));
00258                 qvcamerathread->start(QThread::NormalPriority);
00259                 }
00260 
00261         connect(this, SIGNAL(sendCommandSignal()), mplayerIOProcessor, SLOT(sendCommandToMPlayer()));
00262         qDebug() << "QVMPlayerFrameGrabber::QVMPlayerFrameGrabber() <- return";
00263         };
00264 
00265 QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber()
00266         {
00267         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber()";
00268         fifoInput.close();
00269 
00270         finished = true;
00271         if (realTime) delete qvcamerathread;
00272         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber(): thread deleted.";
00273         qDebug() << "QVMPlayerFrameGrabber::~QVMPlayerFrameGrabber() <- return";
00274         }
00275 
00276 void QVMPlayerFrameGrabber::updateSlot()
00277         {
00278         qDebug() << "QVMPlayerFrameGrabber::updateSlot()";
00279 
00280         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): sent command to mplayer: get_time_pos";
00281         mplayerIOProcessor->queueCommandToMPlayer("pausing_keep get_time_pos\n",true);
00282 
00283         // Avoid QSocketNotifier annoying message, by deferring call:
00284         emit sendCommandSignal(); // NOT mplayerIOProcessor->sendCommandToMPlayer();
00285 
00286         // New frame read:
00287         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): reading frame";
00288         QVImage<uChar, 1> tempY;
00289         QVImage<uChar, 1> tempU;
00290         QVImage<uChar, 1> tempV;
00291 
00292         // We always read in temporal images, that are later safely copied:
00293         // There is no copy overhead because QVImage uses QSharedData (reference
00294         // counting).
00295         tempY = img_auxY;
00296         tempU = img_auxU;
00297         tempV = img_auxV;
00298 
00299         qDebug() << "QVMPlayerFrameGrabber::readYUV4MPEG2Frame(): reading YUV header";
00300         finished = !readYUV4MPEG2Frame(fifoInput, tempY, tempU, tempV);
00301 
00302         // If in real time, we lock, to avoid collision with the thread that is
00303         // grabbing from the camera:
00304         if(realTime)
00305                 mutex.lock();
00306 
00307         img_auxY = tempY;
00308         img_auxU = tempU;
00309         img_auxV = tempV;
00310 
00311         // Unlock (if in real time):
00312         if(realTime)
00313                 {
00314                 condition.wakeAll(); // Wake possible waiting grabs.
00315                 mutex.unlock();
00316                 }
00317 
00318         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): finished" << finished;
00319         frames_read++;
00320         qDebug() << "QVMPlayerFrameGrabber::updateSlot(): frames read" << frames_read;
00321 
00322         mplayerIOProcessor->interpretMPlayerOutput();
00323 
00324         qDebug() << "QVMPlayerFrameGrabber::updateSlot() <- return";
00325 
00326         emit newReadFrameGrabber();
00327         }
00328 
00329 void QVMPlayerFrameGrabber::updateFrameBuffer()
00330         {
00331         qDebug() << "QVMPlayerFrameGrabber::updateFrameBuffer()";
00332 
00333         // Here we come from a grab, so we always lock (if in real time, it is 
00334         // obviously needed, but also if not in real time, to make non-real-cameras
00335         // grabbing also thread-safe (won't be used normally, but who knows...
00336         // maybe the programmer wish to read different frames from different
00337         // threads, without discarding any frame as could happen with real time
00338         // cameras).
00339         mutex.lock();
00340 
00341         if(realTime)
00342                 condition.wait(&mutex); // If in real time, wait for next fresh frame.
00343 
00344         // If in real time, updateSlot is asynchronously called by a dedicated
00345         // thread, otherwise we have to call it explicitly.
00346         if(not realTime)
00347                 updateSlot();
00348 
00349         imgY = img_auxY;
00350         imgU = img_auxU;
00351         imgV = img_auxV;
00352 
00353         mutex.unlock();
00354 
00355         qDebug() << "QVMPlayerFrameGrabber::updateFrameBuffer() <- return";
00356         }
00357 
00358 void QVMPlayerFrameGrabber::getQVImageYUV(QVImage<uChar> &imgY, QVImage<uChar> &imgU, QVImage<uChar> &imgV) const
00359         {
00360         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV()";
00361         imgY = this->imgY;
00362         imgU = this->imgU;
00363         imgV = this->imgV;
00364         qDebug() << "QVMPlayerFrameGrabber::getQVImageYUV() <- return";
00365         }
00366 
00367 void QVMPlayerFrameGrabber::getQVImageGray(QVImage<uChar> &imgGray) const
00368         {
00369         qDebug() << "QVMPlayerFrameGrabber::getQVImageGray()";
00370         imgGray = imgY;
00371         qDebug() << "QVMPlayerFrameGrabber::getQVImageGray() <- return";
00372         }
00373 
00374 /***************************** QVMPlayerProxy Class **************************/
00375 QVMPlayerProxy::QVMPlayerProxy(QString name): status(QVCamera::Closed), open_options(Default)
00376         {
00377         qDebug() << "QVMPlayerProxy::QVMPlayerProxy()";
00378 
00379         frames_grabbed = 0;
00380         live_camera = FALSE;
00381 
00382         qDebug() << "QVMPlayerProxy::QVMPlayerProxy() <- return";
00383         }
00384 
00385 QVMPlayerProxy::~QVMPlayerProxy()
00386         {
00387         qDebug() << "QVMPlayerProxy::~QVMPlayerProxy()";
00388         if (status != QVCamera::Closed) closeCam();
00389         qDebug() << "QVMPlayerProxy::~QVMPlayerProxy() <- deleting image";
00390         qDebug() << "QVMPlayerProxy::~QVMPlayerProxy() <- return";
00391         }
00392 
00393 void QVMPlayerProxy::initMPlayerArgs(QString urlString, uInt rows, uInt cols)
00394         {
00395         qDebug() << "QVMPlayerProxy::initMPlayerArgs()";
00396         qDebug() << "QVMPlayerProxy::initMPlayerArgs(): url string =" << urlString;
00397 
00398         // Loop option and fixed-vo must go first:
00399         if(not (open_options & NoLoop)) mplayer_args << "-loop" << "0";
00400 
00401         mplayer_args << "-fixed-vo";
00402 
00403         QUrl url(urlString);
00404 
00405         if (url.host() != "")
00406                 path = url.host() + "/";
00407 
00408         path += url.path();
00409 
00410         qDebug() << "QVMPlayerProxy::initMPlayerArgs(): path" << path;
00411 
00412         // Here we infer the type of the video source from the url.
00413         // If it is not specified in the schema of it, certain match rules are
00414         // applied to guess it out.
00415         if (url.scheme() != "")                         // schema specified by the user
00416                 schema = url.scheme();
00417         else if (urlString.startsWith("/dev/video"))    // a v4l device
00418                 schema = "v4l";
00419         else if (urlString.startsWith("/dev/dv"))       // a dv device
00420                 schema = "dv";
00421         else if (urlString.contains("*"))               // a multifile
00422                 schema = "mf";
00423         else if (urlString.startsWith("www."))          // a http file
00424                 schema = "http";
00425         else if (urlString.startsWith("ftp."))          // a ftp file
00426                 schema = "ftp";
00427 
00428         qDebug() << "QVMPlayerProxy::initMPlayerArgs(): scheme" << schema;
00429 
00430         live_camera = TRUE;     // default configuration
00431 
00432         // Different mplayer args for different kind of image sources:
00433         if ((schema == "v4l") or (schema == "v4l2") or (schema == "analog"))
00434                 {
00435                 // Video for Linux cameras:
00436                 QString urlQueryValues = QString("driver=%1:device=%2").arg(schema).arg(path);
00437 
00438                 QList<QPair<QString, QString> > queryItems = url.queryItems();
00439                 for (int i = 0; i < queryItems.size(); ++i)
00440                         urlQueryValues += ":" + queryItems.at(i).first + "=" + queryItems.at(i).second;
00441 
00442                 mplayer_args << "tv://" << "-tv" << urlQueryValues;
00443                 }
00444         else if (schema == "dv")
00445                 // DV cameras (connected through firewire):
00446                 mplayer_args << path << "-demuxer" << "rawdv" << "-cache" << "400";
00447         else if (schema == "iidc")
00448                 // IIDC cameras (connected through firewire):
00449                 // For example, iidc:///dev/video1394/0?from=/dev/video0:to=/dev/video1
00450                 qFatal("Currently this driver does not work (apparently with\n"
00451                         "vloopback writing and then reading from a fifo with mplayer\ndoes not work).\n");
00452         else if (schema == "tv")
00453                 // Analog TV input:
00454                 qFatal("tv URL: Still not implemented\n");
00455         else if (schema == "dvb")
00456                 // Digital TV input:
00457                 qFatal("dvb URL: Still not implemented\n");
00458         else    // Format can be rtsp:// http://, ftp://, dvd://, vcd://, mf:// or file://
00459                 { 
00460                 //  We pass the url it directly to mplayer:
00461                 live_camera = FALSE;
00462                 if (schema != "")
00463                         mplayer_args << QString(schema + "://" + path);
00464                 else
00465                         mplayer_args << path;
00466                 }
00467 
00468         // IMPORTANT!! All -vf filters MUST be together, separated by commas, and in
00469         // the right order. By now, we only use deinterlacing and scale, and in that order:
00470         QString aux;
00471 
00472         // Deinterlace option:
00473         if(open_options & Deinterlaced) aux = "pp=md";
00474 
00475         if(rows != 0 or cols != 0)
00476                 {
00477                 if(aux != QString())
00478                         aux += QString(",scale=%1:%2").arg(cols).arg(rows);
00479                 else
00480                         aux = QString("scale=%1:%2").arg(cols).arg(rows);
00481                 }
00482 
00483         if (aux != QString()) mplayer_args << "-vf" << aux;
00484 
00485         // Real time option:
00486         if(not (open_options & RealTime))
00487                 {
00488                 if(not live_camera)
00489                         mplayer_args << "-benchmark";
00490                 else
00491                         // The user attempted to open a live camera in continuous mode.
00492                         // We issue a warning:
00493                         qWarning("Warning: opening live cameras in continuous mode "
00494                                          "wastes less CPU time, but it is prone to delays in "
00495                                          "the pipe of images if your process is slower than "
00496                                          "the camera.");
00497                 }
00498 
00499         // Additional arguments (slave, quiet, nosound & yuv4mpeg output):
00500         mplayer_args << "-slave" << "-quiet" << "-nosound" << "-vo" << QString("yuv4mpeg:file=%1").arg(namedPipe->getInputFilePath());
00501 
00502         qDebug() << "QVMPlayerProxy::initMPlayerArgs() <- return";
00503         }
00504 
00505 // Main method to open a camera:
00506 bool QVMPlayerProxy::openCam(const QString & urlstring, OpenOptions opts, uInt suggestedRows, uInt suggestedCols)
00507         {
00508         std::cout << "QVMPlayerProxy::openCam(" << qPrintable(urlstring) << ","
00509                 << suggestedCols << "x" << suggestedRows << "," << opts << ")" << std::endl;
00510 
00511         qDebug() << "QVMPlayerProxy::openCam(" << urlstring << ","
00512                 << suggestedCols << "x" << suggestedRows << "," << opts << ")";
00513 
00514         setStatus(QVCamera::Closed);
00515 
00516         open_options = opts;
00517 
00518         // Pipe initialization
00519         namedPipe = new QNamedPipe(QString("mplayer"));
00520 
00521         initMPlayerArgs(urlstring, suggestedRows, suggestedCols);
00522 
00523         qDebug() << "QVMPlayerProxy::openCam(): MPlayer args ->" << mplayer_args;
00524         mplayer.start(MPLAYER_BINARY_PATH, mplayer_args);
00525         qDebug() << "QVMPlayerProxy::openCam(): after mplayer.start()";
00526         if(not mplayer.waitForStarted(1000))
00527                 qFatal("Mplayer failed to start: Are you sure it is installed and in the correct PATH?");
00528         qDebug() << "QVMPlayerProxy::openCam(): after mplayer.waitForstarted()";
00529         
00530         qDebug() << "QVMPlayerProxy::openCam(): creating QVMPlayerIOProcessor...";
00531         mplayerIOProcessor = new QVMPlayerIOProcessor(&mplayer);
00532         // -----------------------------------------
00533 
00534         const uInt waitMilisecs = (     schema == "http" or schema == "ftp" or
00535                                         schema == "rtsp" or schema == "dvd" or
00536                                         schema == "vcd" )? 10000:2000;
00537 
00538         // Important to open in ReadWrite mode, to avoid infinite waiting if mplayer did
00539         // not start OK, and because perhaps the former guarding thread will write in the FIFO.
00540         qDebug() << "QVMPlayerProxy::openCam(): opening fifo_file";
00541 
00542         mplayerFrameGrabber = new QVMPlayerFrameGrabber(mplayerIOProcessor, namedPipe->getOutputFilePath(),
00543                                                         open_options & QVMPlayerProxy::RealTime, waitMilisecs);
00544 
00545         if (mplayerFrameGrabber->isFinished())
00546                 { 
00547                 std::cerr << "QVMPlayerProxy::openCam(): Warning: Mplayer could not open the requested video source ("
00548                         << qPrintable(urlstring) << ") of type " << qPrintable(schema) <<std::endl;
00549 
00550                 mplayer.terminate();
00551                 if (not mplayer.waitForFinished(500)) mplayer.kill();   
00552                 delete namedPipe;
00553 
00554                 qDebug() << "QVMPlayerProxy::openCam(): QVCheckOKMplayerCamera thread deleted after detecting an error."
00555                         << " Returning FALSE";
00556                 return FALSE;
00557                 }
00558 
00559         qDebug() << "QVMPlayerProxy::openCam(): QVCheckOKMplayerCamera thread deleted after correct launch of mplayer";
00560 
00561 
00562         // -----------------------------------------
00563         qDebug() << "QVMPlayerProxy::openCam(): initializing MPlayer.";
00564 
00565         // These signals are to defer the call to sendCommandToMplayer, and avoid
00566         // the "QSocketNotifier:: socket notifier cannot be enabled from another
00567         // thread" warning.
00568         connect(mplayerFrameGrabber,SIGNAL(newReadFrameGrabber()),this,SIGNAL(newRead()));
00569         connect(this,SIGNAL(sendCommandSignal()),mplayerIOProcessor,SLOT(sendCommandToMPlayer()));
00570 
00571         mplayer.waitForReadyRead();
00572 
00573         setStatus(QVCamera::Running);
00574 
00575         qDebug() << "QVMPlayerProxy::openCam() <- return";
00576 
00577         emit camOpened();
00578 
00579         return TRUE;
00580         }
00581 
00582 // Close camera method:
00583 void QVMPlayerProxy::closeCam()
00584         {
00585         qDebug() << "QVMPlayerProxy::closeCam()";
00586 
00587         if (status == QVCamera::Closed)
00588                 {
00589                 qDebug() << "QVMPlayerProxy::closeCam(): camera already closed. Returning";
00590                 qDebug() << "QVMPlayerProxy::closeCam() <- return";
00591                 return;
00592                 }
00593 
00594         setStatus(QVCamera::Closed);
00595 
00596         emit camClosed();
00597 
00598         mplayerIOProcessor->queueCommandToMPlayer("quit");      
00599         // Avoid QSocketNotifier annoying message, by deferring call:
00600         emit sendCommandSignal();
00601 
00602         delete mplayerFrameGrabber;
00603         qDebug() << "QVMPlayerProxy::closeCam(): mplayerFrameGrabber deleted";
00604 
00605         delete mplayerIOProcessor;
00606         qDebug() << "QVMPlayerProxy::closeCam(): mplayerIOProcessor deleted";
00607 
00608         mplayer.terminate();
00609         while (not mplayer.waitForFinished(500)) mplayer.kill();
00610         qDebug() << "QVMPlayerProxy::closeCam(): mplayer terminated";
00611         
00612         delete namedPipe;
00613         qDebug() << "QVMPlayerProxy::closecam(): deleted namedpipe";
00614 
00615         qDebug() << "QVMPlayerProxy::closeCam() <- return";
00616         }
00617 
00618 bool QVMPlayerProxy::grab(QVImage<uChar> &imgY, QVImage<uChar> &imgU, QVImage<uChar> &imgV)
00619         {
00620         qDebug() << "QVMPlayerProxy::grab(imageY, imageU, imageV)";
00621 
00622         bool newImages = performGrab();
00623 
00624         if (newImages)
00625                 mplayerFrameGrabber->getQVImageYUV(imgY, imgU, imgV);
00626 
00627         qDebug() << "QVMPlayerProxy::grab() <~ return";
00628 
00629         return newImages;
00630         }
00631 
00632 bool QVMPlayerProxy::grab(QVImage<uChar,3> & imageRGB)
00633         {
00634         qDebug() << "QVMPlayerProxy::grab(imageRGB)";
00635         bool newImages = performGrab();
00636 
00637         QVImage<uChar> grabbedYImage, grabbedUImage, grabbedVImage;
00638 
00639         if (newImages)
00640                 {
00641                 mplayerFrameGrabber->getQVImageYUV(grabbedYImage, grabbedUImage, grabbedVImage);
00642 
00643                 imageRGB = QVImage<uChar,3>(grabbedYImage.getCols(),grabbedYImage.getRows());
00644                 YUV420ToRGB(grabbedYImage, grabbedUImage, grabbedVImage, imageRGB);
00645                 }
00646 
00647         qDebug() << "QVMPlayerProxy::grab() <~ return";
00648         return newImages;
00649         }
00650 
00651 bool QVMPlayerProxy::grab(QVImage<uChar,1> & imageGray)
00652         {
00653         qDebug() << "QVMPlayerProxy::grab(imageGray)";
00654 
00655         bool newImages = performGrab();
00656 
00657         if (newImages)
00658                 mplayerFrameGrabber->getQVImageGray(imageGray);
00659 
00660         qDebug() << "QVMPlayerProxy::grab() <~ return";
00661         return newImages;
00662         }
00663 
00664 bool QVMPlayerProxy::performGrab()
00665         {
00666         // First, if there are any pending commands, we send them to mplayer:
00667         qDebug() << "QVMPlayerProxy::performGrab()";
00668 
00669         if (isClosed()) return false;
00670 
00671         qDebug() << "QVMPlayerProxy::performGrab(): status != Closed";
00672 
00673         bool newFrameGrabbed = false;
00674         // This is for when the camera is paused; it will return the same frames
00675         // over and over, but not immediately, but at a maximum fps rate (to avoid
00676         // intense CPU usage, that will slow the rest of the application and the
00677         // GUI.
00678 
00679         switch(status)
00680                 {
00681                 case QVCamera::RunningOneStep:
00682                         qDebug() << "QVMPlayerProxy::performGrab(): status == RunningOneStep";
00683                         setStatus(QVCamera::Paused);
00684                 case QVCamera::Running:
00685                         qDebug() << "QVMPlayerProxy::performGrab(): status == Running";
00686                         mplayerFrameGrabber->updateFrameBuffer();
00687                         frames_grabbed++;
00688                         newFrameGrabbed = true;
00689                         qDebug() << "QVMPlayerProxy::performGrab(): frames grabbed" << getFramesGrabbed();
00690                         break;
00691 
00692                 case QVCamera::Paused:
00693                         qDebug() << "QVMPlayerProxy::performGrab(): status == Paused";
00694                         /*
00695                         mutexJustToSleepMiliseconds.lock();
00696                         qDebug() << "QVMPlayerProxy::performGrab(): pausing" << milisecsToWait
00697                                 << "milisecs (video is "<< getFPS() <<" FPS's)";
00698                         conditionJustToSleepMiliseconds.wait(&mutexJustToSleepMiliseconds,milisecsToWait);
00699                         qDebug() << "QVMPlayerProxy::performGrab(): unlocking";
00700                         mutexJustToSleepMiliseconds.unlock(); */
00701                         break;
00702 
00703                 default:
00704                         break;
00705                 }
00706         qDebug() << "QVMPlayerProxy::performGrab(): checking finished";
00707 
00708         if (mplayerFrameGrabber->isFinished())
00709                 closeCam();
00710         else
00711                 emit newGrab();
00712 
00713         qDebug() << "QVMPlayerProxy::performGrab() <- return";
00714 
00715         return newFrameGrabbed;
00716         }
00717 
00718 // Pause, unpause, next frame, set speed, seek and close camer slots:
00719 // In all of them, the corresponding command is sent to the shared command queue
00720 // data structure, so access is accordingly protected .
00721 void QVMPlayerProxy::pauseCamSlot()
00722         {
00723         qDebug() << "QVMPlayerProxy::pauseCam()";
00724         if(status == QVCamera::Closed) return;
00725         setStatus(QVCamera::Paused);
00726         qDebug() << "QVMPlayerProxy::pauseCam() <- return";
00727         }
00728 
00729 void QVMPlayerProxy::unpauseCamSlot()
00730         {
00731         qDebug() << "QVMPlayerProxy::unpauseCam()";
00732         if(status == QVCamera::Closed) return;
00733         setStatus(QVCamera::Running);
00734         qDebug() << "QVMPlayerProxy::unpauseCam() <~ return";
00735         }
00736 
00737 void QVMPlayerProxy::nextFrameCamSlot()
00738         {
00739         qDebug() << "QVMPlayerProxy::nextFrameCam()";
00740         if(status == QVCamera::Closed) return;
00741         setStatus(QVCamera::RunningOneStep);
00742         qDebug() << "QVMPlayerProxy::nextFrameCam() <~ return";
00743         }
00744 
00745 void QVMPlayerProxy::setSpeedCamSlot(double d)
00746         {
00747         qDebug() << "QVMPlayerProxy::setSpeedCam()";
00748         if(status == QVCamera::Closed) return;
00749         mplayerIOProcessor->queueCommandToMPlayer(QString("pausing_keep speed_set ") + QString::number(d));
00750         mplayerIOProcessor->queueCommandToMPlayer("get_property speed");
00751         qDebug() << "QVMPlayerProxy::setSpeedCam() <~ return";
00752         }
00753 
00754 void QVMPlayerProxy::seekCamSlot(QVCamera::TSeekType seek,double d)
00755         {
00756         qDebug() << "QVMPlayerProxy::seekCam()";
00757         if(status == QVCamera::Closed) return;
00758         if(status == QVCamera::Paused)
00759                 setStatus(QVCamera::RunningOneStep);
00760         QString command = QString("pausing_keep seek ") + QString::number(d) + " " + QString::number(seek);
00761         mplayerIOProcessor->queueCommandToMPlayer(command);
00762         qDebug() << "QVMPlayerProxy::seekCam() <~ return";
00763         }



QVision framework. PARP research group, copyright 2007, 2008.