Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package live555 for openSUSE:Factory checked in at 2021-08-16 10:09:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/live555 (Old) and /work/SRC/openSUSE:Factory/.live555.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "live555" Mon Aug 16 10:09:04 2021 rev:26 rq:911953 version:2021.08.09 Changes: -------- --- /work/SRC/openSUSE:Factory/live555/live555.changes 2021-06-24 18:22:00.260878288 +0200 +++ /work/SRC/openSUSE:Factory/.live555.new.1899/live555.changes 2021-08-16 10:14:00.874923494 +0200 @@ -1,0 +2,51 @@ +Thu Aug 12 00:38:24 UTC 2021 - Fusion Future <qydwhotm...@gmail.com> + +- Update to 2021.08.09: + - Fixed a bug in the MPEG-1 or 2 file server demultiplexors that + could cause a RTSP server to crash if it received successive + RTSP "SETUP" commands for the same track. (Thanks to Ba + Jinsheng for reporting this.)(boo#1189352, CVE-2021-38381) +- Update to 2021.08.06: + - Fixed a bug in the Matroska and Ogg file server demultiplexors + that could cause a RTSP server to crash if it received + successive RTSP "SETUP" commands for the same track. (Thanks + to Ba Jinsheng for reporting this.)(boo#1189353, CVE-2021-38382) +- Update to 2021.08.04: + - In the "MP3FileSource" implementation, we no longer do a + recursive call to "doEventLoop()" when attempting to + synchronously read from a MP3 file. This avoids a possible + stack overflow in the RTSP server if multiple concurrent + requests are made. (Thanks to Ba Jinsheng for reporting this.) + The server still does some synchronous reads, when + initializing, and when parsing MP3 frame headers. This should + be fixed sometime in the future. (boo#1189351, CVE-2021-38380) +- Update to 2021.07.20: + - If a "RTSPClient" receives a response to a RTSP "PLAY" that + changes the 'scale()' or 'speed()' of the whole session, then + those parameters also need to be changed in each subsession (as + that inheritance doesn't happen automatically). (Thanks to a + developer in China for reporting this.) +- Update to 2021.07.10: + - Updated "H264or5VideoStreamFramer.cpp" once again to set the + default value of "DeltaTfiDivisor" to 2.0 for H.265, and 1.0 + for everything else. (This fixes the frame rate for another + stream supplied by Paul Westlund.) +- Update to 2021.06.29: + - In the proxy server implementation, if a client closes one + substream, but there are still other clients receiving other + substream(s), then we no send a single-track RTSP "PAUSE" + command downstream, because some back-end servers might handle + that by pausing all tracks of the stream. So now, in this + case, we don't send a RTSP "PAUSE" command at all. (Thanks to + Jose Maria Infanzon for noting this issue.) +- Update to 2021.06.25: + - Updated "H264or5VideoStreamFramer.cpp" to set the default value + of "DeltaTfiDivisor" to 1.0 (rather than 2.0), and to assume a + frame rate of 30 fps (rather than 25 fps) if there is no VPS or + SPS NAL unit that specifies a different frame rate. This seems + to work the best for most raw H.264 and H.265 video streams. + (Thanks to Paul Westlund for supplying an example file to + motivate this.) +- Change the so version of libliveMedia to 97 + +------------------------------------------------------------------- Old: ---- live.2021.05.22.tar.gz New: ---- live.2021.08.09.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ live555.spec ++++++ --- /var/tmp/diff_new_pack.fiDPmQ/_old 2021-08-16 10:14:01.310922937 +0200 +++ /var/tmp/diff_new_pack.fiDPmQ/_new 2021-08-16 10:14:01.314922931 +0200 @@ -17,10 +17,10 @@ # -%define lmdmaj 94 +%define lmdmaj 97 Name: live555 -Version: 2021.05.22 +Version: 2021.08.09 Release: 0 Summary: LIVE555 Streaming Media License: LGPL-2.1-only ++++++ live.2021.05.22.tar.gz -> live.2021.08.09.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh --- old/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2021-08-09 08:33:36.000000000 +0200 @@ -19,7 +19,7 @@ #ifndef _BASICUSAGEENVIRONMENT_VERSION_HH #define _BASICUSAGEENVIRONMENT_VERSION_HH -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2021.05.22" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1621641600 +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2021.08.09" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1628467200 #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/UsageEnvironment/include/UsageEnvironment_version.hh new/live/UsageEnvironment/include/UsageEnvironment_version.hh --- old/live/UsageEnvironment/include/UsageEnvironment_version.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/UsageEnvironment/include/UsageEnvironment_version.hh 2021-08-09 08:33:36.000000000 +0200 @@ -19,7 +19,7 @@ #ifndef _USAGEENVIRONMENT_VERSION_HH #define _USAGEENVIRONMENT_VERSION_HH -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2021.05.22" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1621641600 +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2021.08.09" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1628467200 #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/config.linux-with-shared-libraries new/live/config.linux-with-shared-libraries --- old/live/config.linux-with-shared-libraries 2021-05-22 07:12:22.000000000 +0200 +++ new/live/config.linux-with-shared-libraries 2021-08-09 08:33:57.000000000 +0200 @@ -3,8 +3,8 @@ # At least one interface changes, or is removed => CURRENT += 1; REVISION = 0; AGE = 0 # One or more interfaces were added, but no existing interfaces were changed or removed => CURRENT += 1; REVISION = 0; AGE += 1 -libliveMedia_VERSION_CURRENT=94 -libliveMedia_VERSION_REVISION=3 +libliveMedia_VERSION_CURRENT=97 +libliveMedia_VERSION_REVISION=0 libliveMedia_VERSION_AGE=0 libliveMedia_LIB_SUFFIX=so.$(shell expr $(libliveMedia_VERSION_CURRENT) - $(libliveMedia_VERSION_AGE)).$(libliveMedia_VERSION_AGE).$(libliveMedia_VERSION_REVISION) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/include/groupsock_version.hh new/live/groupsock/include/groupsock_version.hh --- old/live/groupsock/include/groupsock_version.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/groupsock/include/groupsock_version.hh 2021-08-09 08:33:36.000000000 +0200 @@ -19,7 +19,7 @@ #ifndef _GROUPSOCK_VERSION_HH #define _GROUPSOCK_VERSION_HH -#define GROUPSOCK_LIBRARY_VERSION_STRING "2021.05.22" -#define GROUPSOCK_LIBRARY_VERSION_INT 1621641600 +#define GROUPSOCK_LIBRARY_VERSION_STRING "2021.08.09" +#define GROUPSOCK_LIBRARY_VERSION_INT 1628467200 #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/H264or5VideoStreamFramer.cpp new/live/liveMedia/H264or5VideoStreamFramer.cpp --- old/live/liveMedia/H264or5VideoStreamFramer.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/H264or5VideoStreamFramer.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -86,7 +86,7 @@ fParser = createParser ? new H264or5VideoStreamParser(hNumber, this, inputSource, includeStartCodeInOutput) : NULL; - fFrameRate = 25.0; // We assume a frame rate of 25 fps, unless we learn otherwise (from parsing a VPS or SPS NAL unit) + fFrameRate = 30.0; // We assume a frame rate of 30 fps, unless we learn otherwise (from parsing a VPS or SPS NAL unit) } H264or5VideoStreamFramer::~H264or5VideoStreamFramer() { @@ -198,7 +198,7 @@ fHNumber(hNumber), fOutputStartCodeSize(includeStartCodeInOutput ? 4 : 0), fHaveSeenFirstStartCode(False), fHaveSeenFirstByteOfNALUnit(False), fParsedFrameRate(0.0), cpb_removal_delay_length_minus1(23), dpb_output_delay_length_minus1(23), CpbDpbDelaysPresentFlag(0), pic_struct_present_flag(0), - DeltaTfiDivisor(2.0) { + DeltaTfiDivisor(hNumber == 264 ? 2.0 : 1.0) { } H264or5VideoStreamParser::~H264or5VideoStreamParser() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MP3AudioFileServerMediaSubsession.cpp new/live/liveMedia/MP3AudioFileServerMediaSubsession.cpp --- old/live/liveMedia/MP3AudioFileServerMediaSubsession.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MP3AudioFileServerMediaSubsession.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -57,6 +57,7 @@ // Use the MP3 file size, plus the duration, to estimate the stream's bitrate: if (mp3NumBytes > 0 && fFileDuration > 0.0) { estBitrate = (unsigned)(mp3NumBytes/(125*fFileDuration) + 0.5); // kbps, rounded + if (estBitrate == 0) estBitrate = 128; // kbps, estimate } else { estBitrate = 128; // kbps, estimate } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MP3FileSource.cpp new/live/liveMedia/MP3FileSource.cpp --- old/live/liveMedia/MP3FileSource.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MP3FileSource.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -24,19 +24,6 @@ ////////// MP3FileSource ////////// -MP3FileSource::MP3FileSource(UsageEnvironment& env, FILE* fid) - : FramedFileSource(env, fid), - fStreamState(new MP3StreamState(env)) { -} - -MP3FileSource::~MP3FileSource() { - delete fStreamState; -} - -char const* MP3FileSource::MIMEtype() const { - return "audio/MPEG"; -} - MP3FileSource* MP3FileSource::createNew(UsageEnvironment& env, char const* fileName) { MP3FileSource* newSource = NULL; @@ -51,7 +38,6 @@ unsigned fileSize = (unsigned)GetFileSize(fileName, fid); newSource->assignStream(fid, fileSize); - if (!newSource->initializeStream()) break; return newSource; } while (0); @@ -60,6 +46,29 @@ return NULL; } +MP3FileSource::MP3FileSource(UsageEnvironment& env, FILE* fid) + : FramedFileSource(env, fid), + fStreamState(new MP3StreamState), + fHaveStartedReading(False), fHaveBeenInitialized(False), + fLimitNumBytesToStream(False), fNumBytesToStream(0) { + //###### We can't make the socket non-blocking yet, because we still do synchronous reads + //###### on it (to find MP3 headers). Later, fix this. + //makeSocketNonBlocking(fileno(fFid)); + + // Test whether the file is seekable + fFidIsSeekable = FileIsSeekable(fFid); +} + +MP3FileSource::~MP3FileSource() { + if (fFid != NULL) envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid)); + + delete fStreamState; // closes the input file +} + +char const* MP3FileSource::MIMEtype() const { + return "audio/MPEG"; +} + float MP3FileSource::filePlayTime() const { return fStreamState->filePlayTime(); } @@ -109,54 +118,66 @@ } void MP3FileSource::doGetNextFrame() { - if (!doGetNextFrame1()) { + if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) { handleClosure(); return; } - // Switch to another task: -#if defined(__WIN32__) || defined(_WIN32) - // HACK: liveCaster/lc uses an implementation of scheduleDelayedTask() - // that performs very badly (chewing up lots of CPU time, apparently polling) - // on Windows. Until this is fixed, we just call our "afterGetting()" - // function directly. This avoids infinite recursion, as long as our sink - // is discontinuous, which is the case for the RTP sink that liveCaster/lc - // uses. ##### - afterGetting(this); -#else - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)afterGetting, this); -#endif -} + if (!fHaveStartedReading) { + // Await readable data from the file: + envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid), + (TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this); + fHaveStartedReading = True; + return; + } -Boolean MP3FileSource::doGetNextFrame1() { - if (fLimitNumBytesToStream && fNumBytesToStream == 0) return False; // we've already streamed as much as we were asked for + if (!fHaveBeenInitialized) { + if (!initializeStream()) return; - if (!fHaveJustInitialized) { - if (fStreamState->findNextHeader(fPresentationTime) == 0) return False; - } else { fPresentationTime = fFirstFramePresentationTime; - fHaveJustInitialized = False; + fHaveBeenInitialized = True; + } else { + if (fStreamState->findNextHeader(fPresentationTime) == 0) return; } + if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) { + fMaxSize = (unsigned)fNumBytesToStream; + } if (!fStreamState->readFrame(fTo, fMaxSize, fFrameSize, fDurationInMicroseconds)) { char tmp[200]; sprintf(tmp, "Insufficient buffer size %d for reading MPEG audio frame (needed %d)\n", fMaxSize, fFrameSize); envir().setResultMsg(tmp); - fFrameSize = fMaxSize; - return False; + handleClosure(); + return; } - if (fNumBytesToStream > fFrameSize) fNumBytesToStream -= fFrameSize; else fNumBytesToStream = 0; + fNumBytesToStream -= fFrameSize; - return True; + // Inform the reader that he has data: + // Because the file read was done from the event loop, we can call the + // 'after getting' function directly, without risk of infinite recursion: + FramedSource::afterGetting(this); +} + +void MP3FileSource::fileReadableHandler(MP3FileSource* source, int /*mask*/) { + if (!source->isCurrentlyAwaitingData()) { + source->doStopGettingFrames(); // we're not ready for the data yet + return; + } + source->doGetNextFrame(); } void MP3FileSource::assignStream(FILE* fid, unsigned fileSize) { fStreamState->assignStream(fid, fileSize); -} + if (!fHaveBeenInitialized) { + if (!initializeStream()) return; + + fPresentationTime = fFirstFramePresentationTime; + fHaveBeenInitialized = True; + } +} Boolean MP3FileSource::initializeStream() { // Make sure the file has an appropriate header near the start: @@ -167,10 +188,6 @@ fStreamState->checkForXingHeader(); // in case this is a VBR file - fHaveJustInitialized = True; - fLimitNumBytesToStream = False; - fNumBytesToStream = 0; - // Hack: It's possible that our environment's 'result message' has been // reset within this function, so set it again to our name now: envir().setResultMsg(name()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MP3Internals.cpp new/live/liveMedia/MP3Internals.cpp --- old/live/liveMedia/MP3Internals.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MP3Internals.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -97,7 +97,8 @@ ////////// MP3FrameParams ////////// MP3FrameParams::MP3FrameParams() - : bv(frameBytes, 0, sizeof frameBytes) /* by default */ { + : isMPEG2(0), samplingFreq(44100), frameSize(413), // init params, in case we're used early + bv(frameBytes, 0, sizeof frameBytes) /* by default */ { oldHdr = firstHdr = 0; static Boolean doneInit = False; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MP3StreamState.cpp new/live/liveMedia/MP3StreamState.cpp --- old/live/liveMedia/MP3StreamState.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MP3StreamState.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -31,8 +31,8 @@ #define MILLION 1000000 -MP3StreamState::MP3StreamState(UsageEnvironment& env) - : fEnv(env), fFid(NULL), fPresentationTimeScale(1) { +MP3StreamState::MP3StreamState() + : fFid(NULL), fPresentationTimeScale(1) { } MP3StreamState::~MP3StreamState() { @@ -142,7 +142,7 @@ Boolean MP3StreamState::readFrame(unsigned char* outBuf, unsigned outBufSize, unsigned& resultFrameSize, unsigned& resultDurationInMicroseconds) { - /* We assume that "mp3FindNextHeader()" has already been called */ + /* We assume that "findNextHeader()" has already been called */ resultFrameSize = 4 + fr().frameSize; @@ -336,59 +336,9 @@ return True; } -static Boolean socketIsReadable(int socket) { - const unsigned numFds = socket+1; - fd_set rd_set; - FD_ZERO(&rd_set); - FD_SET((unsigned)socket, &rd_set); - struct timeval timeout; - timeout.tv_sec = timeout.tv_usec = 0; - - int result = select(numFds, &rd_set, NULL, NULL, &timeout); - return result != 0; // not > 0, because windows can return -1 for file sockets -} - -static char watchVariable; - -static void checkFunc(void* /*clientData*/) { - watchVariable = ~0; -} - -static void waitUntilSocketIsReadable(UsageEnvironment& env, int socket) { - while (!socketIsReadable(socket)) { - // Delay a short period of time before checking again. - unsigned usecsToDelay = 1000; // 1 ms - env.taskScheduler().scheduleDelayedTask(usecsToDelay, - (TaskFunc*)checkFunc, (void*)NULL); - watchVariable = 0; - env.taskScheduler().doEventLoop(&watchVariable); - // This allows other tasks to run while we're waiting: - } -} - unsigned MP3StreamState::readFromStream(unsigned char* buf, unsigned numChars) { - // Hack for doing socket I/O instead of file I/O (e.g., on Windows) - if (fFidIsReallyASocket) { - intptr_t fid_long = (intptr_t)fFid; - int sock = (int)fid_long; - unsigned totBytesRead = 0; - do { - waitUntilSocketIsReadable(fEnv, sock); - int bytesRead - = recv(sock, &((char*)buf)[totBytesRead], numChars-totBytesRead, 0); - if (bytesRead < 0) return 0; - - totBytesRead += (unsigned)bytesRead; - } while (totBytesRead < numChars); - - return totBytesRead; - } else { -#ifndef _WIN32_WCE - waitUntilSocketIsReadable(fEnv, (int)fileno(fFid)); -#endif - return fread(buf, 1, numChars, fFid); - } + return fread(buf, 1, numChars, fFid); } #define XING_FRAMES_FLAG 0x0001 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MP3StreamState.hh new/live/liveMedia/MP3StreamState.hh --- old/live/liveMedia/MP3StreamState.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MP3StreamState.hh 2021-08-09 08:33:36.000000000 +0200 @@ -40,7 +40,7 @@ class MP3StreamState { public: - MP3StreamState(UsageEnvironment& env); + MP3StreamState(); virtual ~MP3StreamState(); void assignStream(FILE* fid, unsigned fileSize); @@ -73,7 +73,6 @@ Boolean findNextFrame(); private: - UsageEnvironment& fEnv; FILE* fFid; Boolean fFidIsReallyASocket; unsigned fFileSize; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MPEG1or2Demux.cpp new/live/liveMedia/MPEG1or2Demux.cpp --- old/live/liveMedia/MPEG1or2Demux.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MPEG1or2Demux.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -80,12 +80,14 @@ MPEG1or2Demux ::MPEG1or2Demux(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies) + FramedSource* inputSource, Boolean reclaimWhenLastESDies, + MPEG1or2DemuxOnDeletionFunc* onDeletionFunc, void* objectToNotify) : Medium(env), fInputSource(inputSource), fMPEGversion(0), fNextAudioStreamNumber(0), fNextVideoStreamNumber(0), fReclaimWhenLastESDies(reclaimWhenLastESDies), fNumOutstandingESs(0), - fNumPendingReads(0), fHaveUndeliveredData(False) { + fNumPendingReads(0), fHaveUndeliveredData(False), + fOnDeletionFunc(onDeletionFunc), fOnDeletionObjectToNotify(objectToNotify) { fParser = new MPEGProgramStreamParser(this, inputSource); for (unsigned i = 0; i < 256; ++i) { fOutput[i].savedDataHead = fOutput[i].savedDataTail = NULL; @@ -96,6 +98,10 @@ } MPEG1or2Demux::~MPEG1or2Demux() { + if (fOnDeletionFunc != NULL) { + (*fOnDeletionFunc)(fOnDeletionObjectToNotify, this); + } + delete fParser; for (unsigned i = 0; i < 256; ++i) delete fOutput[i].savedDataHead; Medium::close(fInputSource); @@ -103,10 +109,13 @@ MPEG1or2Demux* MPEG1or2Demux ::createNew(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies) { + FramedSource* inputSource, Boolean reclaimWhenLastESDies, + MPEG1or2DemuxOnDeletionFunc* onDeletionFunc, + void* objectToNotify) { // Need to add source type checking here??? ##### - return new MPEG1or2Demux(env, inputSource, reclaimWhenLastESDies); + return new MPEG1or2Demux(env, inputSource, reclaimWhenLastESDies, + onDeletionFunc, objectToNotify); } MPEG1or2Demux::SCR::SCR() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MPEG1or2FileServerDemux.cpp new/live/liveMedia/MPEG1or2FileServerDemux.cpp --- old/live/liveMedia/MPEG1or2FileServerDemux.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MPEG1or2FileServerDemux.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -67,7 +67,8 @@ MPEG1or2DemuxedElementaryStream* MPEG1or2FileServerDemux::newElementaryStream(unsigned clientSessionId, u_int8_t streamIdTag) { - MPEG1or2Demux* demuxToUse; + MPEG1or2Demux* demuxToUse = NULL; + if (clientSessionId == 0) { // 'Session 0' is treated especially, because its audio & video streams // are created and destroyed one-at-a-time, rather than both streams being @@ -86,28 +87,36 @@ } else { // First, check whether this is a new client session. If so, create a new // demux for it: - if (clientSessionId != fLastClientSessionId) { + if (clientSessionId == fLastClientSessionId) { + demuxToUse = fLastCreatedDemux; // use the same demultiplexor as before + } + + if (demuxToUse == NULL) { // Open our input file as a 'byte-stream file source': ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(envir(), fFileName); if (fileSource == NULL) return NULL; - fLastCreatedDemux = MPEG1or2Demux::createNew(envir(), fileSource, True); - // Note: We tell the demux to delete itself when its last - // elementary stream is deleted. - fLastClientSessionId = clientSessionId; - // Note: This code relies upon the fact that the creation of streams for - // different client sessions do not overlap - so one "MPEG1or2Demux" is used - // at a time. + demuxToUse = MPEG1or2Demux::createNew(envir(), fileSource, True, onDemuxDeletion, this); + // Note: We tell the demux to delete itself when its last + // elementary stream is deleted. } - demuxToUse = fLastCreatedDemux; - } - if (demuxToUse == NULL) return NULL; // shouldn't happen + fLastClientSessionId = clientSessionId; + fLastCreatedDemux = demuxToUse; + } return demuxToUse->newElementaryStream(streamIdTag); } +void MPEG1or2FileServerDemux::onDemuxDeletion(void* clientData, MPEG1or2Demux* demuxBeingDeleted) { + ((MPEG1or2FileServerDemux*)clientData)->onDemuxDeletion(demuxBeingDeleted); +} + +void MPEG1or2FileServerDemux::onDemuxDeletion(MPEG1or2Demux* demuxBeingDeleted) { + if (fLastCreatedDemux == demuxBeingDeleted) fLastCreatedDemux = NULL; +} + static Boolean getMPEG1or2TimeCode(FramedSource* dataSource, MPEG1or2Demux& parentDemux, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MatroskaFile.cpp new/live/liveMedia/MatroskaFile.cpp --- old/live/liveMedia/MatroskaFile.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MatroskaFile.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -132,14 +132,21 @@ } } +struct DemuxRecord { + MatroskaDemux* demux; + MatroskaDemuxOnDeletionFunc* onDeletionFunc; + void* objectToNotify; +}; + MatroskaFile::~MatroskaFile() { delete fParserForInitialization; delete fCuePoints; // Delete any outstanding "MatroskaDemux"s, and the table for them: - MatroskaDemux* demux; - while ((demux = (MatroskaDemux*)fDemuxesTable->RemoveNext()) != NULL) { - delete demux; + DemuxRecord* demuxRecord; + while ((demuxRecord = (DemuxRecord*)fDemuxesTable->RemoveNext()) != NULL) { + delete demuxRecord->demux; + delete demuxRecord; } delete fDemuxesTable; delete fTrackTable; @@ -233,15 +240,30 @@ return fTrackTable->lookup(trackNumber); } -MatroskaDemux* MatroskaFile::newDemux() { +MatroskaDemux* MatroskaFile +::newDemux(MatroskaDemuxOnDeletionFunc* onDeletionFunc, void* objectToNotify) { MatroskaDemux* demux = new MatroskaDemux(*this); - fDemuxesTable->Add((char const*)demux, demux); + + DemuxRecord* demuxRecord = new DemuxRecord(); + demuxRecord->demux = demux; + demuxRecord->onDeletionFunc = onDeletionFunc; + demuxRecord->objectToNotify = objectToNotify; + + fDemuxesTable->Add((char const*)demux, demuxRecord); return demux; } void MatroskaFile::removeDemux(MatroskaDemux* demux) { - fDemuxesTable->Remove((char const*)demux); + DemuxRecord* demuxRecord = (DemuxRecord*)(fDemuxesTable->Lookup((char const*)demux)); + if (demuxRecord != NULL) { + fDemuxesTable->Remove((char const*)demux); + + if (demuxRecord->onDeletionFunc != NULL) { + (*demuxRecord->onDeletionFunc)(demuxRecord->objectToNotify, demux); + } + delete demuxRecord; + } } #define getPrivByte(b) if (n == 0) break; else do {b = *p++; --n;} while (0) /* Vorbis/Theora configuration header parsing */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MatroskaFileServerDemux.cpp new/live/liveMedia/MatroskaFileServerDemux.cpp --- old/live/liveMedia/MatroskaFileServerDemux.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/MatroskaFileServerDemux.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -87,7 +87,7 @@ // for other ('real') session ids). Because of this, a separate demultiplexor is used for each 'session 0' track. } - if (demuxToUse == NULL) demuxToUse = fOurMatroskaFile->newDemux(); + if (demuxToUse == NULL) demuxToUse = fOurMatroskaFile->newDemux(onDemuxDeletion, this); fLastClientSessionId = clientSessionId; fLastCreatedDemux = demuxToUse; @@ -119,3 +119,12 @@ // Now, call our own creation notification function: if (fOnCreation != NULL) (*fOnCreation)(this, fOnCreationClientData); } + +void MatroskaFileServerDemux +::onDemuxDeletion(void* clientData, MatroskaDemux* demuxBeingDeleted) { + ((MatroskaFileServerDemux*)clientData)->onDemuxDeletion(demuxBeingDeleted); +} + +void MatroskaFileServerDemux::onDemuxDeletion(MatroskaDemux* demuxBeingDeleted) { + if (fLastCreatedDemux == demuxBeingDeleted) fLastCreatedDemux = NULL; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/OggFile.cpp new/live/liveMedia/OggFile.cpp --- old/live/liveMedia/OggFile.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/OggFile.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -56,13 +56,38 @@ return fTrackTable->lookup(trackNumber); } -OggDemux* OggFile::newDemux() { +struct DemuxRecord { + OggDemux* demux; + OggDemuxOnDeletionFunc* onDeletionFunc; + void* objectToNotify; +}; + +OggDemux* OggFile +::newDemux(OggDemuxOnDeletionFunc* onDeletionFunc, void* objectToNotify) { OggDemux* demux = new OggDemux(*this); - fDemuxesTable->Add((char const*)demux, demux); + + DemuxRecord* demuxRecord = new DemuxRecord(); + demuxRecord->demux = demux; + demuxRecord->onDeletionFunc = onDeletionFunc; + demuxRecord->objectToNotify = objectToNotify; + + fDemuxesTable->Add((char const*)demux, demuxRecord); return demux; } +void OggFile::removeDemux(OggDemux* demux) { + DemuxRecord* demuxRecord = (DemuxRecord*)(fDemuxesTable->Lookup((char const*)demux)); + if (demuxRecord != NULL) { + fDemuxesTable->Remove((char const*)demux); + + if (demuxRecord->onDeletionFunc != NULL) { + (*demuxRecord->onDeletionFunc)(demuxRecord->objectToNotify, demux); + } + delete demuxRecord; + } +} + unsigned OggFile::numTracks() const { return fTrackTable->numTracks(); } @@ -143,9 +168,10 @@ delete fParserForInitialization; // Delete any outstanding "OggDemux"s, and the table for them: - OggDemux* demux; - while ((demux = (OggDemux*)fDemuxesTable->RemoveNext()) != NULL) { - delete demux; + DemuxRecord* demuxRecord; + while ((demuxRecord = (DemuxRecord*)fDemuxesTable->RemoveNext()) != NULL) { + delete demuxRecord->demux; + delete demuxRecord; } delete fDemuxesTable; delete fTrackTable; @@ -169,10 +195,6 @@ fTrackTable->add(newTrack); } -void OggFile::removeDemux(OggDemux* demux) { - fDemuxesTable->Remove((char const*)demux); -} - ////////// OggTrackTable implementation ///////// @@ -290,7 +312,7 @@ fDemuxedTracksTable->Remove((char const*)trackNumber); if (fDemuxedTracksTable->numEntries() == 0) { // We no longer have any demuxed tracks, so delete ourselves now: - delete this; + Medium::close(this); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/OggFileServerDemux.cpp new/live/liveMedia/OggFileServerDemux.cpp --- old/live/liveMedia/OggFileServerDemux.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/OggFileServerDemux.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -71,7 +71,7 @@ // for other ('real') session ids). Because of this, a separate demultiplexor is used for each 'session 0' track. } - if (demuxToUse == NULL) demuxToUse = fOurOggFile->newDemux(); + if (demuxToUse == NULL) demuxToUse = fOurOggFile->newDemux(onDemuxDeletion, this); fLastClientSessionId = clientSessionId; fLastCreatedDemux = demuxToUse; @@ -107,3 +107,11 @@ // Now, call our own creation notification function: if (fOnCreation != NULL) (*fOnCreation)(this, fOnCreationClientData); } + +void OggFileServerDemux::onDemuxDeletion(void* clientData, OggDemux* demuxBeingDeleted) { + ((OggFileServerDemux*)clientData)->onDemuxDeletion(demuxBeingDeleted); +} + +void OggFileServerDemux::onDemuxDeletion(OggDemux* demuxBeingDeleted) { + if (fLastCreatedDemux == demuxBeingDeleted) fLastCreatedDemux = NULL; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/ProxyServerMediaSession.cpp new/live/liveMedia/ProxyServerMediaSession.cpp --- old/live/liveMedia/ProxyServerMediaSession.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/ProxyServerMediaSession.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -653,10 +653,13 @@ if (proxyRTSPClient->fLastCommandWasPLAY) { // so that we send only one "PAUSE"; not one for each subsession if (fParentSession->referenceCount() > 1) { // There are other client(s) still streaming other subsessions of this stream. - // Therefore, we don't send a "PAUSE" for the whole stream, but only for the sub-stream: - proxyRTSPClient->sendPauseCommand(fClientMediaSubsession, NULL, proxyRTSPClient->auth()); + // Therefore, we don't send a "PAUSE" for the whole stream. + // In principle, we would send a "PAUSE" only for the sub-stream here, but some + // back-end servers might mis-handle that by pausing the entire stream. + // So instead, we do nothing here. + //proxyRTSPClient->sendPauseCommand(fClientMediaSubsession, NULL, proxyRTSPClient->auth()); } else { - // Normal case: There are no other client still streaming (parts of) this stream. + // Normal case: There are no other clients still streaming (parts of) this stream. // Send a "PAUSE" for the whole stream. proxyRTSPClient->sendPauseCommand(fClientMediaSubsession.parentSession(), NULL, proxyRTSPClient->auth()); proxyRTSPClient->fLastCommandWasPLAY = False; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPClient.cpp new/live/liveMedia/RTSPClient.cpp --- old/live/liveMedia/RTSPClient.cpp 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/RTSPClient.cpp 2021-08-09 08:33:36.000000000 +0200 @@ -1301,6 +1301,9 @@ MediaSubsessionIterator iter(*session); MediaSubsession* subsession; while ((subsession = iter.next()) != NULL) { + subsession->scale() = session->scale(); + subsession->speed() = session->speed(); + u_int16_t seqNum; u_int32_t timestamp; subsession->rtpInfo.infoIsNew = False; if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) { @@ -1328,9 +1331,9 @@ u_int16_t seqNum; u_int32_t timestamp; subsession->rtpInfo.infoIsNew = False; if (parseRTPInfoParams(rtpInfoParamsStr, seqNum, timestamp)) { - subsession->rtpInfo.seqNum = seqNum; - subsession->rtpInfo.timestamp = timestamp; - subsession->rtpInfo.infoIsNew = True; + subsession->rtpInfo.seqNum = seqNum; + subsession->rtpInfo.timestamp = timestamp; + subsession->rtpInfo.infoIsNew = True; } if (subsession->rtpSource() != NULL) subsession->rtpSource()->enableRTCPReports() = True; // start sending RTCP "RR"s now diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/MP3FileSource.hh new/live/liveMedia/include/MP3FileSource.hh --- old/live/liveMedia/include/MP3FileSource.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/MP3FileSource.hh 2021-08-09 08:33:36.000000000 +0200 @@ -56,11 +56,13 @@ virtual void getAttributes() const; private: - virtual Boolean doGetNextFrame1(); + static void fileReadableHandler(MP3FileSource* source, int mask); private: MP3StreamState* fStreamState; - Boolean fHaveJustInitialized; + Boolean fFidIsSeekable; + Boolean fHaveStartedReading; + unsigned fHaveBeenInitialized; struct timeval fFirstFramePresentationTime; // set on stream init Boolean fLimitNumBytesToStream; unsigned fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/MPEG1or2Demux.hh new/live/liveMedia/include/MPEG1or2Demux.hh --- old/live/liveMedia/include/MPEG1or2Demux.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/MPEG1or2Demux.hh 2021-08-09 08:33:36.000000000 +0200 @@ -27,11 +27,15 @@ class MPEG1or2DemuxedElementaryStream; // forward +typedef void MPEG1or2DemuxOnDeletionFunc(void* objectToNotify, class MPEG1or2Demux* demuxBeingDeleted); + class MPEG1or2Demux: public Medium { public: static MPEG1or2Demux* createNew(UsageEnvironment& env, FramedSource* inputSource, - Boolean reclaimWhenLastESDies = False); + Boolean reclaimWhenLastESDies = False, + MPEG1or2DemuxOnDeletionFunc* onDeletionFunc = NULL, + void* objectToNotify = NULL); // If "reclaimWhenLastESDies" is True, the the demux is deleted when // all "MPEG1or2DemuxedElementaryStream"s that we created get deleted. @@ -81,7 +85,8 @@ private: MPEG1or2Demux(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies); + FramedSource* inputSource, Boolean reclaimWhenLastESDies, + MPEG1or2DemuxOnDeletionFunc* onDeletionFunc, void* objectToNotify); // called only by createNew() virtual ~MPEG1or2Demux(); @@ -142,6 +147,9 @@ unsigned fNumPendingReads; Boolean fHaveUndeliveredData; + MPEG1or2DemuxOnDeletionFunc* fOnDeletionFunc; + void* fOnDeletionObjectToNotify; + private: // parsing state class MPEGProgramStreamParser* fParser; friend class MPEGProgramStreamParser; // hack diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/MPEG1or2FileServerDemux.hh new/live/liveMedia/include/MPEG1or2FileServerDemux.hh --- old/live/liveMedia/include/MPEG1or2FileServerDemux.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/MPEG1or2FileServerDemux.hh 2021-08-09 08:33:36.000000000 +0200 @@ -54,6 +54,9 @@ MPEG1or2DemuxedElementaryStream* newElementaryStream(unsigned clientSessionId, u_int8_t streamIdTag); + static void onDemuxDeletion(void* clientData, MPEG1or2Demux* demuxBeingDeleted); + void onDemuxDeletion(MPEG1or2Demux* demuxBeingDeleted); + private: char const* fFileName; unsigned fFileSize; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/MatroskaFile.hh new/live/liveMedia/include/MatroskaFile.hh --- old/live/liveMedia/include/MatroskaFile.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/MatroskaFile.hh 2021-08-09 08:33:36.000000000 +0200 @@ -34,6 +34,8 @@ class MatroskaTrack; // forward class MatroskaDemux; // forward +typedef void MatroskaDemuxOnDeletionFunc(void* objectToNotify, MatroskaDemux* demuxBeingDeleted); + class MatroskaFile: public Medium { public: typedef void (onCreationFunc)(MatroskaFile* newFile, void* clientData); @@ -45,8 +47,9 @@ MatroskaTrack* lookup(unsigned trackNumber) const; - // Create a demultiplexor for extracting tracks from this file. (Separate clients will typically have separate demultiplexors.) - MatroskaDemux* newDemux(); + MatroskaDemux* newDemux(MatroskaDemuxOnDeletionFunc* onDeletionFunc = NULL, void* objectToNotify = NULL); + // Creates a demultiplexor for extracting tracks from this file. + // (Separate clients will typically have separate demultiplexors.) // Parameters of the file ('Segment'); set when the file is parsed: unsigned timecodeScale() { return fTimecodeScale; } // in nanoseconds diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/MatroskaFileServerDemux.hh new/live/liveMedia/include/MatroskaFileServerDemux.hh --- old/live/liveMedia/include/MatroskaFileServerDemux.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/MatroskaFileServerDemux.hh 2021-08-09 08:33:36.000000000 +0200 @@ -67,6 +67,10 @@ static void onMatroskaFileCreation(MatroskaFile* newFile, void* clientData); void onMatroskaFileCreation(MatroskaFile* newFile); + + static void onDemuxDeletion(void* clientData, MatroskaDemux* demuxBeingDeleted); + void onDemuxDeletion(MatroskaDemux* demuxBeingDeleted); + private: char const* fFileName; onCreationFunc* fOnCreation; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/OggFile.hh new/live/liveMedia/include/OggFile.hh --- old/live/liveMedia/include/OggFile.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/OggFile.hh 2021-08-09 08:33:36.000000000 +0200 @@ -31,6 +31,8 @@ class OggTrack; // forward class OggDemux; // forward +typedef void OggDemuxOnDeletionFunc(void* objectToNotify, OggDemux* demuxBeingDeleted); + class OggFile: public Medium { public: typedef void (onCreationFunc)(OggFile* newFile, void* clientData); @@ -44,7 +46,7 @@ OggTrack* lookup(u_int32_t trackNumber); - OggDemux* newDemux(); + OggDemux* newDemux(OggDemuxOnDeletionFunc* onDeletionFunc = NULL, void* objectToNotify = NULL); // Creates a demultiplexor for extracting tracks from this file. // (Separate clients will typically have separate demultiplexors.) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/OggFileServerDemux.hh new/live/liveMedia/include/OggFileServerDemux.hh --- old/live/liveMedia/include/OggFileServerDemux.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/OggFileServerDemux.hh 2021-08-09 08:33:36.000000000 +0200 @@ -64,6 +64,10 @@ static void onOggFileCreation(OggFile* newFile, void* clientData); void onOggFileCreation(OggFile* newFile); + + static void onDemuxDeletion(void* clientData, OggDemux* demuxBeingDeleted); + void onDemuxDeletion(OggDemux* demuxBeingDeleted); + private: char const* fFileName; onCreationFunc* fOnCreation; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/liveMedia_version.hh new/live/liveMedia/include/liveMedia_version.hh --- old/live/liveMedia/include/liveMedia_version.hh 2021-05-22 07:12:13.000000000 +0200 +++ new/live/liveMedia/include/liveMedia_version.hh 2021-08-09 08:33:36.000000000 +0200 @@ -19,7 +19,7 @@ #ifndef _LIVEMEDIA_VERSION_HH #define _LIVEMEDIA_VERSION_HH -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2021.05.22" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1621641600 +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2021.08.09" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1628467200 #endif