RTSPGrabber.C

Go to the documentation of this file.
00001 /*!@file Devices/RTSPGrabber.C video stream grabber froman rtsp source using LiveMedia */
00002 
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Lior Elazary
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/RTSPGrabber.C $
00036 // $Id: RTSPGrabber.C 12962 2010-03-06 02:13:53Z irock $
00037 //
00038 
00039 #include "Devices/RTSPGrabber.H"
00040 
00041 #include "Component/OptionManager.H" // for option alias requests
00042 #include "Component/ModelOptionDef.H"
00043 #include "Devices/DeviceOpts.H"
00044 #include "Image/Image.H"
00045 #include "Image/Pixels.H"
00046 #include "Image/MathOps.H"
00047 #include "Raster/GenericFrame.H"
00048 #include "Util/Assert.H"
00049 #include "Util/SimTime.H"
00050 #include "Util/sformat.H"
00051 #include "Video/VideoFrame.H"
00052 #include "Video/FfmpegFrame.H"
00053 
00054 
00055 #ifdef INVT_HAVE_LIVEMEDIA
00056 #include <groupsock/GroupsockHelper.hh>
00057 #endif
00058 
00059 #include <unistd.h>
00060 
00061 #ifdef INVT_HAVE_LIVEMEDIA
00062 void sessionAfterPlaying(void* /*clientData*/) {
00063    LINFO("Sesstion after playing\n");
00064 }
00065 
00066 static void getFrame(void *clientData, unsigned frameSize,
00067     unsigned, struct timeval pTime, unsigned)
00068 {
00069   RTSPGrabber* rtspGrabber = (RTSPGrabber*)clientData;
00070 
00071   if (frameSize > rtspGrabber->getFrameBufferSize())
00072     LINFO("Frame buffer size to small, please increase (framesize %i)",
00073         frameSize);
00074 
00075   rtspGrabber->itsFrameSize = frameSize;
00076   rtspGrabber->blockingFlag = ~0;
00077 }
00078 
00079 static void onSourceClosure(void* clientData)
00080 {
00081   RTSPGrabber* rtspGrabber = (RTSPGrabber*)clientData;
00082   LINFO("On source closure\n");
00083   rtspGrabber->blockingFlag = ~0;
00084 }
00085 #endif
00086 
00087 
00088 
00089 // ######################################################################
00090 void* RTSPGrabber_run(void *r0)
00091 {
00092   RTSPGrabber *r = (RTSPGrabber *)r0;
00093   r->run(); return NULL;
00094 }
00095 
00096 // ######################################################################
00097 RTSPGrabber::RTSPGrabber(OptionManager& mgr,
00098                                  const std::string& descrName,
00099                                  const std::string& tagName,
00100                                  const ParamFlag flags,
00101                                  unsigned int bufferSize) :
00102   FrameIstream(mgr, descrName, tagName),
00103   itsDims(&OPT_FrameGrabberDims, this, Dims(320, 240), USE_MY_VAL),
00104   itsGrabMode(&OPT_FrameGrabberMode, this, VIDFMT_RGB24, USE_MY_VAL),
00105   itsByteSwap(&OPT_FrameGrabberByteSwap, this, false, USE_MY_VAL),
00106   itsWhiteBalTarR(&OPT_FrameGrabberWhiteBalTargetR, this, false, USE_MY_VAL),
00107   itsWhiteBalTarG(&OPT_FrameGrabberWhiteBalTargetG, this, false, USE_MY_VAL),
00108   itsWhiteBalTarB(&OPT_FrameGrabberWhiteBalTargetB, this, false, USE_MY_VAL),
00109   itsWhiteBalRefR(&OPT_FrameGrabberWhiteBalReferenceR, this, false, USE_MY_VAL),
00110   itsWhiteBalRefG(&OPT_FrameGrabberWhiteBalReferenceG, this, false, USE_MY_VAL),
00111   itsWhiteBalRefB(&OPT_FrameGrabberWhiteBalReferenceB, this, false, USE_MY_VAL),
00112   itsFPS(&OPT_FrameGrabberFPS, this, 15.0, USE_MY_VAL),
00113   itsFrameBufferSize(bufferSize),
00114   itsFrameBuffer(new unsigned char[bufferSize]),
00115   itsThreadRunning(false)
00116 {
00117   pthread_mutex_init(&itsLock, NULL);
00118 
00119 #ifdef INVT_HAVE_AVCODEC
00120 
00121   // no need to guard these functions for being called multiple times;
00122   // they all have internal guards
00123   av_register_all();
00124 
00125   //init ffmpeg
00126   avcodec_init();
00127 
00128   // register all the codecs
00129   avcodec_register_all();
00130 
00131   itsCodecContext = avcodec_alloc_context();
00132 
00133   AVCodec* codec = avcodec_find_decoder(CODEC_ID_MPEG4 );
00134 
00135   if (codec == 0) LFATAL("no codec found for codec_id=%d", CODEC_ID_MPEG4);
00136 
00137   if (!codec || avcodec_open(itsCodecContext, codec) < 0) LFATAL("avcodec_open() failed");
00138 
00139 #if defined(INVT_FFMPEG_HAS_DEFAULTS_FUNCTIONS)
00140   avcodec_get_frame_defaults(&itsPicture);
00141 #else
00142   {
00143     AVFrame* tmp = avcodec_alloc_frame();
00144     memcpy(&itsPicture, tmp, sizeof(AVFrame));
00145     av_free(tmp);
00146   }
00147 #endif
00148 
00149   Image<PixRGB<byte> > frame(itsDims.getVal(), NO_INIT);
00150   itsCurrentFrame = VideoFrame(frame);
00151 #endif
00152 }
00153 
00154 // ######################################################################
00155 void RTSPGrabber::start1()
00156 {
00157 #ifndef INVT_HAVE_LIVEMEDIA
00158   LFATAL("you must have liveMedia support in order to use RTSPGrabber");
00159 #else
00160   LINFO("URL %s", itsURL.c_str());
00161   TaskScheduler* scheduler = BasicTaskScheduler::createNew();
00162   itsEnv = BasicUsageEnvironment::createNew(*scheduler);
00163   itsClient = RTSPClient::createNew(*itsEnv,
00164       0, //verbosity level
00165       "test", //prog name
00166       0);
00167 
00168   if (itsClient == NULL)
00169     LFATAL("Failed to create client\n");
00170 
00171   itsRTSPClient = (RTSPClient*)itsClient;
00172   char* optionsResponse = itsRTSPClient->sendOptionsCmd(itsURL.c_str(), NULL, NULL);
00173   LINFO("%s", optionsResponse);
00174 
00175   char* sdpDescription = itsRTSPClient->describeURL(itsURL.c_str());
00176   if (sdpDescription == NULL) {
00177     Medium::close(itsClient);
00178     LFATAL("Failed to get a SDP description from URL %s", itsEnv->getResultMsg());
00179   }
00180   LINFO("SDP desc: %s", sdpDescription);
00181 
00182   itsSession = MediaSession::createNew(*itsEnv, sdpDescription);
00183   delete[] sdpDescription;
00184 
00185   if (itsSession == NULL)
00186   {
00187     Medium::close(itsClient);
00188     LFATAL("Failed to create a MediaSession object from the SDP description: %s ", itsEnv->getResultMsg());
00189   } else if (!itsSession->hasSubsessions()) {
00190     Medium::close(itsClient);
00191     LFATAL("This session has no media subsessions (i.e., \"m=\" lines)");
00192   }
00193 
00194   //setup sub sessions
00195   MediaSubsessionIterator iter(*itsSession);
00196   MediaSubsession *subsession;
00197   while ((subsession = iter.next()) != NULL) {
00198 
00199     //get only video
00200     //TODO add audio as well
00201     if (strcmp(subsession->mediumName(), "video") != 0) {
00202       LINFO("Ignoring %s/%s", subsession->mediumName(), subsession->codecName());
00203       continue;
00204     }
00205 
00206 
00207     if (!subsession->initiate(-1)) {
00208       LINFO("Unable to create receiver for %s/%s %s",
00209           subsession->mediumName(),
00210           subsession->codecName(),
00211           itsEnv->getResultMsg());
00212     } else {
00213       LINFO("Created receiver for %s/%s port %i",
00214           subsession->mediumName(),
00215           subsession->codecName(),
00216           subsession->clientPortNum());
00217 
00218       if (subsession->readSource() != NULL)
00219         itsFramedSource = subsession->readSource();
00220 
00221       if (subsession->rtpSource() != NULL) {
00222         // Because we're saving the incoming data, rather than playing
00223         // it in real time, allow an especially large time threshold
00224         // (1 second) for reordering misordered incoming packets:
00225         unsigned const thresh = 1000000; // 1 second
00226         subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
00227 
00228         unsigned int socketInputBufferSize = 20000;
00229         if (socketInputBufferSize > 0) {
00230           // Set the RTP source's input buffer size as specified:
00231           int socketNum
00232             = subsession->rtpSource()->RTPgs()->socketNum();
00233           unsigned curBufferSize
00234             = getReceiveBufferSize(*itsEnv, socketNum);
00235           unsigned newBufferSize
00236             = setReceiveBufferTo(*itsEnv, socketNum, socketInputBufferSize);
00237           LINFO("Changed socket receive buffer size for the %s/%s cur=%i bytes new=%i bytes",
00238               subsession->mediumName(),
00239               subsession->codecName(),
00240               curBufferSize,  newBufferSize);
00241         }
00242       }
00243 
00244       Boolean streamUsingTCP = False;
00245       if (!itsRTSPClient->setupMediaSubsession(*subsession, false, streamUsingTCP)) {
00246         LINFO("Failed to setup %s/%s  %s",
00247             subsession->mediumName(), subsession->codecName(),
00248             itsEnv->getResultMsg());
00249       } else {
00250         LINFO("Setup %s/%s port %i",
00251             subsession->mediumName(),  subsession->codecName(),
00252             subsession->clientPortNum());
00253       }
00254     }
00255   }
00256 
00257   if(!itsRTSPClient->playMediaSession(*itsSession))
00258     LINFO("Can not play %s", itsEnv->getResultMsg());
00259 
00260 
00261   // start the capture thread
00262   // start thread for run():
00263   pthread_create(&itsRunThread, NULL, &RTSPGrabber_run, (void *)this);
00264 
00265 #endif
00266 }
00267 
00268 // ######################################################################
00269 void RTSPGrabber::run()
00270 {
00271 #ifndef INVT_HAVE_LIVEMEDIA
00272   LFATAL("you must have liveMedia support in order to use RTSPGrabber");
00273 #else
00274 
00275   itsThreadRunning = true;
00276 
00277   while(itsThreadRunning)
00278   {
00279 
00280     //Grab the frame
00281     blockingFlag = 0;
00282     itsFrameSize = 0;
00283     itsFramedSource->getNextFrame(itsFrameBuffer, itsFrameBufferSize,
00284         getFrame, this,
00285         onSourceClosure,this);
00286 
00287     //block untill data becomes available
00288     TaskScheduler& scheduler = itsFramedSource->envir().taskScheduler();
00289     scheduler.doEventLoop(&blockingFlag);
00290 
00291     //convert the frame
00292     if (itsFrameSize > 0)
00293     {
00294       pthread_mutex_lock(&itsLock);
00295 
00296       //usleep(50000);
00297       int len = avcodec_decode_video(itsCodecContext,
00298           &itsPicture, &itsGotPicture,
00299           itsFrameBuffer, itsFrameSize);
00300       (void)len; //to avoid compiler warning;
00301 
00302       itsCurrentFrame =  convertAVFrameToVideoFrame(&itsPicture,
00303           itsCodecContext->pix_fmt,
00304           itsDims.getVal());
00305       itsGotPicture = 0;
00306 
00307       pthread_mutex_unlock(&itsLock);
00308     }
00309     usleep(10000);
00310   }
00311 
00312 
00313   pthread_exit(0);
00314 #endif
00315 }
00316 
00317 
00318 
00319 // ######################################################################
00320 void RTSPGrabber::setConfigInfo(const std::string& url)
00321 {
00322 //  if (url[0] == '/') //skip the // if nedded
00323 //    itsURL.setVal(url.substr(2));
00324 //  else
00325 //    itsURL.setVal(url);
00326 
00327   itsURL = std::string("rtsp:") + url;
00328 
00329 }
00330 
00331 // ######################################################################
00332 void RTSPGrabber::shutdown()
00333 {
00334   itsThreadRunning = false;
00335 
00336   if (0 != pthread_join(itsRunThread, NULL)) LERROR("Pthread__join() failed");
00337   LINFO("Disconnecting from stream");
00338 
00339 #ifdef INVT_HAVE_LIVEMEDIA
00340   //close
00341   MediaSubsessionIterator iter(*itsSession);
00342   MediaSubsession* subsession;
00343   while ((subsession = iter.next()) != NULL) {
00344     Medium::close(subsession->sink);
00345     subsession->sink = NULL;
00346   }
00347 
00348   itsRTSPClient->teardownMediaSession(*itsSession);
00349   Medium::close(itsSession);
00350   Medium::close(itsClient);
00351 #endif
00352 }
00353 
00354 // ######################################################################
00355 void RTSPGrabber::stop2()
00356 {
00357 #ifndef INVT_HAVE_LIVEMEDIA
00358   LFATAL("you must have liveMedia support in order to use RTSPGrabber");
00359 #else
00360   shutdown();
00361 #endif
00362 
00363 }
00364 
00365 // ######################################################################
00366 RTSPGrabber::~RTSPGrabber()
00367 {
00368   delete itsFrameBuffer;
00369 
00370 #ifdef HAVE_FFMPEG_AVCODEC_H
00371   avcodec_close(itsCodecContext);
00372   av_free(itsCodecContext);
00373   av_free(&itsPicture);
00374 #endif
00375 }
00376 
00377 // ######################################################################
00378 GenericFrameSpec RTSPGrabber::peekFrameSpec()
00379 {
00380   GenericFrameSpec result;
00381 
00382   result.nativeType = GenericFrame::VIDEO;
00383   result.videoFormat = itsGrabMode.getVal();
00384   result.videoByteSwap = itsByteSwap.getVal();
00385   result.dims = itsDims.getVal();
00386   result.floatFlags = 0;
00387 
00388   return result;
00389 }
00390 
00391 // ######################################################################
00392 SimTime RTSPGrabber::getNaturalFrameTime() const
00393 {
00394   return SimTime::HERTZ(itsFPS.getVal());
00395 }
00396 
00397 
00398 
00399 // ######################################################################
00400 GenericFrame RTSPGrabber::readFrame()
00401 {
00402   return GenericFrame(this->grabRaw());
00403 }
00404 
00405 // ######################################################################
00406 VideoFrame RTSPGrabber::grabRaw()
00407 {
00408 #ifndef INVT_HAVE_LIVEMEDIA
00409   LFATAL("you must have liveMedia support in order to use RTSPGrabber");
00410   return VideoFrame();  /* can't happen */
00411 #else
00412   pthread_mutex_lock(&itsLock);
00413   VideoFrame videoFrame = itsCurrentFrame;
00414   pthread_mutex_unlock(&itsLock);
00415   usleep(10000);
00416   return videoFrame;
00417 #endif
00418 }
00419 
00420 // ######################################################################
00421 void RTSPGrabber::paramChanged(ModelParamBase* const param,
00422                                    const bool valueChanged,
00423                                    ParamClient::ChangeStatus* status)
00424 {
00425 #ifndef INVT_HAVE_LIVEMEDIA
00426   LFATAL("you must have liveMedia support in order to use RTSPGrabber");
00427 #else
00428   FrameIstream::paramChanged(param, valueChanged, status);
00429 #endif
00430 }
00431 
00432 // ######################################################################
00433 void RTSPGrabber::createDecoder()
00434 {
00435 
00436 }
00437 
00438 // ######################################################################
00439 /* So things look consistent in everyone's emacs... */
00440 /* Local Variables: */
00441 /* indent-tabs-mode: nil */
00442 /* End: */
00443 
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3