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 initMPlayerArgs(urlstring, suggested_cols, suggested_rows);
00272 mplayer->start(MPLAYER_BINARY_PATH, mplayer_args);
00273 qDebug() << "QVMPlayerReader::openCam(): after mplayer->start()";
00274 if(not mplayer->waitForStarted(1000))
00275 qFatal("Mplayer failed to start in a second: Are you sure it is installed and in the correct PATH?");
00276 qDebug() << "QVMPlayerReader::openCam(): after mplayer->waitForstarted()";
00277
00278
00279
00280 qDebug() << "QVMPlayerReader::openCam(): opening fifo " << qPrintable(namedPipe->getOutputFilePath());
00281 fifoInput.setFileName(namedPipe->getOutputFilePath());
00282 if(fifoInput.open(QIODevice::ReadWrite|QIODevice::Unbuffered) == -1)
00283 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00284 qDebug() << "QVMPlayerReader::openCam(): fifo opened";
00285
00286
00287
00288
00289
00290 const uInt waitMilisecs = ( schema == "http" or schema == "ftp" or
00291 schema == "rtsp" or schema == "dvd" or
00292 schema == "vcd" )? 10000:2000;
00293 QVCheckOKMPlayer check_thread(fifoInput, waitMilisecs);
00294
00295 qDebug()<< "QVMPlayerReader::openCam(): going to read YUV header";
00296
00297 if (!readYUV4MPEG2Header(fifoInput, cols, rows, fps))
00298 {
00299 qWarning() << "QVMPlayerReader::openCam(): Warning: Mplayer could not open the requested video source ("
00300 << qPrintable(urlstring) << ") of type " << qPrintable(schema);
00301 qDebug() << "QVMPlayerReader::openCam(): Terminating and killing mplayer";
00302 mplayer->terminate();
00303 if (not mplayer->waitForFinished(500)) mplayer->kill();
00304 qDebug() << "QVMPlayerReader::openCam(): Deleting pipe and mplayer";
00305 delete namedPipe;
00306 delete mplayer;
00307 qDebug() << "QVMPlayerReader::openCam(): closing fifo";
00308 fifoInput.close();
00309
00310 while(not check_thread.isFinished())
00311 {
00312 qDebug() << "QVMPlayerReader::openCam(): quitting guarding thread (incorrect mplayer launch)";
00313 check_thread.quit();
00314 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread quitted after correct launch of mplayer";
00315 check_thread.wait(100);
00316 }
00317 qDebug() << "QVMPlayerReader::openCam(): guarding thread finished after incorrect launch of mplayer";
00318 qDebug() << "QVMPlayerReader::openCam(): Returning FALSE";
00319 cols = 0;
00320 rows = 0;
00321 fps = 0;
00322 frames_grabbed = 0;
00323 camera_opened = FALSE;
00324 return FALSE;
00325 }
00326 qDebug()<< "QVMPlayerReader::openCam(): back from read YUV header: cols = " << cols << " rows = " << rows << ", fps = " << fps;
00327
00328
00329 while(not check_thread.isFinished())
00330 {
00331 qDebug() << "QVMPlayerReader::openCam(): quitting guarding thread (correct mplayer launch)";
00332 check_thread.quit();
00333 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread quitted after correct launch of mplayer";
00334 check_thread.wait(100);
00335 }
00336 qDebug() << "QVMPlayerReader::openCam(): CheckOKMPlayerCamera thread finished after correct launch of mplayer";
00337
00338
00339
00340
00341
00342
00343 QFile fifoAux;
00344 fifoAux.setFileName(namedPipe->getOutputFilePath());
00345 fifoAux.open(QIODevice::ReadOnly);
00346 fifoInput.close();
00347
00348 if(fifoInput.open(QIODevice::ReadOnly|QIODevice::Unbuffered) == -1)
00349 qFatal("Error opening fifo %s\n", qPrintable(namedPipe->getOutputFilePath()));
00350 fifoAux.close();
00351
00352 qDebug() << "QVMPlayerReader::openCam(): Header correctly read: cols = "
00353 << cols << ", rows = " << rows << ", fps = " << fps;
00354
00355
00356 frames_grabbed = 0;
00357 camera_opened = TRUE;
00358
00359
00360 imgY = QVImage<uChar>(cols, rows, iRoundUp(cols,8));
00361 imgU = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00362 imgV = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00363
00364
00365
00366
00367
00368 qDebug() << "QVMPlayerReader::openCam() <- sending get_time_length command to mplayer";
00369 mplayer->write("get_time_length\n");
00370 mplayer->waitForReadyRead();
00371
00372 qDebug() << "QVMPlayerReader::openCam() <- emitting camOpened signal";
00373 emit camOpened();
00374
00375 qDebug() << "QVMPlayerReader::openCam() <- return";
00376 return TRUE;
00377 }
00378
00379 void QVMPlayerReader::closeCam()
00380 {
00381 qDebug() << "QVMPlayerReader::closeCam()";
00382
00383 if (not camera_opened)
00384 {
00385 qDebug() << "QVMPlayerReader::closeCam(): camera already closed. Returning";
00386 return;
00387 }
00388
00389 qDebug() << "QVMPlayerReader::closeCam(): closing fifo";
00390 fifoInput.close();
00391
00392 if(not end_of_video)
00393 {
00394 qDebug() << "QVMPlayerReader::closeCam(): going to send quit command to mplayer";
00395 mplayer->write("quit\n");
00396 }
00397 qDebug() << "QVMPlayerReader::closeCam(): going to terminate mplayer";
00398 mplayer->terminate();
00399 qDebug() << "QVMPlayerReader::closeCam(): going to kill mplayer";
00400 mplayer->kill();
00401 qDebug() << "QVMPlayerReader::closeCam(): going to wait for mplayer to finish";
00402 mplayer->waitForFinished();
00403 qDebug() << "QVMPlayerReader::closeCam(): mplayer finished";
00404
00405 qDebug() << "QVMPlayerReader::closecam(): deleting namedpipe";
00406 delete namedPipe;
00407
00408 qDebug() << "QVMPlayerReader::closecam(): deleting QProcess mplayer";
00409 delete mplayer;
00410
00411
00412 open_options = Default;
00413 path = QString();
00414 schema = QString();
00415 camera_opened = FALSE;
00416 frames_grabbed = 0;
00417 live_camera = FALSE;
00418 imgY = QVImage<uChar>();
00419 imgU = QVImage<uChar>();
00420 imgV = QVImage<uChar>();
00421 cols = 0;
00422 rows = 0;
00423 fps = 0;
00424 time_length = 0;
00425 time_pos = 0;
00426 end_of_video = FALSE;
00427
00428 qDebug() << "QVMPlayerReader::closeCam() <- emitting camClosed signal";
00429 emit camClosed();
00430
00431 qDebug() << "QVMPlayerReader::closeCam() <- return";
00432 }
00433
00434 bool QVMPlayerReader::grab(QVImage<uChar,1> & imageGray)
00435 {
00436 qDebug() << "QVMPlayerReader::grab(imageGray)";
00437 if (performGrab())
00438 {
00439 imageGray = imgY;
00440 return TRUE;
00441 }
00442 else
00443 return FALSE;
00444 }
00445
00446 bool QVMPlayerReader::grab(QVImage<uChar,3> & imageRGB)
00447 {
00448 qDebug() << "QVMPlayerReader::grab(imageRGB)";
00449 if (performGrab())
00450 {
00451 imageRGB = QVImage<uChar,3>(imgY.getCols(),imgY.getRows());
00452 YUV420ToRGB(imgY, imgU, imgV, imageRGB);
00453 return TRUE;
00454 }
00455 else
00456 return FALSE;
00457 }
00458
00459 bool QVMPlayerReader::grab(QVImage<uChar> &imageY, QVImage<uChar> &imageU, QVImage<uChar> &imageV)
00460 {
00461 qDebug() << "QVMPlayerReader::grab(imageY, imageU, imageV)";
00462 if (performGrab())
00463 {
00464 imageY = imgY;
00465 imageU = imgU;
00466 imageV = imgV;
00467 return TRUE;
00468 }
00469 else
00470 return FALSE;
00471 }
00472
00473 void QVMPlayerReader::seekCam(TSeekType seek,double d)
00474 {
00475 qDebug() << "QVMPlayerReader::seekCam(" << static_cast<int>(seek) << "," << d << ")";
00476 if(not camera_opened) return;
00477 QString command = QString("pausing_keep seek ") + QString::number(d) + " " + QString::number(seek) + "\n";
00478 mplayer->write(qPrintable(command));
00479 qDebug() << "QVMPlayerReader::seekCam() <~ return";
00480 }