00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "liveMedia.hh"
00023 #include "AC3AudioStreamFramer.hh"
00024 #include "BasicUsageEnvironment.hh"
00025 #include "GroupsockHelper.hh"
00026
00027 char const* programName;
00028
00029
00030 Boolean iFramesOnly = False;
00031
00032 unsigned const VOB_AUDIO = 1<<0;
00033 unsigned const VOB_VIDEO = 1<<1;
00034 unsigned mediaToStream = VOB_AUDIO|VOB_VIDEO;
00035
00036 char const** inputFileNames;
00037 char const** curInputFileName;
00038 Boolean haveReadOneFile = False;
00039
00040 UsageEnvironment* env;
00041 MPEG1or2Demux* mpegDemux;
00042 AC3AudioStreamFramer* audioSource = NULL;
00043 FramedSource* videoSource = NULL;
00044 RTPSink* audioSink = NULL;
00045 RTCPInstance* audioRTCP = NULL;
00046 RTPSink* videoSink = NULL;
00047 RTCPInstance* videoRTCP = NULL;
00048 RTSPServer* rtspServer = NULL;
00049 unsigned short const defaultRTSPServerPortNum = 554;
00050 unsigned short rtspServerPortNum = defaultRTSPServerPortNum;
00051
00052 Groupsock* rtpGroupsockAudio;
00053 Groupsock* rtcpGroupsockAudio;
00054 Groupsock* rtpGroupsockVideo;
00055 Groupsock* rtcpGroupsockVideo;
00056
00057 void usage() {
00058 *env << "usage: " << programName << " [-i] [-a|-v] "
00059 "[-p <RTSP-server-port-number>] "
00060 "<VOB-file>...<VOB-file>\n";
00061 exit(1);
00062 }
00063
00064 void play();
00065
00066 int main(int argc, char const** argv) {
00067
00068 TaskScheduler* scheduler = BasicTaskScheduler::createNew();
00069 env = BasicUsageEnvironment::createNew(*scheduler);
00070
00071
00072
00073 programName = argv[0];
00074 while (argc > 2) {
00075 char const* const opt = argv[1];
00076 if (opt[0] != '-') break;
00077 switch (opt[1]) {
00078
00079 case 'i': {
00080 iFramesOnly = True;
00081 break;
00082 }
00083
00084 case 'a': {
00085 mediaToStream &=~ VOB_VIDEO;
00086 break;
00087 }
00088
00089 case 'v': {
00090 mediaToStream &=~ VOB_AUDIO;
00091 break;
00092 }
00093
00094 case 'p': {
00095 int portArg;
00096 if (sscanf(argv[2], "%d", &portArg) != 1) {
00097 usage();
00098 }
00099 if (portArg <= 0 || portArg >= 65536) {
00100 *env << "bad port number: " << portArg
00101 << " (must be in the range (0,65536))\n";
00102 usage();
00103 }
00104 rtspServerPortNum = (unsigned short)portArg;
00105 ++argv; --argc;
00106 break;
00107 }
00108
00109 default: {
00110 usage();
00111 break;
00112 }
00113 }
00114
00115 ++argv; --argc;
00116 }
00117 if (argc < 2) usage();
00118 if (mediaToStream == 0) {
00119 *env << "The -a and -v flags cannot both be used!\n";
00120 usage();
00121 }
00122 if (iFramesOnly && (mediaToStream&VOB_VIDEO) == 0) {
00123 *env << "Warning: Because we're not streaming video, the -i flag has no effect.\n";
00124 }
00125
00126 inputFileNames = &argv[1];
00127 curInputFileName = inputFileNames;
00128
00129
00130 struct in_addr destinationAddress;
00131 destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
00132
00133 const unsigned short rtpPortNumAudio = 4444;
00134 const unsigned short rtcpPortNumAudio = rtpPortNumAudio+1;
00135 const unsigned short rtpPortNumVideo = 8888;
00136 const unsigned short rtcpPortNumVideo = rtpPortNumVideo+1;
00137 const unsigned char ttl = 255;
00138
00139 const Port rtpPortAudio(rtpPortNumAudio);
00140 const Port rtcpPortAudio(rtcpPortNumAudio);
00141 const Port rtpPortVideo(rtpPortNumVideo);
00142 const Port rtcpPortVideo(rtcpPortNumVideo);
00143
00144 const unsigned maxCNAMElen = 100;
00145 unsigned char CNAME[maxCNAMElen+1];
00146 gethostname((char*)CNAME, maxCNAMElen);
00147 CNAME[maxCNAMElen] = '\0';
00148
00149 if (mediaToStream&VOB_AUDIO) {
00150 rtpGroupsockAudio
00151 = new Groupsock(*env, destinationAddress, rtpPortAudio, ttl);
00152 rtpGroupsockAudio->multicastSendOnly();
00153
00154
00155 audioSink
00156 = AC3AudioRTPSink::createNew(*env, rtpGroupsockAudio, 96, 0);
00157
00158
00159
00160 rtcpGroupsockAudio
00161 = new Groupsock(*env, destinationAddress, rtcpPortAudio, ttl);
00162 rtcpGroupsockAudio->multicastSendOnly();
00163 const unsigned estimatedSessionBandwidthAudio
00164 = 160;
00165 audioRTCP = RTCPInstance::createNew(*env, rtcpGroupsockAudio,
00166 estimatedSessionBandwidthAudio, CNAME,
00167 audioSink, NULL ,
00168 True );
00169
00170 }
00171
00172 if (mediaToStream&VOB_VIDEO) {
00173 rtpGroupsockVideo
00174 = new Groupsock(*env, destinationAddress, rtpPortVideo, ttl);
00175 rtpGroupsockVideo->multicastSendOnly();
00176
00177
00178 videoSink = MPEG1or2VideoRTPSink::createNew(*env, rtpGroupsockVideo);
00179
00180
00181 rtcpGroupsockVideo
00182 = new Groupsock(*env, destinationAddress, rtcpPortVideo, ttl);
00183 rtcpGroupsockVideo->multicastSendOnly();
00184 const unsigned estimatedSessionBandwidthVideo
00185 = 4500;
00186 videoRTCP = RTCPInstance::createNew(*env, rtcpGroupsockVideo,
00187 estimatedSessionBandwidthVideo, CNAME,
00188 videoSink, NULL ,
00189 True );
00190
00191 }
00192
00193 if (rtspServer == NULL) {
00194 rtspServer = RTSPServer::createNew(*env, rtspServerPortNum);
00195 if (rtspServer == NULL) {
00196 *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
00197 *env << "To change the RTSP server's port number, use the \"-p <port number>\" option.\n";
00198 exit(1);
00199 }
00200 ServerMediaSession* sms
00201 = ServerMediaSession::createNew(*env, "vobStream", *curInputFileName,
00202 "Session streamed by \"vobStreamer\"", True );
00203 if (audioSink != NULL) sms->addSubsession(PassiveServerMediaSubsession::createNew(*audioSink, audioRTCP));
00204 if (videoSink != NULL) sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, videoRTCP));
00205 rtspServer->addServerMediaSession(sms);
00206
00207 *env << "Created RTSP server.\n";
00208
00209
00210 char* url = rtspServer->rtspURL(sms);
00211 *env << "Access this stream using the URL:\n\t" << url << "\n";
00212 delete[] url;
00213 }
00214
00215
00216 *env << "Beginning streaming...\n";
00217 play();
00218
00219 env->taskScheduler().doEventLoop();
00220
00221 return 0;
00222 }
00223
00224 void afterPlaying(void* clientData) {
00225
00226
00227
00228 if (audioSource != NULL && audioSource->isCurrentlyAwaitingData()
00229 || videoSource != NULL && videoSource->isCurrentlyAwaitingData()) {
00230 return;
00231 }
00232
00233
00234
00235 *env << "...done reading from file\n";
00236
00237 if (audioSink != NULL) audioSink->stopPlaying();
00238 if (videoSink != NULL) videoSink->stopPlaying();
00239
00240 Medium::close(audioSource);
00241 Medium::close(videoSource);
00242 Medium::close(mpegDemux);
00243
00244
00245
00246 ++curInputFileName;
00247
00248
00249 play();
00250 }
00251
00252 void play() {
00253 if (*curInputFileName == NULL) {
00254
00255
00256 if (!haveReadOneFile) exit(1);
00257 haveReadOneFile = False;
00258 curInputFileName = inputFileNames;
00259 }
00260
00261
00262 ByteStreamFileSource* fileSource
00263 = ByteStreamFileSource::createNew(*env, *curInputFileName);
00264 if (fileSource == NULL) {
00265 *env << "Unable to open file \"" << *curInputFileName
00266 << "\" as a byte-stream file source\n";
00267
00268 ++curInputFileName;
00269 play();
00270 return;
00271 }
00272 haveReadOneFile = True;
00273
00274
00275
00276 mpegDemux = MPEG1or2Demux::createNew(*env, fileSource);
00277 if (mediaToStream&VOB_AUDIO) {
00278 FramedSource* audioES = mpegDemux->newElementaryStream(0xBD);
00279
00280 audioSource
00281 = AC3AudioStreamFramer::createNew(*env, audioES, 0x80);
00282 }
00283 if (mediaToStream&VOB_VIDEO) {
00284 FramedSource* videoES = mpegDemux->newVideoStream();
00285
00286 videoSource
00287 = MPEG1or2VideoStreamFramer::createNew(*env, videoES, iFramesOnly);
00288 }
00289
00290
00291 *env << "Beginning to read from \"" << *curInputFileName << "\"...\n";
00292 if (videoSink != NULL) {
00293 videoSink->startPlaying(*videoSource, afterPlaying, videoSink);
00294 }
00295 if (audioSink != NULL) {
00296 audioSink->setRTPTimestampFrequency(audioSource->samplingRate());
00297 audioSink->startPlaying(*audioSource, afterPlaying, audioSink);
00298 }
00299 }