testProgs/testMPEG1or2AudioVideoStreamer.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // Copyright (c) 1996-2012, Live Networks, Inc.  All rights reserved
00017 // A test program that reads a MPEG-1 or 2 Program Stream file,
00018 // splits it into Audio and Video Elementary Streams,
00019 // and streams both using RTP
00020 // main program
00021 
00022 #include "liveMedia.hh"
00023 #include "BasicUsageEnvironment.hh"
00024 #include "GroupsockHelper.hh"
00025 
00026 UsageEnvironment* env;
00027 char const* inputFileName = "test.mpg";
00028 MPEG1or2Demux* mpegDemux;
00029 FramedSource* audioSource;
00030 FramedSource* videoSource;
00031 RTPSink* audioSink;
00032 RTPSink* videoSink;
00033 
00034 void play(); // forward
00035 
00036 // To stream using "source-specific multicast" (SSM), uncomment the following:
00037 //#define USE_SSM 1
00038 #ifdef USE_SSM
00039 Boolean const isSSM = True;
00040 #else
00041 Boolean const isSSM = False;
00042 #endif
00043 
00044 // To set up an internal RTSP server, uncomment the following:
00045 //#define IMPLEMENT_RTSP_SERVER 1
00046 // (Note that this RTSP server works for multicast only)
00047 
00048 // To stream *only* MPEG "I" frames (e.g., to reduce network bandwidth),
00049 // change the following "False" to "True":
00050 Boolean iFramesOnly = False;
00051 
00052 int main(int argc, char** argv) {
00053   // Begin by setting up our usage environment:
00054   TaskScheduler* scheduler = BasicTaskScheduler::createNew();
00055   env = BasicUsageEnvironment::createNew(*scheduler);
00056 
00057   // Create 'groupsocks' for RTP and RTCP:
00058   char const* destinationAddressStr
00059 #ifdef USE_SSM
00060     = "232.255.42.42";
00061 #else
00062     = "239.255.42.42";
00063   // Note: This is a multicast address.  If you wish to stream using
00064   // unicast instead, then replace this string with the unicast address
00065   // of the (single) destination.  (You may also need to make a similar
00066   // change to the receiver program.)
00067 #endif
00068   const unsigned short rtpPortNumAudio = 6666;
00069   const unsigned short rtcpPortNumAudio = rtpPortNumAudio+1;
00070   const unsigned short rtpPortNumVideo = 8888;
00071   const unsigned short rtcpPortNumVideo = rtpPortNumVideo+1;
00072   const unsigned char ttl = 7; // low, in case routers don't admin scope
00073 
00074   struct in_addr destinationAddress;
00075   destinationAddress.s_addr = our_inet_addr(destinationAddressStr);
00076   const Port rtpPortAudio(rtpPortNumAudio);
00077   const Port rtcpPortAudio(rtcpPortNumAudio);
00078   const Port rtpPortVideo(rtpPortNumVideo);
00079   const Port rtcpPortVideo(rtcpPortNumVideo);
00080 
00081   Groupsock rtpGroupsockAudio(*env, destinationAddress, rtpPortAudio, ttl);
00082   Groupsock rtcpGroupsockAudio(*env, destinationAddress, rtcpPortAudio, ttl);
00083   Groupsock rtpGroupsockVideo(*env, destinationAddress, rtpPortVideo, ttl);
00084   Groupsock rtcpGroupsockVideo(*env, destinationAddress, rtcpPortVideo, ttl);
00085 #ifdef USE_SSM
00086   rtpGroupsockAudio.multicastSendOnly();
00087   rtcpGroupsockAudio.multicastSendOnly();
00088   rtpGroupsockVideo.multicastSendOnly();
00089   rtcpGroupsockVideo.multicastSendOnly();
00090 #endif
00091 
00092   // Create a 'MPEG Audio RTP' sink from the RTP 'groupsock':
00093   audioSink = MPEG1or2AudioRTPSink::createNew(*env, &rtpGroupsockAudio);
00094 
00095   // Create (and start) a 'RTCP instance' for this RTP sink:
00096   const unsigned estimatedSessionBandwidthAudio = 160; // in kbps; for RTCP b/w share
00097   const unsigned maxCNAMElen = 100;
00098   unsigned char CNAME[maxCNAMElen+1];
00099   gethostname((char*)CNAME, maxCNAMElen);
00100   CNAME[maxCNAMElen] = '\0'; // just in case
00101 #ifdef IMPLEMENT_RTSP_SERVER
00102   RTCPInstance* audioRTCP =
00103 #endif
00104     RTCPInstance::createNew(*env, &rtcpGroupsockAudio,
00105                             estimatedSessionBandwidthAudio, CNAME,
00106                             audioSink, NULL /* we're a server */, isSSM);
00107   // Note: This starts RTCP running automatically
00108 
00109   // Create a 'MPEG Video RTP' sink from the RTP 'groupsock':
00110   videoSink = MPEG1or2VideoRTPSink::createNew(*env, &rtpGroupsockVideo);
00111 
00112   // Create (and start) a 'RTCP instance' for this RTP sink:
00113   const unsigned estimatedSessionBandwidthVideo = 4500; // in kbps; for RTCP b/w share
00114 #ifdef IMPLEMENT_RTSP_SERVER
00115   RTCPInstance* videoRTCP =
00116 #endif
00117     RTCPInstance::createNew(*env, &rtcpGroupsockVideo,
00118                               estimatedSessionBandwidthVideo, CNAME,
00119                               videoSink, NULL /* we're a server */, isSSM);
00120   // Note: This starts RTCP running automatically
00121 
00122 #ifdef IMPLEMENT_RTSP_SERVER
00123   RTSPServer* rtspServer = RTSPServer::createNew(*env);
00124   // Note that this (attempts to) start a server on the default RTSP server
00125   // port: 554.  To use a different port number, add it as an extra
00126   // (optional) parameter to the "RTSPServer::createNew()" call above.
00127   if (rtspServer == NULL) {
00128     *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
00129     exit(1);
00130   }
00131   ServerMediaSession* sms
00132     = ServerMediaSession::createNew(*env, "testStream", inputFileName,
00133                    "Session streamed by \"testMPEG1or2AudioVideoStreamer\"",
00134                                            isSSM);
00135   sms->addSubsession(PassiveServerMediaSubsession::createNew(*audioSink, audioRTCP));
00136   sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, videoRTCP));
00137   rtspServer->addServerMediaSession(sms);
00138 
00139   char* url = rtspServer->rtspURL(sms);
00140   *env << "Play this stream using the URL \"" << url << "\"\n";
00141   delete[] url;
00142 #endif
00143 
00144   // Finally, start the streaming:
00145   *env << "Beginning streaming...\n";
00146   play();
00147 
00148   env->taskScheduler().doEventLoop(); // does not return
00149 
00150   return 0; // only to prevent compiler warning
00151 }
00152 
00153 void afterPlaying(void* clientData) {
00154   // One of the sinks has ended playing.
00155   // Check whether any of the sources have a pending read.  If so,
00156   // wait until its sink ends playing also:
00157   if (audioSource->isCurrentlyAwaitingData()
00158       || videoSource->isCurrentlyAwaitingData()) return;
00159 
00160   // Now that both sinks have ended, close both input sources,
00161   // and start playing again:
00162   *env << "...done reading from file\n";
00163 
00164   audioSink->stopPlaying();
00165   videoSink->stopPlaying();
00166       // ensures that both are shut down
00167   Medium::close(audioSource);
00168   Medium::close(videoSource);
00169   Medium::close(mpegDemux);
00170   // Note: This also closes the input file that this source read from.
00171 
00172   // Start playing once again:
00173   play();
00174 }
00175 
00176 void play() {
00177   // Open the input file as a 'byte-stream file source':
00178   ByteStreamFileSource* fileSource
00179     = ByteStreamFileSource::createNew(*env, inputFileName);
00180   if (fileSource == NULL) {
00181     *env << "Unable to open file \"" << inputFileName
00182          << "\" as a byte-stream file source\n";
00183     exit(1);
00184   }
00185 
00186   // We must demultiplex Audio and Video Elementary Streams
00187   // from the input source:
00188   mpegDemux = MPEG1or2Demux::createNew(*env, fileSource);
00189   FramedSource* audioES = mpegDemux->newAudioStream();
00190   FramedSource* videoES = mpegDemux->newVideoStream();
00191 
00192   // Create a framer for each Elementary Stream:
00193   audioSource
00194     = MPEG1or2AudioStreamFramer::createNew(*env, audioES);
00195   videoSource
00196     = MPEG1or2VideoStreamFramer::createNew(*env, videoES, iFramesOnly);
00197 
00198   // Finally, start playing each sink.
00199   *env << "Beginning to read from file...\n";
00200   videoSink->startPlaying(*videoSource, afterPlaying, videoSink);
00201   audioSink->startPlaying(*audioSource, afterPlaying, audioSink);
00202 }

Generated on Thu May 17 07:11:48 2012 for live by  doxygen 1.5.2