testProgs/testMPEG4VideoToDarwin.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 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015 **********/
00016 // Copyright (c) 1996-2008, Live Networks, Inc.  All rights reserved
00017 // A test program that reads a MPEG-4 Video Elementary Stream file,
00018 // and streams both using RTP, through a remote Darwin Streaming Server.
00019 // main program
00020 
00022 // This demo software is provided only as a courtesy to those developers who - for whatever reason - wish
00023 // to send outgoing streams through a separate Darwin Streaming Server.  However, it is not necessary to use
00024 // a Darwin Streaming Server in order to serve streams using RTP/RTSP.  Instead, the "LIVE555 Streaming Media"
00025 // includes its own RTSP/RTP server implementation, which you should use instead.  For tips on using our
00026 // RTSP/RTP server implementation, see the "testOnDemandRTSPServer" demo application, and/or the
00027 // "live555MediaServer" application (in the "mediaServer") directory.
00029 
00030 #include "liveMedia.hh"
00031 #include "BasicUsageEnvironment.hh"
00032 
00033 UsageEnvironment* env;
00034 char const* inputFileName = "test.m4e";
00035 char const* remoteStreamName = "test.sdp"; // the stream name, as served by the DSS
00036 MPEG4VideoStreamFramer* videoSource;
00037 RTPSink* videoSink;
00038 
00039 char const* programName;
00040 
00041 void usage() {
00042   *env << "usage: " << programName
00043        << " <Darwin Streaming Server name or IP address>\n";
00044   exit(1);
00045 }
00046 
00047 Boolean awaitConfigInfo(RTPSink* sink); // forward
00048 void play(); // forward
00049 
00050 int main(int argc, char** argv) {
00051   // Begin by setting up our usage environment:
00052   TaskScheduler* scheduler = BasicTaskScheduler::createNew();
00053   env = BasicUsageEnvironment::createNew(*scheduler);
00054 
00055   // Parse command-line arguments:
00056   programName = argv[0];
00057   if (argc != 2) usage();
00058   char const* dssNameOrAddress = argv[1];
00059 
00060   // Create a 'Darwin injector' object:
00061   DarwinInjector* injector = DarwinInjector::createNew(*env, programName);
00062 
00063   // Create 'groupsocks' for RTP and RTCP.
00064   // (Note: Because we will actually be streaming through a remote Darwin server,
00065   // via TCP, we just use dummy destination addresses, port numbers, and TTLs here.)
00066   struct in_addr dummyDestAddress;
00067   dummyDestAddress.s_addr = 0;
00068   Groupsock rtpGroupsockVideo(*env, dummyDestAddress, 0, 0);
00069   Groupsock rtcpGroupsockVideo(*env, dummyDestAddress, 0, 0);
00070 
00071   // Create a 'MPEG-4 Video RTP' sink from the RTP 'groupsock':
00072   videoSink = MPEG4ESVideoRTPSink::createNew(*env, &rtpGroupsockVideo, 96);
00073 
00074   // HACK, specifically for MPEG-4 video:
00075   // Before we can use this RTP sink, we need its MPEG-4 'config' information (for
00076   // use in the SDP description).  Unfortunately, this config information depends
00077   // on the the properties of the MPEG-4 input data.  Therefore, we need to start
00078   // 'playing' this RTP sink from the input source now, and wait until we get
00079   // the needed config information, before continuing:
00080   // that we need:
00081   *env << "Beginning streaming...\n";
00082   play();
00083 
00084   if (!awaitConfigInfo(videoSink)) {
00085     *env << "Failed to get MPEG-4 'config' information from input file: "
00086          << env->getResultMsg() << "\n";
00087     exit(1);
00088   }
00089 
00090   // Create (and start) a 'RTCP instance' for this RTP sink:
00091   const unsigned estimatedSessionBandwidthVideo = 500; // in kbps; for RTCP b/w share
00092   const unsigned maxCNAMElen = 100;
00093   unsigned char CNAME[maxCNAMElen+1];
00094   gethostname((char*)CNAME, maxCNAMElen);
00095   CNAME[maxCNAMElen] = '\0'; // just in case
00096   RTCPInstance* videoRTCP =
00097     RTCPInstance::createNew(*env, &rtcpGroupsockVideo,
00098                             estimatedSessionBandwidthVideo, CNAME,
00099                             videoSink, NULL /* we're a server */);
00100   // Note: This starts RTCP running automatically
00101 
00102   // Add these to our 'Darwin injector':
00103   injector->addStream(videoSink, videoRTCP);
00104 
00105   // Next, specify the destination Darwin Streaming Server:
00106   if (!injector->setDestination(dssNameOrAddress, remoteStreamName,
00107                                 programName, "LIVE555 Streaming Media")) {
00108     *env << "injector->setDestination() failed: "
00109          << env->getResultMsg() << "\n";
00110     exit(1);
00111   }
00112 
00113   *env << "Play this stream (from the Darwin Streaming Server) using the URL:\n"
00114        << "\trtsp://" << dssNameOrAddress << "/" << remoteStreamName << "\n";
00115 
00116   env->taskScheduler().doEventLoop(); // does not return
00117 
00118   return 0; // only to prevent compiler warning
00119 }
00120 
00121 void afterPlaying(void* clientData) {
00122   *env << "...done reading from file\n";
00123 
00124   Medium::close(videoSource);
00125   // Note: This also closes the input file that this source read from.
00126 
00127   // Start playing once again:
00128   play();
00129 }
00130 
00131 void play() {
00132   // Open the input file as a 'byte-stream file source':
00133   ByteStreamFileSource* fileSource
00134     = ByteStreamFileSource::createNew(*env, inputFileName);
00135   if (fileSource == NULL) {
00136     *env << "Unable to open file \"" << inputFileName
00137          << "\" as a byte-stream file source\n";
00138     exit(1);
00139   }
00140   
00141   FramedSource* videoES = fileSource;
00142 
00143   // Create a framer for the Video Elementary Stream:
00144   FramedSource* videoSource = MPEG4VideoStreamFramer::createNew(*env, videoES);
00145 
00146   // Finally, start playing:
00147   *env << "Beginning to read from file...\n";
00148   videoSink->startPlaying(*videoSource, afterPlaying, videoSink);
00149 }
00150 
00151 static char doneFlag = 0;
00152 
00153 static void checkForAuxSDPLine(void* clientData) {
00154   RTPSink* sink = (RTPSink*)clientData;
00155   if (sink->auxSDPLine() != NULL) {
00156     // Signal the event loop that we're done:
00157     doneFlag = ~0;
00158   } else {
00159     // No luck yet.  Try again, after a brief delay:
00160     int uSecsToDelay = 100000; // 100 ms
00161     env->taskScheduler().scheduleDelayedTask(uSecsToDelay,
00162                                              (TaskFunc*)checkForAuxSDPLine, sink);
00163   }
00164 }
00165 
00166 Boolean awaitConfigInfo(RTPSink* sink) {
00167   // Check whether the sink's 'auxSDPLine()' is ready:
00168   checkForAuxSDPLine(sink);
00169 
00170   env->taskScheduler().doEventLoop(&doneFlag);
00171 
00172   char const* auxSDPLine = sink->auxSDPLine();
00173   return auxSDPLine != NULL;
00174 }

Generated on Tue Jul 22 06:39:07 2008 for live by  doxygen 1.5.2