MPlayerWrapper.C

Go to the documentation of this file.
00001 /*!@file Psycho/MPlayerWrapper.C Wrapper class for playing videos in MPlayer */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: John Shen <shenjohn at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/MPlayerWrapper.C $
00035 // $Id: MPlayerWrapper.C 13712 2010-07-28 21:00:40Z itti $
00036 //
00037 
00038 #ifndef PSYCHO_MPLAYERWRAPPER_C_DEFINED
00039 #define PSYCHO_MPLAYERWRAPPER_C_DEFINED
00040 
00041 #include "Psycho/MPlayerWrapper.H"
00042 #include "Component/ComponentOpts.H"
00043 #include "Component/ModelManager.H"
00044 #include "Util/Pause.H"
00045 #include "Util/csignals.H"
00046 #include "Util/Types.H"
00047 #include "GUI/GUIOpts.H"
00048 #include "Util/StringConversions.H"
00049 #include "Util/StringUtil.H"
00050 #include "rutz/pipe.h"
00051 #include "nub/ref.h"
00052 #include "Component/ModelOptionDef.H"
00053 #include <stdlib.h>
00054 #include "Psycho/PsychoDisplay.H"
00055 #include <iostream>
00056 #include <sstream>
00057 #include <string>
00058 #include <stdio.h>
00059 #include <vector>
00060 #include <unistd.h>
00061 
00062 const ModelOptionCateg MOC_MPLAYER = {
00063   MOC_SORTPRI_2, "MPlayer-Related Options" };
00064 
00065 const ModelOptionDef OPT_MPlayerPath =
00066   { MODOPT_ARG_STRING, "MPlayerPath", &MOC_MPLAYER, OPTEXP_CORE,
00067     "Path for the mplayer application.",
00068     "mplayer-path", '\0', "<std::string>", "/usr/bin/mplayer" };
00069 
00070 const ModelOptionDef OPT_MPlayerSound =
00071   { MODOPT_FLAG, "MPlayerSound", &MOC_MPLAYER, OPTEXP_CORE,
00072     "Play sound.", "sound", '\0', "", "true" };
00073 
00074 const ModelOptionDef OPT_MPlayerAudioDriver =
00075   { MODOPT_ARG_STRING, "MPlayerAudioDriver", &MOC_MPLAYER, OPTEXP_CORE,
00076     "Audio driver to send to mplayer.  If sound does not work try alsa/oss.  Other valid options are esd/pulse/jack/nas/sdl/mpegpes/v4l2/pcm.  Setting to null is equivalent to --nosound.", "ao", '\0', "<std::string>", "alsa" };
00077 
00078 const ModelOptionDef OPT_MPlayerCacheSize =
00079   { MODOPT_ARG(uint), "MPlayerCacheSize", &MOC_MPLAYER, OPTEXP_CORE,
00080     "Amount of memory for precaching the video, in kB.",
00081     "cachesize", '\0', "<uint>", "16384"};
00082 
00083 const ModelOptionDef OPT_MPlayerCachePercent =
00084   { MODOPT_ARG(double), "MPlayerCachePercent", &MOC_MPLAYER, OPTEXP_CORE,
00085     "Playback begins when the cache is filled to this percent of the total.",
00086     "cachepercent", '\0', "<0-99>", "50" };
00087 
00088 
00089 MPlayerWrapper::MPlayerWrapper(OptionManager &mgr,
00090                                const std::string& descrName,
00091                                const std::string& tagName) :
00092   ModelComponent(mgr, descrName, tagName),
00093   itsEventLog(),
00094         itsPlayingVideo(false),
00095   itsIsFullScreen(&OPT_SDLdisplayFullscreen, this),
00096   itsMPlayerPath(&OPT_MPlayerPath, this),
00097   itsIsSound(&OPT_MPlayerSound, this),
00098   itsAudioDriver(&OPT_MPlayerAudioDriver, this),
00099   itsCacheSize(&OPT_MPlayerCacheSize, this),
00100   itsCachePercent(&OPT_MPlayerCachePercent, this)
00101 {
00102 }
00103 
00104 // ######################################################################
00105 MPlayerWrapper::~MPlayerWrapper()
00106 {}
00107 
00108 // ######################################################################
00109 void MPlayerWrapper::setSourceVideo(std::string fname)
00110 {
00111   itsFileName = fname;
00112 }
00113 
00114 // ######################################################################
00115 void MPlayerWrapper::pushEvent(const std::string& msg, const bool& useLinfo)
00116 {
00117   if (useLinfo)
00118     LINFO("%s", msg.c_str());
00119   if (itsEventLog.isValid())
00120     itsEventLog->pushEvent(msg);
00121 }
00122 
00123 // ######################################################################
00124 
00125 //display a movie in
00126 int MPlayerWrapper::run(const int argc, const char** argv,
00127                         const char* extraArgsDescription,
00128                         const int minExtraArgs, const int maxExtraArgs)
00129 {
00130   try
00131     {
00132       return this->tryRun(argc, argv, extraArgsDescription,
00133                           minExtraArgs, maxExtraArgs);
00134     }
00135   catch (...)
00136     {
00137       REPORT_CURRENT_EXCEPTION;
00138     }
00139 
00140   return 1;
00141 }
00142 
00143 
00144 // ######################################################################
00145 
00146 //display a movie in mplayer - meant to call through run()
00147 int MPlayerWrapper::tryRun(const int argc, const char** argv,
00148                            const char* extraArgsDescription,
00149                            const int minExtraArgs, const int maxExtraArgs)
00150 {
00151   volatile int signum = 0;
00152   catchsignals(&signum);
00153 
00154   try
00155     {
00156       //playing in mplayer
00157       pushEvent(std::string("===== Playing movie: ") +
00158                 itsFileName + " =====");
00159 
00160       std::string mp_out;
00161       rutz::exec_pipe mphandle("r", itsMPlayerPath.getVal().c_str(), "-fs", itsFileName.c_str(), (const char*) 0);
00162 
00163       bool movie_begun = false;
00164       while(std::getline(mphandle.stream(), mp_out, '\r')) //Read the output from mplayer word by word
00165         {
00166           //when the video starts, the status line reads as
00167           //A:   # V:   # A-V: # ct: #   #/  #   ??% ??% ??,?% 0 0
00168 
00169           movie_begun |= (mp_out.find("A:")!=std::string::npos);
00170 
00171           //send messages through parser
00172           if(movie_begun)
00173             parseStatusLine(mp_out);
00174         }
00175     }
00176   catch (...)
00177     {
00178       fprintf(stderr,"Mplayer initializer failed.\n");
00179     }
00180   //itsManager->stop();
00181 
00182   return 0;
00183 }
00184 
00185 // ######################################################################
00186 
00187 //run a movie while closing an SDL display
00188 //the movie should display seamlessly after the SDL stops
00189 //in reality, mplayer will rush the first few frames regardless.
00190 //also, the timing is inconsistent
00191 
00192 int MPlayerWrapper::runfromSDL(nub::soft_ref<PsychoDisplay> D)
00193 {
00194   try
00195     {
00196       //play movie in mplayer
00197       //create a pipe which sends mplayer output to a stream
00198       //NB: mplayer process inherits SDLpriority
00199       nub::ref<rutz::exec_pipe> mphandle = createMPlayerPipe();
00200       std::string mp_out;
00201 
00202       ModelComponent * displayManager(D->getParent()); //for some reason a nub_ref crashes the program
00203 
00204       bool status_displayed = false, movie_begun = false, display_closed=false;
00205 
00206       //this is the last line before screen displays, e.g.
00207       //VO: [vdpau] 1280x720 => 1920x1080 Planar YV12  [fs]
00208       const std::string firstline = "VO: [";
00209       while(std::getline(mphandle->stream(), mp_out, '\r'))
00210         //Read the output from mplayer line by line
00211         {
00212           status_displayed = (mp_out.find("A:")!=std::string::npos);
00213           movie_begun |= (mp_out.find(firstline)!=std::string::npos);
00214 
00215           //if the status line begins stop the SDL display
00216           if(!display_closed && movie_begun)
00217             {
00218               //there may be a rescaling: need to wait before closing SDL display
00219               pushEvent("===== Movie starting =====");
00220               //const uint delay = 250000; //in microseconds
00221               //usleep(delay);
00222 
00223               //remove D from its manager or close it independently
00224               while(displayManager->hasSubComponent(D) && displayManager != NULL)
00225                 {
00226                   LINFO("removing subcomponent from %s", D->getParent()->tagName().c_str());
00227                   displayManager->removeSubComponent(*D);
00228                   displayManager = D->getParent();
00229                 }
00230               pushEvent("===== Closing PsychoDisplay: " +
00231                         D->descriptiveName() + " =====");
00232               D->stop();
00233               display_closed = true;
00234             }
00235 
00236                                         //loop that runs while movie plays
00237           //send messages through parser
00238           if(status_displayed && movie_begun)
00239             {
00240               //itsEventLog->pushEvent(mp_out.c_str());
00241               parseStatusLine(mp_out);  
00242               itsPlayingVideo = true;
00243             }
00244         }
00245       //after video restart the PsychoDisplay
00246       //displayManager->addSubComponent(D);
00247       itsPlayingVideo = false;
00248       D->start();
00249       D->clearScreen();
00250     }
00251   catch (...)
00252     {
00253       LFATAL("MPlayer initializer failed.");
00254     }
00255 
00256   return 0;
00257 }
00258 
00259 nub::ref<rutz::exec_pipe> MPlayerWrapper::createMPlayerPipe()
00260 {
00261   const uint maxargs = 20;
00262   char** arglist = new(char* [maxargs]);
00263   for (uint i = 0; i < maxargs; i++)
00264     arglist[i] = new char(50);
00265 
00266   int numargs = 0;
00267   //explicit casts b/c the pipe only takes char*
00268 
00269   arglist[numargs++] = (char*) (itsMPlayerPath.getVal()).c_str();
00270   arglist[numargs++] = (char*) itsFileName.c_str();
00271 
00272   //these arguments allow for full screening
00273   if(itsIsFullScreen.getVal())
00274     {
00275       arglist[numargs++] = (char*) "-fs";
00276       arglist[numargs++] = (char*) "-xineramascreen";
00277       arglist[numargs++] = (char*) "0";
00278     }
00279 
00280   if(itsIsSound.getVal()) // sets correct audio output driver
00281     {
00282       arglist[numargs++] = (char*) "-ao";
00283       arglist[numargs++] = (char*) (itsAudioDriver.getVal()).c_str();
00284     }
00285   else //no sound
00286     {
00287       arglist[numargs++] = (char*) "-nosound";
00288     }
00289 
00290   //this argument *SHOULD* get rid of tearing artifacts
00291   //arglist[numargs++] = (char*) "-vsync";
00292 
00293   //trying to get better initial A-V sync
00294   if(0)
00295     {
00296       arglist[numargs++] = (char*) "-autosync";
00297       arglist[numargs++] = (char*) "30";
00298     }
00299   if(0) //allowing dropped frames
00300     {
00301       //this allows framedropping for slower displays
00302       arglist[numargs++] = (char*) "-framedrop";
00303     }
00304 
00305   //&OPT_InputMPEGStreamPreload is the OModelParam<bool> for this
00306   if(itsCacheSize.getVal() > 0) //caching
00307     {
00308       //this sets the cache size
00309       arglist[numargs++] = (char*) "-cache";
00310       std::string cacheStr = toStr<int>(itsCacheSize.getVal());
00311       arglist[numargs++] = (char*) cacheStr.c_str();
00312 
00313       //this precaches a certain % of the video
00314       arglist[numargs++] = (char*) "-cache-min";
00315       std::string percentStr = toStr<double>(itsCachePercent.getVal());
00316       arglist[numargs++] = (char*) percentStr.c_str();
00317 
00318    }
00319 
00320   arglist[numargs] = (char*) 0; //null-terminate
00321   for(int i = 0; arglist[i]!=NULL; i++)
00322        LINFO("arg %d: \"%s\"", i, arglist[i]);
00323    return nub::ref<rutz::exec_pipe>(new rutz::exec_pipe("r", arglist));
00324 }
00325 
00326 void MPlayerWrapper::parseStatusLine(const std::string stat_line)
00327 {
00328   //parse status line with sscanf...
00329   //A:   # V:   # A-V: # ct: #   #/  #   ??% ??% ??.?% 0 0
00330   unsigned int num_frames = 1, num_dropped = 0;
00331   static unsigned int num_prev_dropped = 0;
00332   double t_video = 0;
00333 
00334   if(sscanf(stat_line.c_str(),"A: %*f V: %lf A-V: %*f ct: %*f %u/%*u %*s %*s %*s %u %*u",
00335             &t_video, &num_frames, &num_dropped)==EOF)
00336     pushEvent("Status line error");
00337   else //if status line is correctly read
00338     {
00339       //for the start of each video, restart dropped frame count
00340       if(num_frames == 1) num_prev_dropped = 0;
00341 
00342       //see if the number of dropped frames so far increased
00343       if(num_dropped > num_prev_dropped)
00344         {
00345           pushEvent("MPlayerWrapper - " + toStr<int>(num_dropped - num_prev_dropped) + " frames dropped");
00346           num_prev_dropped = num_dropped;
00347         }
00348       //account for drop frames, start frame index from 0
00349                         //NB: sometimes counter will report back to frame 0 - we prevent this from happening here:
00350                         if(!(num_frames==1 && itsPlayingVideo))
00351                         pushEvent("MPlayerWrapper - frame " + toStr<int>(num_frames + num_dropped-1)
00352                 + " at time " + toStr<double>(t_video));
00353     }
00354 
00355 }
00356 
00357 #endif
00358 // PSYCHO_MPLAYERWRAPPER_C_DEFINED
Generated on Sun May 8 08:05:32 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3