1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s
19// on demand, from a MPEG-4 video file.
20// Implementation
21
22#include "MPEG4VideoFileServerMediaSubsession.hh"
23#include "MPEG4ESVideoRTPSink.hh"
24#include "ByteStreamFileSource.hh"
25#include "MPEG4VideoStreamFramer.hh"
26
27MPEG4VideoFileServerMediaSubsession*
28MPEG4VideoFileServerMediaSubsession::createNew(UsageEnvironment& env,
29 char const* fileName,
30 Boolean reuseFirstSource) {
31 return new MPEG4VideoFileServerMediaSubsession(env, fileName, reuseFirstSource);
32}
33
34MPEG4VideoFileServerMediaSubsession
35::MPEG4VideoFileServerMediaSubsession(UsageEnvironment& env,
36 char const* fileName, Boolean reuseFirstSource)
37 : FileServerMediaSubsession(env, fileName, reuseFirstSource),
38 fAuxSDPLine(NULL), fDoneFlag(0), fDummyRTPSink(NULL) {
39}
40
41MPEG4VideoFileServerMediaSubsession::~MPEG4VideoFileServerMediaSubsession() {
42 delete[] fAuxSDPLine;
43}
44
45static void afterPlayingDummy(void* clientData) {
46 MPEG4VideoFileServerMediaSubsession* subsess
47 = (MPEG4VideoFileServerMediaSubsession*)clientData;
48 subsess->afterPlayingDummy1();
49}
50
51void MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1() {
52 // Unschedule any pending 'checking' task:
53 envir().taskScheduler().unscheduleDelayedTask(nextTask());
54 // Signal the event loop that we're done:
55 setDoneFlag();
56}
57
58static void checkForAuxSDPLine(void* clientData) {
59 MPEG4VideoFileServerMediaSubsession* subsess
60 = (MPEG4VideoFileServerMediaSubsession*)clientData;
61 subsess->checkForAuxSDPLine1();
62}
63
64void MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1() {
65 nextTask() = NULL;
66
67 char const* dasl;
68 if (fAuxSDPLine != NULL) {
69 // Signal the event loop that we're done:
70 setDoneFlag();
71 } else if (fDummyRTPSink != NULL && (dasl = fDummyRTPSink->auxSDPLine()) != NULL) {
72 fAuxSDPLine= strDup(dasl);
73 fDummyRTPSink = NULL;
74
75 // Signal the event loop that we're done:
76 setDoneFlag();
77 } else if (!fDoneFlag) {
78 // try again after a brief delay:
79 int uSecsToDelay = 100000; // 100 ms
80 nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay,
81 (TaskFunc*)checkForAuxSDPLine, this);
82 }
83}
84
85char const* MPEG4VideoFileServerMediaSubsession::getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource) {
86 if (fAuxSDPLine != NULL) return fAuxSDPLine; // it's already been set up (for a previous client)
87
88 if (fDummyRTPSink == NULL) { // we're not already setting it up for another, concurrent stream
89 // Note: For MPEG-4 video files, the 'config' information isn't known
90 // until we start reading the file. This means that "rtpSink"s
91 // "auxSDPLine()" will be NULL initially, and we need to start reading data from our file until this changes.
92 fDummyRTPSink = rtpSink;
93
94 // Start reading the file:
95 fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this);
96
97 // Check whether the sink's 'auxSDPLine()' is ready:
98 checkForAuxSDPLine(this);
99 }
100
101 envir().taskScheduler().doEventLoop(&fDoneFlag);
102
103 return fAuxSDPLine;
104}
105
106FramedSource* MPEG4VideoFileServerMediaSubsession
107::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
108 estBitrate = 500; // kbps, estimate
109
110 // Create the video source:
111 ByteStreamFileSource* fileSource
112 = ByteStreamFileSource::createNew(envir(), fFileName);
113 if (fileSource == NULL) return NULL;
114 fFileSize = fileSource->fileSize();
115
116 // Create a framer for the Video Elementary Stream:
117 return MPEG4VideoStreamFramer::createNew(envir(), fileSource);
118}
119
120RTPSink* MPEG4VideoFileServerMediaSubsession
121::createNewRTPSink(Groupsock* rtpGroupsock,
122 unsigned char rtpPayloadTypeIfDynamic,
123 FramedSource* /*inputSource*/) {
124 return MPEG4ESVideoRTPSink::createNew(envir(), rtpGroupsock,
125 rtpPayloadTypeIfDynamic);
126}
127