00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 <iostream>
00033
00034 #include <QDebug>
00035 #include <QStringList>
00036 #include <QRegExp>
00037
00038 #include <qvipp.h>
00039 #include <qvio.h>
00040
00041 #include <QVMPlayerReader>
00042
00043 #include <QTimer>
00044
00045
00046
00047 QVCheckOKMPlayer::QVCheckOKMPlayer(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)
00048 {
00049 qDebug() << "QVCheckOKMPlayer::QVCheckOKMPlayer() <- starting thread";
00050 moveToThread(this);
00051 start();
00052 }
00053
00054 void QVCheckOKMPlayer::run()
00055 {
00056 QTimer::singleShot(_max_time_ms_to_wait_for_open, this, SLOT(writeErrorInFifo()));
00057 qDebug() << "QVCheckOKMPlayer::run() <- entering event loop";
00058 exec();
00059 qDebug() << "QVCheckOKMPlayer::run() <- back from event loop";
00060 }
00061
00062 void QVCheckOKMPlayer::writeErrorInFifo()
00063 {
00064 qDebug() << "QVCheckOKMPlayerCamera::writeErrorInFifo()";
00065 _fifo_file.write("MPLAYER ERROR\n");
00066 qDebug() << "QVCheckOKMPlayerCamera::writeErrorInFifo() -> return";
00067 };
00068
00069
00070
00071 void QVMPlayerReader::initMPlayerArgs(QString urlString, unsigned int suggested_cols, unsigned int suggested_rows)
00072 {
00073 qDebug() << "QVMPlayerReader::initMPlayerArgs(" << urlString << "," << suggested_cols << "," << suggested_rows << ")";
00074
00075 mplayer_args = QStringList();
00076
00077
00078 if(not (open_options & NoLoop)) mplayer_args << "-loop" << "0";
00079
00080 mplayer_args << "-fixed-vo";
00081
00082 QUrl url(urlString);
00083
00084 path = QString();
00085
00086 if (url.host() != "")
00087 path = url.host() + "/";
00088
00089 path += url.path();
00090
00091
00092
00093
00094 if (url.scheme() != "")
00095 schema = url.scheme();
00096 else if (urlString.startsWith("/dev/video"))
00097 schema = "v4l";
00098 else if (urlString.startsWith("/dev/dv"))
00099 schema = "dv";
00100 else if (urlString.contains("*"))
00101 schema = "mf";
00102 else if (urlString.startsWith("www."))
00103 schema = "http";
00104 else if (urlString.startsWith("ftp."))
00105 schema = "ftp";
00106 else
00107 schema = QString();
00108
00109 live_camera = TRUE;
00110
00111
00112 if ((schema == "v4l") or (schema == "v4l2") or (schema == "analog"))
00113 {
00114
00115 QString urlQueryValues = QString("driver=%1:device=%2").arg(schema).arg(path);
00116
00117 QList<QPair<QString, QString> > queryItems = url.queryItems();
00118 for (int i = 0; i < queryItems.size(); ++i)
00119 urlQueryValues += ":" + queryItems.at(i).first + "=" + queryItems.at(i).second;
00120
00121 mplayer_args << "tv://" << "-tv" << urlQueryValues;
00122 }
00123 else if (schema == "dv")
00124
00125 mplayer_args << path << "-demuxer" << "rawdv" << "-cache" << "400";
00126 else if (schema == "iidc")
00127
00128
00129 qFatal("Currently this driver does not work (apparently with\n"
00130 "vloopback writing and then reading from a fifo with mplayer\ndoes not work).\n");
00131 else if (schema == "tv")
00132
00133 qFatal("tv URL: Still not implemented\n");
00134 else if (schema == "dvb")
00135
00136 qFatal("dvb URL: Still not implemented\n");
00137 else
00138 {
00139
00140 live_camera = FALSE;
00141 if (schema != "")
00142 mplayer_args << QString(schema + "://" + path);
00143 else
00144 mplayer_args << path;
00145 }
00146
00147
00148
00149 QString aux;
00150
00151
00152 if(open_options & Deinterlaced) aux = "pp=md";
00153
00154
00155 if(suggested_cols != 0 and suggested_rows != 0)
00156 {
00157 if(aux != QString())
00158 aux += QString(",scale=%1:%2").arg(suggested_cols).arg(suggested_rows);
00159 else
00160 aux = QString("scale=%1:%2").arg(suggested_cols).arg(suggested_rows);
00161 }
00162 if (aux != QString()) mplayer_args << "-vf" << aux;
00163
00164
00165 if(not (open_options & RealTime))
00166 {
00167 if(not live_camera)
00168 mplayer_args << "-benchmark";
00169 }
00170
00171
00172 mplayer_args << "-slave" << "-quiet" << "-nosound" << "-vo" << QString("yuv4mpeg:file=%1").arg(namedPipe->getInputFilePath());
00173
00174 qDebug() << "QVMPlayerReader::initMPlayerArgs(): MPlayer args = " << mplayer_args;
00175 qDebug() << "QVMPlayerReader::initMPlayerArgs() <- return";
00176 }
00177
00178 int QVMPlayerReader::interpretMPlayerOutput()
00179 {
00180 int length = -1;
00181 char buf[1024];
00182
00183 length = mplayer->readLine(buf, sizeof(buf));
00184
00185 if (length == -1)
00186 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): length == -1";
00187 else {
00188 QString str(buf);
00189 QStringList variables = str.simplified().split("=");
00190 QStringList palabras = str.simplified().split(" ");
00191
00192 if(variables[0] == "ANS_LENGTH")
00193 {
00194 time_length = variables[1].toDouble();
00195 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): updating time_length =" << time_length;
00196 }
00197 else if(variables[0] == "ANS_TIME_POSITION")
00198 {
00199 time_pos = variables[1].toDouble();
00200 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): updating time_pos =" << time_pos;
00201 }
00202 else
00203 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): uninterpreted mplayer output:" << str;
00204 }
00205 qDebug() << "QVMPlayerReader::interpretMPlayerOutput() <- return " << length;
00206 return length;
00207 }
00208
00209 bool QVMPlayerReader::performGrab()
00210 {
00211 qDebug() << "QVMPlayerReader::performGrab()";
00212
00213 if (not camera_opened)
00214 {
00215 qDebug() << "QVMPlayerReader::performGrab() returns FALSE (camera is closed)";
00216 return false;
00217 }
00218
00219 qDebug() << "QVMPlayerReader::performGrab(): sending command get_time_pos to mplayer";
00220 mplayer->write("pausing_keep get_time_pos\n");
00221
00222
00223 qDebug() << "QVMPlayerReader::performGrab: reading YUV frame: readYUV4MPEG2Frame()";
00224 if (!readYUV4MPEG2Frame(fifoInput, imgY, imgU, imgV))
00225 {
00226 qDebug() << "QVMPlayerReader::performGrab: No more frames left, closing camera";
00227 end_of_video = TRUE;
00228 closeCam();
00229 qDebug() << "QVMPlayerReader::performGrab: No more frames left, camera closed, returning false";
00230 return FALSE;
00231 }
00232
00233 frames_grabbed++;
00234 qDebug() << "QVMPlayerReader::performGrab: new frame read (" << frames_grabbed << ")";
00235
00236
00237 qDebug() << "QVMPlayerReader::performGrab: now interpreting mplayer output";
00238 while(interpretMPlayerOutput() > 0);
00239
00240 qDebug() << "QVMPlayerReader::performGrab: emitting newGrab() signal";
00241 emit newGrab();
00242
00243 qDebug() << "QVMPlayerReader::performGrab() <- returning TRUE";
00244 return TRUE;
00245 }
00246
00247 static inline int iRoundUp(int a, int b) {
00248 return (a % b == 0) ? a : b*(a / b + 1) ;
00249 }
00250
00251 bool QVMPlayerReader::openCam(const QString & urlstring, OpenOptions opts, unsigned int suggested_cols, unsigned int suggested_rows)
00252 {
00253 qDebug() << "QVMPlayerReader::openCam(" << qPrintable(urlstring) << "," << static_cast<int>(opts) << ","
00254 << suggested_cols << "," << suggested_rows << "," << opts << ")";
00255
00256 if (camera_opened)
00257 {
00258 qDebug() << "QVMPlayerReader::openCam() <- closing previously opened camera";
00259 closeCam();
00260 qDebug() << "QVMPlayerReader::openCam() <- previously opened camera closed";
00261 }
00262
00263 open_options = opts;
00264
00265
00266 namedPipe = new QNamedPipe(QString("mplayer"));
00267 qDebug() << "QVMPlayerReader::openCam(): Named pipe created" << namedPipe->getOutputFilePath();
00268
00269
00270 mplayer = new QProcess;
00271 mplayer->setParent(this);
00272 mplayer->moveToThread(this->thread());
00273 initMPlayerArgs(urlstring, suggested_cols, suggested_rows);
00274 mplayer->start(MPLAYER_BINARY_PATH, mplayer_args);
00275 qDebug() << "QVMPlayerReader::openCam(): after mplayer->start()";
00276 if(not mplayer->waitForStarted(1000))
00277 qFatal("Mplayer failed to start in a second: Are you sure it is installed and in the correct PATH?");
00278 qDebug() << "QVMPlayerReader::openCam(): after mplayer->waitForstarted()";
00279
00280
00281
00282 qDebug() << "QVMPlayerReader::openCam(): opening fifo " << qPrintable(namedPipe->getOutputFilePath());
00283 fifoInput.setFileName(namedPipe->getOutputFilePath());
00284 if(fifoInput.open(QIODevice::ReadWrite|QIODevice::Unbuffered) == -1)
00285 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00286 qDebug() << "QVMPlayerReader::openCam(): fifo opened";
00287
00288
00289
00290
00291
00292 const uInt waitMilisecs = ( schema == "http" or schema == "ftp" or
00293 schema == "rtsp" or schema == "dvd" or
00294 schema == "vcd" )? 10000:2000;
00295 QVCheckOKMPlayer check_thread(fifoInput, waitMilisecs);
00296
00297 qDebug()<< "QVMPlayerReader::openCam(): going to read YUV header";
00298
00299 if (!readYUV4MPEG2Header(fifoInput, cols, rows, fps))
00300 {
00301 qWarning() << "QVMPlayerReader::openCam(): Warning: Mplayer could not open the requested video source ("
00302 << qPrintable(urlstring) << ") of type " << qPrintable(schema);
00303 qDebug() << "QVMPlayerReader::openCam(): Terminating and killing mplayer";
00304 mplayer->terminate();
00305 if (not mplayer->waitForFinished(500)) mplayer->kill();
00306 qDebug() << "QVMPlayerReader::openCam(): Deleting pipe and mplayer";
00307 delete namedPipe;
00308 delete mplayer;
00309 qDebug() << "QVMPlayerReader::openCam(): closing fifo";
00310 fifoInput.close();
00311
00312 while(not check_thread.isFinished())
00313 {
00314 qDebug() << "QVMPlayerReader::openCam(): quitting guarding thread (incorrect mplayer launch)";
00315 check_thread.quit();
00316 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread quitted after correct launch of mplayer";
00317 check_thread.wait(100);
00318 }
00319 qDebug() << "QVMPlayerReader::openCam(): guarding thread finished after incorrect launch of mplayer";
00320 qDebug() << "QVMPlayerReader::openCam(): Returning FALSE";
00321 cols = 0;
00322 rows = 0;
00323 fps = 0;
00324 frames_grabbed = 0;
00325 camera_opened = FALSE;
00326 return FALSE;
00327 }
00328 qDebug()<< "QVMPlayerReader::openCam(): back from read YUV header: cols = " << cols << " rows = " << rows << ", fps = " << fps;
00329
00330
00331 while(not check_thread.isFinished())
00332 {
00333 qDebug() << "QVMPlayerReader::openCam(): quitting guarding thread (correct mplayer launch)";
00334 check_thread.quit();
00335 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread quitted after correct launch of mplayer";
00336 check_thread.wait(100);
00337 }
00338 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread finished after correct launch of mplayer";
00339
00340
00341
00342
00343
00344
00345 QFile fifoAux;
00346 fifoAux.setFileName(namedPipe->getOutputFilePath());
00347 fifoAux.open(QIODevice::ReadOnly);
00348 fifoInput.close();
00349
00350 if(fifoInput.open(QIODevice::ReadOnly|QIODevice::Unbuffered) == -1)
00351 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00352 fifoAux.close();
00353
00354 qDebug() << "QVMPlayerReader::openCam(): Header correctly read: cols = "
00355 << cols << ", rows = " << rows << ", fps = " << fps;
00356
00357
00358 frames_grabbed = 0;
00359 camera_opened = TRUE;
00360
00361
00362 imgY = QVImage<uChar>(cols, rows, iRoundUp(cols,8));
00363 imgU = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00364 imgV = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00365
00366
00367
00368
00369
00370 qDebug() << "QVMPlayerReader::openCam() <- sending get_time_length command to mplayer";
00371 mplayer->write("get_time_length\n");
00372 mplayer->waitForReadyRead();
00373
00374 qDebug() << "QVMPlayerReader::openCam() <- emitting camOpened signal";
00375 emit camOpened();
00376
00377 qDebug() << "QVMPlayerReader::openCam() <- return";
00378 return TRUE;
00379 }
00380
00381 void QVMPlayerReader::closeCam()
00382 {
00383 qDebug() << "QVMPlayerReader::closeCam()";
00384
00385 if (not camera_opened)
00386 {
00387 qDebug() << "QVMPlayerReader::closeCam(): camera already closed. Returning";
00388 return;
00389 }
00390
00391 qDebug() << "QVMPlayerReader::closeCam(): closing fifo";
00392 fifoInput.close();
00393
00394 if(not end_of_video)
00395 {
00396 qDebug() << "QVMPlayerReader::closeCam(): going to send quit command to mplayer";
00397 mplayer->write("quit\n");
00398 }
00399 qDebug() << "QVMPlayerReader::closeCam(): going to terminate mplayer";
00400 mplayer->terminate();
00401 qDebug() << "QVMPlayerReader::closeCam(): going to kill mplayer";
00402 mplayer->kill();
00403 qDebug() << "QVMPlayerReader::closeCam(): going to wait for mplayer to finish";
00404 mplayer->waitForFinished();
00405 qDebug() << "QVMPlayerReader::closeCam(): mplayer finished";
00406
00407 qDebug() << "QVMPlayerReader::closecam(): deleting namedpipe";
00408 delete namedPipe;
00409
00410 qDebug() << "QVMPlayerReader::closecam(): deleting QProcess mplayer";
00411 delete mplayer;
00412
00413
00414 open_options = Default;
00415 path = QString();
00416 schema = QString();
00417 camera_opened = FALSE;
00418 frames_grabbed = 0;
00419 live_camera = FALSE;
00420 imgY = QVImage<uChar>();
00421 imgU = QVImage<uChar>();
00422 imgV = QVImage<uChar>();
00423 cols = 0;
00424 rows = 0;
00425 fps = 0;
00426 time_length = 0;
00427 time_pos = 0;
00428 end_of_video = FALSE;
00429
00430 qDebug() << "QVMPlayerReader::closeCam() <- emitting camClosed signal";
00431 emit camClosed();
00432
00433 qDebug() << "QVMPlayerReader::closeCam() <- return";
00434 }
00435
00436 bool QVMPlayerReader::grab(QVImage<uChar,1> & imageGray)
00437 {
00438 qDebug() << "QVMPlayerReader::grab(imageGray)";
00439 if (performGrab())
00440 {
00441 imageGray = imgY;
00442 return TRUE;
00443 }
00444 else
00445 return FALSE;
00446 }
00447
00448 bool QVMPlayerReader::grab(QVImage<uChar,3> & imageRGB)
00449 {
00450 qDebug() << "QVMPlayerReader::grab(imageRGB)";
00451 if (performGrab())
00452 {
00453 imageRGB = QVImage<uChar,3>(imgY.getCols(),imgY.getRows());
00454 YUV420ToRGB(imgY, imgU, imgV, imageRGB);
00455 return TRUE;
00456 }
00457 else
00458 return FALSE;
00459 }
00460
00461 bool QVMPlayerReader::grab(QVImage<uChar> &imageY, QVImage<uChar> &imageU, QVImage<uChar> &imageV)
00462 {
00463 qDebug() << "QVMPlayerReader::grab(imageY, imageU, imageV)";
00464 if (performGrab())
00465 {
00466 imageY = imgY;
00467 imageU = imgU;
00468 imageV = imgV;
00469 return TRUE;
00470 }
00471 else
00472 return FALSE;
00473 }
00474
00475 void QVMPlayerReader::seekCam(TSeekType seek,double d)
00476 {
00477 qDebug() << "QVMPlayerReader::seekCam(" << static_cast<int>(seek) << "," << d << ")";
00478 if(not camera_opened) return;
00479 QString command = QString("pausing_keep seek ") + QString::number(d) + " " + QString::number(seek) + "\n";
00480 mplayer->write(qPrintable(command));
00481 qDebug() << "QVMPlayerReader::seekCam() <~ return";
00482 }