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