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