mediaServer/DynamicRTSPServer.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-2013, Live Networks, Inc.  All rights reserved
00017 // A subclass of "RTSPServer" that creates "ServerMediaSession"s on demand,
00018 // based on whether or not the specified stream name exists as a file
00019 // Implementation
00020 
00021 #include "DynamicRTSPServer.hh"
00022 #include <liveMedia.hh>
00023 #include <string.h>
00024 
00025 DynamicRTSPServer*
00026 DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
00027                              UserAuthenticationDatabase* authDatabase,
00028                              unsigned reclamationTestSeconds) {
00029   int ourSocket = setUpOurSocket(env, ourPort);
00030   if (ourSocket == -1) return NULL;
00031 
00032   return new DynamicRTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
00033 }
00034 
00035 DynamicRTSPServer::DynamicRTSPServer(UsageEnvironment& env, int ourSocket,
00036                                      Port ourPort,
00037                                      UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
00038   : RTSPServerSupportingHTTPStreaming(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds) {
00039 }
00040 
00041 DynamicRTSPServer::~DynamicRTSPServer() {
00042 }
00043 
00044 static ServerMediaSession* createNewSMS(UsageEnvironment& env,
00045                                         char const* fileName, FILE* fid); // forward
00046 
00047 ServerMediaSession*
00048 DynamicRTSPServer::lookupServerMediaSession(char const* streamName) {
00049   // First, check whether the specified "streamName" exists as a local file:
00050   FILE* fid = fopen(streamName, "rb");
00051   Boolean fileExists = fid != NULL;
00052 
00053   // Next, check whether we already have a "ServerMediaSession" for this file:
00054   ServerMediaSession* sms = RTSPServer::lookupServerMediaSession(streamName);
00055   Boolean smsExists = sms != NULL;
00056 
00057   // Handle the four possibilities for "fileExists" and "smsExists":
00058   if (!fileExists) {
00059     if (smsExists) {
00060       // "sms" was created for a file that no longer exists. Remove it:
00061       removeServerMediaSession(sms);
00062     }
00063     return NULL;
00064   } else {
00065     if (!smsExists) {
00066       // Create a new "ServerMediaSession" object for streaming from the named file.
00067       sms = createNewSMS(envir(), streamName, fid);
00068       addServerMediaSession(sms);
00069     }
00070     fclose(fid);
00071     return sms;
00072   }
00073 }
00074 
00075 // Special code for handling Matroska files:
00076 static char newMatroskaDemuxWatchVariable;
00077 static MatroskaFileServerDemux* demux;
00078 static void onMatroskaDemuxCreation(MatroskaFileServerDemux* newDemux, void* /*clientData*/) {
00079   demux = newDemux;
00080   newMatroskaDemuxWatchVariable = 1;
00081 }
00082 // END Special code for handling Matroska files:
00083 
00084 #define NEW_SMS(description) do {\
00085 char const* descStr = description\
00086     ", streamed by the LIVE555 Media Server";\
00087 sms = ServerMediaSession::createNew(env, fileName, fileName, descStr);\
00088 } while(0)
00089 
00090 static ServerMediaSession* createNewSMS(UsageEnvironment& env,
00091                                         char const* fileName, FILE* /*fid*/) {
00092   // Use the file name extension to determine the type of "ServerMediaSession":
00093   char const* extension = strrchr(fileName, '.');
00094   if (extension == NULL) return NULL;
00095 
00096   ServerMediaSession* sms = NULL;
00097   Boolean const reuseSource = False;
00098   if (strcmp(extension, ".aac") == 0) {
00099     // Assumed to be an AAC Audio (ADTS format) file:
00100     NEW_SMS("AAC Audio");
00101     sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00102   } else if (strcmp(extension, ".amr") == 0) {
00103     // Assumed to be an AMR Audio file:
00104     NEW_SMS("AMR Audio");
00105     sms->addSubsession(AMRAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00106   } else if (strcmp(extension, ".ac3") == 0) {
00107     // Assumed to be an AC-3 Audio file:
00108     NEW_SMS("AC-3 Audio");
00109     sms->addSubsession(AC3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00110   } else if (strcmp(extension, ".m4e") == 0) {
00111     // Assumed to be a MPEG-4 Video Elementary Stream file:
00112     NEW_SMS("MPEG-4 Video");
00113     sms->addSubsession(MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00114   } else if (strcmp(extension, ".264") == 0) {
00115     // Assumed to be a H.264 Video Elementary Stream file:
00116     NEW_SMS("H.264 Video");
00117     OutPacketBuffer::maxSize = 100000; // allow for some possibly large H.264 frames
00118     sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00119   } else if (strcmp(extension, ".mp3") == 0) {
00120     // Assumed to be a MPEG-1 or 2 Audio file:
00121     NEW_SMS("MPEG-1 or 2 Audio");
00122     // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
00123 //#define STREAM_USING_ADUS 1
00124     // To also reorder ADUs before streaming, uncomment the following:
00125 //#define INTERLEAVE_ADUS 1
00126     // (For more information about ADUs and interleaving,
00127     //  see <http://www.live555.com/rtp-mp3/>)
00128     Boolean useADUs = False;
00129     Interleaving* interleaving = NULL;
00130 #ifdef STREAM_USING_ADUS
00131     useADUs = True;
00132 #ifdef INTERLEAVE_ADUS
00133     unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...
00134     unsigned const interleaveCycleSize
00135       = (sizeof interleaveCycle)/(sizeof (unsigned char));
00136     interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);
00137 #endif
00138 #endif
00139     sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving));
00140   } else if (strcmp(extension, ".mpg") == 0) {
00141     // Assumed to be a MPEG-1 or 2 Program Stream (audio+video) file:
00142     NEW_SMS("MPEG-1 or 2 Program Stream");
00143     MPEG1or2FileServerDemux* demux
00144       = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);
00145     sms->addSubsession(demux->newVideoServerMediaSubsession());
00146     sms->addSubsession(demux->newAudioServerMediaSubsession());
00147   } else if (strcmp(extension, ".vob") == 0) {
00148     // Assumed to be a VOB (MPEG-2 Program Stream, with AC-3 audio) file:
00149     NEW_SMS("VOB (MPEG-2 video with AC-3 audio)");
00150     MPEG1or2FileServerDemux* demux
00151       = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);
00152     sms->addSubsession(demux->newVideoServerMediaSubsession());
00153     sms->addSubsession(demux->newAC3AudioServerMediaSubsession());
00154   } else if (strcmp(extension, ".ts") == 0) {
00155     // Assumed to be a MPEG Transport Stream file:
00156     // Use an index file name that's the same as the TS file name, except with ".tsx":
00157     unsigned indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0"
00158     char* indexFileName = new char[indexFileNameLen];
00159     sprintf(indexFileName, "%sx", fileName);
00160     NEW_SMS("MPEG Transport Stream");
00161     sms->addSubsession(MPEG2TransportFileServerMediaSubsession::createNew(env, fileName, indexFileName, reuseSource));
00162     delete[] indexFileName;
00163   } else if (strcmp(extension, ".wav") == 0) {
00164     // Assumed to be a WAV Audio file:
00165     NEW_SMS("WAV Audio Stream");
00166     // To convert 16-bit PCM data to 8-bit u-law, prior to streaming,
00167     // change the following to True:
00168     Boolean convertToULaw = False;
00169     sms->addSubsession(WAVAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, convertToULaw));
00170   } else if (strcmp(extension, ".dv") == 0) {
00171     // Assumed to be a DV Video file
00172     // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000).
00173     OutPacketBuffer::maxSize = 300000;
00174 
00175     NEW_SMS("DV Video");
00176     sms->addSubsession(DVVideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
00177   } else if (strcmp(extension, ".mkv") == 0 || strcmp(extension, ".webm") == 0) {
00178     // Assumed to be a Matroska file (note that WebM ('.webm') files are also Matroska files)
00179     NEW_SMS("Matroska video+audio+(optional)subtitles");
00180 
00181     // Create a Matroska file server demultiplexor for the specified file.  (We enter the event loop to wait for this to complete.)
00182     newMatroskaDemuxWatchVariable = 0;
00183     MatroskaFileServerDemux::createNew(env, fileName, onMatroskaDemuxCreation, NULL);
00184     env.taskScheduler().doEventLoop(&newMatroskaDemuxWatchVariable);
00185 
00186     ServerMediaSubsession* smss;
00187     while ((smss = demux->newServerMediaSubsession()) != NULL) {
00188       sms->addSubsession(smss);
00189     }
00190   }
00191 
00192   return sms;
00193 }

Generated on Mon Apr 29 13:28:03 2013 for live by  doxygen 1.5.2