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 live_camera = TRUE;
00137 mplayer_args << urlString;
00138 } else
00139 {
00140
00141 if(schema == "rtsp")
00142 live_camera = TRUE;
00143 else
00144 live_camera = FALSE;
00145 if (schema != "")
00146 mplayer_args << QString(schema + "://" + path);
00147 else
00148 mplayer_args << path;
00149 }
00150
00151
00152
00153 QString aux;
00154
00155
00156 if(open_options & Deinterlaced) aux = "pp=md";
00157
00158
00159 if(suggested_cols != 0 and suggested_rows != 0)
00160 {
00161 if(aux != QString())
00162 aux += QString(",scale=%1:%2").arg(suggested_cols).arg(suggested_rows);
00163 else
00164 aux = QString("scale=%1:%2").arg(suggested_cols).arg(suggested_rows);
00165 }
00166 if (aux != QString()) mplayer_args << "-vf" << aux;
00167
00168
00169 if(not (open_options & RealTime))
00170 {
00171 if(not live_camera)
00172 mplayer_args << "-benchmark";
00173 }
00174
00175
00176 mplayer_args << "-slave" << "-quiet" << "-nosound" << "-vo" << QString("yuv4mpeg:file=%1").arg(namedPipe->getInputFilePath());
00177
00178 qDebug() << "QVMPlayerReader::initMPlayerArgs(): MPlayer args = " << mplayer_args;
00179 qDebug() << "QVMPlayerReader::initMPlayerArgs() <- return";
00180 }
00181
00182 int QVMPlayerReader::interpretMPlayerOutput()
00183 {
00184 int length = -1;
00185 char buf[1024];
00186
00187 length = mplayer->readLine(buf, sizeof(buf));
00188
00189 if (length == -1)
00190 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): length == -1";
00191 else {
00192 QString str(buf);
00193 QStringList variables = str.simplified().split("=");
00194 QStringList palabras = str.simplified().split(" ");
00195
00196 if(variables[0] == "ANS_LENGTH")
00197 {
00198 time_length = variables[1].toDouble();
00199 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): updating time_length =" << time_length;
00200 }
00201 else if(variables[0] == "ANS_TIME_POSITION")
00202 {
00203 time_pos = variables[1].toDouble();
00204 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): updating time_pos =" << time_pos;
00205 }
00206 else
00207 qDebug() << "QVMPlayerReader::interpretMPlayerOutput(): uninterpreted mplayer output:" << str;
00208 }
00209 qDebug() << "QVMPlayerReader::interpretMPlayerOutput() <- return " << length;
00210 return length;
00211 }
00212
00213 bool QVMPlayerReader::performGrab()
00214 {
00215 qDebug() << "QVMPlayerReader::performGrab()";
00216
00217 if (not camera_opened)
00218 {
00219 qDebug() << "QVMPlayerReader::performGrab() returns FALSE (camera is closed)";
00220 return false;
00221 }
00222
00223 qDebug() << "QVMPlayerReader::performGrab(): sending command get_time_pos to mplayer";
00224 mplayer->write("pausing_keep get_time_pos\n");
00225
00226
00227 qDebug() << "QVMPlayerReader::performGrab: reading YUV frame: readYUV4MPEG2Frame()";
00228 if (!readYUV4MPEG2Frame(fifoInput, imgY, imgU, imgV))
00229 {
00230 qDebug() << "QVMPlayerReader::performGrab: No more frames left, closing camera";
00231 end_of_video = TRUE;
00232 close();
00233 qDebug() << "QVMPlayerReader::performGrab: No more frames left, camera closed, returning false";
00234 return FALSE;
00235 }
00236
00237 frames_grabbed++;
00238 qDebug() << "QVMPlayerReader::performGrab: new frame read (" << frames_grabbed << ")";
00239
00240
00241 qDebug() << "QVMPlayerReader::performGrab: now interpreting mplayer output";
00242 while(interpretMPlayerOutput() > 0);
00243
00244 qDebug() << "QVMPlayerReader::performGrab: emitting newGrab() signal";
00245 emit newGrab();
00246
00247 qDebug() << "QVMPlayerReader::performGrab() <- returning TRUE";
00248 return TRUE;
00249 }
00250
00251 static inline int iRoundUp(int a, int b) {
00252 return (a % b == 0) ? a : b*(a / b + 1) ;
00253 }
00254
00255 bool QVMPlayerReader::open(const QString & urlstring, OpenOptions opts, unsigned int suggested_cols, unsigned int suggested_rows)
00256 {
00257 qDebug() << "QVMPlayerReader::open(" << qPrintable(urlstring) << "," << static_cast<int>(opts) << ","
00258 << suggested_cols << "," << suggested_rows << "," << opts << ")";
00259
00260 if (camera_opened)
00261 {
00262 qDebug() << "QVMPlayerReader::open() <- closing previously opened camera";
00263 close();
00264 qDebug() << "QVMPlayerReader::open() <- previously opened camera closed";
00265 }
00266
00267 open_options = opts;
00268
00269
00270 namedPipe = new QNamedPipe(QString("mplayer"));
00271 qDebug() << "QVMPlayerReader::open(): Named pipe created" << namedPipe->getOutputFilePath();
00272
00273
00274 mplayer = new QProcess;
00275 mplayer->setParent(this);
00276 mplayer->moveToThread(this->thread());
00277 initMPlayerArgs(urlstring, suggested_cols, suggested_rows);
00278 mplayer->start(MPLAYER_BINARY_PATH, mplayer_args);
00279 qDebug() << "QVMPlayerReader::open(): after mplayer->start()";
00280 if(not mplayer->waitForStarted(1000))
00281 qFatal("Mplayer failed to start in a second: Are you sure it is installed and in the correct PATH?");
00282 qDebug() << "QVMPlayerReader::open(): after mplayer->waitForstarted()";
00283
00284
00285
00286 qDebug() << "QVMPlayerReader::open(): opening fifo " << qPrintable(namedPipe->getOutputFilePath());
00287 fifoInput.setFileName(namedPipe->getOutputFilePath());
00288 if(fifoInput.open(QIODevice::ReadWrite|QIODevice::Unbuffered) == -1)
00289 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00290 qDebug() << "QVMPlayerReader::open(): fifo opened";
00291
00292
00293
00294
00295
00296 const uInt waitMilisecs = ( schema == "http" or schema == "ftp" or
00297 schema == "rtsp" or schema == "dvd" or
00298 schema == "vcd" or schema == "dvb" ) ? 20000:2000;
00299
00300 QVCheckOKMPlayer check_thread(fifoInput, waitMilisecs);
00301
00302 qDebug()<< "QVMPlayerReader::open(): going to read YUV header";
00303
00304 if (!readYUV4MPEG2Header(fifoInput, cols, rows, fps))
00305 {
00306 qWarning() << "QVMPlayerReader::open(): Warning: Mplayer could not open the requested video source ("
00307 << qPrintable(urlstring) << ") of type " << qPrintable(schema);
00308 qDebug() << "QVMPlayerReader::open(): Terminating and killing mplayer";
00309 mplayer->terminate();
00310 if (not mplayer->waitForFinished(500)) mplayer->kill();
00311 qDebug() << "QVMPlayerReader::open(): Deleting pipe and mplayer";
00312 delete namedPipe;
00313 delete mplayer;
00314 qDebug() << "QVMPlayerReader::open(): closing fifo";
00315 fifoInput.close();
00316
00318
00319
00320
00321
00322
00323
00324
00325 qDebug() << "QVMPlayerReader::open(): quitting guarding thread";
00326 do check_thread.quit();
00327 while (not check_thread.wait(100));
00328 qDebug() << "QVMPlayerReader::open(): CheckOKMPlayerCamera thread quitted";
00329 qDebug() << "QVMPlayerReader::open(): Returning FALSE";
00330 cols = 0;
00331 rows = 0;
00332 fps = 0;
00333 frames_grabbed = 0;
00334 camera_opened = FALSE;
00335 return FALSE;
00336 }
00337 qDebug()<< "QVMPlayerReader::open(): back from read YUV header: cols = " << cols << " rows = " << rows << ", fps = " << fps;
00338
00339
00341
00342
00343
00344
00345
00346
00347
00348 qDebug() << "QVMPlayerReader::open(): quitting guarding thread";
00349 do check_thread.quit();
00350 while (not check_thread.wait(100));
00351 qDebug() << "QVMPlayerReader::open(): CheckOKMPlayerCamera thread finished after correct launch of mplayer";
00352
00353
00354
00355
00356
00357
00358 QFile fifoAux;
00359 fifoAux.setFileName(namedPipe->getOutputFilePath());
00360 fifoAux.open(QIODevice::ReadOnly);
00361 fifoInput.close();
00362
00363 if(fifoInput.open(QIODevice::ReadOnly|QIODevice::Unbuffered) == -1)
00364 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00365 fifoAux.close();
00366
00367 qDebug() << "QVMPlayerReader::open(): Header correctly read: cols = "
00368 << cols << ", rows = " << rows << ", fps = " << fps;
00369
00370
00371 frames_grabbed = 0;
00372 camera_opened = TRUE;
00373
00374
00375 imgY = QVImage<uChar>(cols, rows, iRoundUp(cols,8));
00376 imgU = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00377 imgV = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00378
00379
00380
00381
00382
00383 qDebug() << "QVMPlayerReader::open() <- sending get_time_length command to mplayer";
00384 mplayer->write("get_time_length\n");
00385 mplayer->waitForReadyRead();
00386
00387 qDebug() << "QVMPlayerReader::open() <- emitting camOpened signal";
00388 emit camOpened();
00389
00390 qDebug() << "QVMPlayerReader::open() <- return";
00391 return TRUE;
00392 }
00393
00394 void QVMPlayerReader::close()
00395 {
00396 qDebug() << "QVMPlayerReader::close()";
00397
00398 if (not camera_opened)
00399 {
00400 qDebug() << "QVMPlayerReader::close(): camera already closed. Returning";
00401 return;
00402 }
00403
00404 qDebug() << "QVMPlayerReader::close(): closing fifo";
00405 fifoInput.close();
00406
00407 if(not end_of_video)
00408 {
00409 qDebug() << "QVMPlayerReader::close(): going to send quit command to mplayer";
00410 mplayer->write("quit\n");
00411 }
00412 qDebug() << "QVMPlayerReader::close(): going to terminate mplayer";
00413 mplayer->terminate();
00414 qDebug() << "QVMPlayerReader::close(): going to kill mplayer";
00415 mplayer->kill();
00416 qDebug() << "QVMPlayerReader::close(): going to wait for mplayer to finish";
00417 mplayer->waitForFinished();
00418 qDebug() << "QVMPlayerReader::close(): mplayer finished";
00419
00420 qDebug() << "QVMPlayerReader::closecam(): deleting namedpipe";
00421 delete namedPipe;
00422
00423 qDebug() << "QVMPlayerReader::closecam(): deleting QProcess mplayer";
00424 delete mplayer;
00425
00426
00427 open_options = Default;
00428 path = QString();
00429 schema = QString();
00430 camera_opened = FALSE;
00431 frames_grabbed = 0;
00432 live_camera = FALSE;
00433 imgY = QVImage<uChar>();
00434 imgU = QVImage<uChar>();
00435 imgV = QVImage<uChar>();
00436 cols = 0;
00437 rows = 0;
00438 fps = 0;
00439 time_length = 0;
00440 time_pos = 0;
00441 end_of_video = FALSE;
00442
00443 qDebug() << "QVMPlayerReader::close() <- emitting camClosed signal";
00444 emit camClosed();
00445
00446 qDebug() << "QVMPlayerReader::close() <- return";
00447 }
00448
00449 bool QVMPlayerReader::grab(QVImage<uChar,1> & imageGray)
00450 {
00451 qDebug() << "QVMPlayerReader::grab(imageGray)";
00452 if (performGrab())
00453 {
00454 imageGray = imgY;
00455 return TRUE;
00456 }
00457 else
00458 return FALSE;
00459 }
00460
00461 bool QVMPlayerReader::grab(QVImage<uChar,3> & imageRGB)
00462 {
00463 qDebug() << "QVMPlayerReader::grab(imageRGB)";
00464 if (performGrab())
00465 {
00466 imageRGB = QVImage<uChar,3>(imgY.getCols(),imgY.getRows());
00467 YUV420ToRGB(imgY, imgU, imgV, imageRGB);
00468 return TRUE;
00469 }
00470 else
00471 return FALSE;
00472 }
00473
00474 bool QVMPlayerReader::grab(QVImage<uChar> &imageY, QVImage<uChar> &imageU, QVImage<uChar> &imageV)
00475 {
00476 qDebug() << "QVMPlayerReader::grab(imageY, imageU, imageV)";
00477 if (performGrab())
00478 {
00479 imageY = imgY;
00480 imageU = imgU;
00481 imageV = imgV;
00482 return TRUE;
00483 }
00484 else
00485 return FALSE;
00486 }
00487
00488 void QVMPlayerReader::seekCam(TSeekType seek,double d)
00489 {
00490 qDebug() << "QVMPlayerReader::seekCam(" << static_cast<int>(seek) << "," << d << ")";
00491 if(not camera_opened) return;
00492 QString command = QString("pausing_keep seek ") + QString::number(d) + " " + QString::number(seek) + "\n";
00493 mplayer->write(qPrintable(command));
00494 qDebug() << "QVMPlayerReader::seekCam() <~ return";
00495 }