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