commit live555 for openSUSE:Factory
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package live555 for openSUSE:Factory checked in at 2024-07-22 17:14:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/live555 (Old) and /work/SRC/openSUSE:Factory/.live555.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "live555" Mon Jul 22 17:14:18 2024 rev:41 rq:1188462 version:2024.06.26 Changes: -------- --- /work/SRC/openSUSE:Factory/live555/live555.changes 2024-03-03 20:19:32.662314621 +0100 +++ /work/SRC/openSUSE:Factory/.live555.new.17339/live555.changes 2024-07-22 17:14:35.501098450 +0200 @@ -1,0 +2,50 @@ +Thu Jul 18 14:19:57 UTC 2024 - Dirk Müller <dmueller@suse.com> + +- update to 2024-06-26: + * Updated the "OnDemandServerMediaSubsession" implementation to + output an error message if the "sink->startPlaying()" call failed + (e.g., due to its source not being compatible with the sink). + This makes some common errors (e.g, a proper 'framer' not + being used) easier to detect. +- update to 2024-05-30: + * Fixed a mistake that caused the config file + "config.raspberrypi" to not appear in the distribution. +- update to 2024-05-15: + * Added a new config file "config.raspberrypi" that is known to + work for building the code on/for a Raspberry Pi 5. +- update to 2024-05-05: + * Updated "QuickTimeFileSink" to add support for recording H.265 + video streams. (This is not fully working yet; it appears to + have some bugs.) +- update to 2024-04-19: + * Updated "MPEG2TransportStreamFramer" to ignore big jumps (2x or + more) in the estimate for the duration of each Transport + packet. + This is likely caused by an unexpected jump in the PCR (not + indicated by "discontinuity_indicator"). +- update to 2024-03-08: + * Changed "ServerTLSState::setup()" (in "TLSState.cpp") to call + "SSL_CTX_use_certificate_chain_file()" instead of + "SSL_CTX_use_certificate_file()", to allow the server operator to + specify a chain of certificates, rather than just one. +- update to 2024.02.28: + * Updated the code for "dateHeader()" (in "RTSPCommon.cpp") to + avoid using "strftime()", because that can produce a localized + date string that violates the RTSP specification + (which uses section 3.3.1 of RFC 2068 (the HTTP/1.1 + specification) to define the "Date:" header). +- update to 2024.02.23: + * Updated the code for "dateHeader()" (in "RTSPCommon.cpp") to use + "NULL" instead of "nullptr"; the latter was causing compilation + problems for someone. +- update to 2024.02.15: + * Updated the RTCP implementation so that reception stats for a + SSRC are no longer deleted, even if a SSRC is reaped due to RTCP + inactivity (no RTCP "SR" reports received recently). + +------------------------------------------------------------------- +Thu Jul 18 14:17:02 UTC 2024 - Dirk Müller <dmueller@suse.com> + +- update to 2024. + +------------------------------------------------------------------- Old: ---- live.2023.11.30.tar.gz New: ---- live.2024.06.26.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ live555.spec ++++++ --- /var/tmp/diff_new_pack.MPTQLL/_old 2024-07-22 17:14:36.257127807 +0200 +++ /var/tmp/diff_new_pack.MPTQLL/_new 2024-07-22 17:14:36.257127807 +0200 @@ -20,7 +20,7 @@ %define lmdmaj 112 Name: live555 -Version: 2023.11.30 +Version: 2024.06.26 Release: 0 Summary: LIVE555 Streaming Media License: LGPL-2.1-only ++++++ live.2023.11.30.tar.gz -> live.2024.06.26.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp new/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp --- old/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/BasicUsageEnvironment/BasicUsageEnvironment.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -20,6 +20,11 @@ #include "BasicUsageEnvironment.hh" #include <stdio.h> +////////// library version constants ////////// + +extern char const* const BasicUsageEnvironmentLibraryVersionStr = BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING; +extern int const BasicUsageEnvironmentLibraryVersionInt = BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT; + ////////// BasicUsageEnvironment ////////// #if defined(__WIN32__) || defined(_WIN32) 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 2023-11-30 09:22:23.000000000 +0100 +++ new/live/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh 2024-06-26 07:46:23.000000000 +0200 @@ -14,12 +14,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // Version information for the "BasicUsageEnvironment" library -// Copyright (c) 1996-2023 Live Networks, Inc. All rights reserved. +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. #ifndef _BASICUSAGEENVIRONMENT_VERSION_HH #define _BASICUSAGEENVIRONMENT_VERSION_HH -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2023.11.30" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1701302400 +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2024.06.26" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1719360000 + +extern char const* const BasicUsageEnvironmentLibraryVersionStr; +extern int const BasicUsageEnvironmentLibraryVersionInt; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/UsageEnvironment/UsageEnvironment.cpp new/live/UsageEnvironment/UsageEnvironment.cpp --- old/live/UsageEnvironment/UsageEnvironment.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/UsageEnvironment/UsageEnvironment.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -19,6 +19,13 @@ #include "UsageEnvironment.hh" +////////// library version constants ////////// + +extern char const* const UsageEnvironmentLibraryVersionStr = USAGEENVIRONMENT_LIBRARY_VERSION_STRING; +extern int const UsageEnvironmentLibraryVersionInt = USAGEENVIRONMENT_LIBRARY_VERSION_INT; + +////////// UsageEnvironment ////////// + Boolean UsageEnvironment::reclaim() { // We delete ourselves only if we have no remainining state: if (liveMediaPriv == NULL && groupsockPriv == NULL) { 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 2023-11-30 09:22:23.000000000 +0100 +++ new/live/UsageEnvironment/include/UsageEnvironment_version.hh 2024-06-26 07:46:23.000000000 +0200 @@ -14,12 +14,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // Version information for the "UsageEnvironment" library -// Copyright (c) 1996-2023 Live Networks, Inc. All rights reserved. +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. #ifndef _USAGEENVIRONMENT_VERSION_HH #define _USAGEENVIRONMENT_VERSION_HH -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2023.11.30" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1701302400 +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2024.06.26" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1719360000 + +extern char const* const UsageEnvironmentLibraryVersionStr; +extern int const UsageEnvironmentLibraryVersionInt; #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 2023-11-30 09:22:51.000000000 +0100 +++ new/live/config.linux-with-shared-libraries 2024-06-26 07:46:35.000000000 +0200 @@ -3,24 +3,24 @@ # 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=112 -libliveMedia_VERSION_REVISION=0 -libliveMedia_VERSION_AGE=0 +libliveMedia_VERSION_CURRENT=113 +libliveMedia_VERSION_REVISION=3 +libliveMedia_VERSION_AGE=1 libliveMedia_LIB_SUFFIX=so.$(shell expr $(libliveMedia_VERSION_CURRENT) - $(libliveMedia_VERSION_AGE)).$(libliveMedia_VERSION_AGE).$(libliveMedia_VERSION_REVISION) -libBasicUsageEnvironment_VERSION_CURRENT=2 -libBasicUsageEnvironment_VERSION_REVISION=4 -libBasicUsageEnvironment_VERSION_AGE=0 +libBasicUsageEnvironment_VERSION_CURRENT=3 +libBasicUsageEnvironment_VERSION_REVISION=0 +libBasicUsageEnvironment_VERSION_AGE=1 libBasicUsageEnvironment_LIB_SUFFIX=so.$(shell expr $(libBasicUsageEnvironment_VERSION_CURRENT) - $(libBasicUsageEnvironment_VERSION_AGE)).$(libBasicUsageEnvironment_VERSION_AGE).$(libBasicUsageEnvironment_VERSION_REVISION) -libUsageEnvironment_VERSION_CURRENT=4 +libUsageEnvironment_VERSION_CURRENT=5 libUsageEnvironment_VERSION_REVISION=0 -libUsageEnvironment_VERSION_AGE=1 +libUsageEnvironment_VERSION_AGE=2 libUsageEnvironment_LIB_SUFFIX=so.$(shell expr $(libUsageEnvironment_VERSION_CURRENT) - $(libUsageEnvironment_VERSION_AGE)).$(libUsageEnvironment_VERSION_AGE).$(libUsageEnvironment_VERSION_REVISION) -libgroupsock_VERSION_CURRENT=31 -libgroupsock_VERSION_REVISION=13 -libgroupsock_VERSION_AGE=1 +libgroupsock_VERSION_CURRENT=32 +libgroupsock_VERSION_REVISION=0 +libgroupsock_VERSION_AGE=2 libgroupsock_LIB_SUFFIX=so.$(shell expr $(libgroupsock_VERSION_CURRENT) - $(libgroupsock_VERSION_AGE)).$(libgroupsock_VERSION_AGE).$(libgroupsock_VERSION_REVISION) ##### diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/config.raspberrypi new/live/config.raspberrypi --- old/live/config.raspberrypi 1970-01-01 01:00:00.000000000 +0100 +++ new/live/config.raspberrypi 2024-06-26 07:46:35.000000000 +0200 @@ -0,0 +1,17 @@ +COMPILE_OPTS = $(INCLUDES) -I. -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DNO_OPENSSL=1 -DNO_STD_LIB=1 +C = c +C_COMPILER = cc +C_FLAGS = $(COMPILE_OPTS) $(CPPFLAGS) $(CFLAGS) +CPP = cpp +CPLUSPLUS_COMPILER = c++ +CPLUSPLUS_FLAGS = $(COMPILE_OPTS) -Wall -DBSD=1 $(CPPFLAGS) $(CXXFLAGS) +OBJ = o +LINK = c++ -o +LINK_OPTS = -L. $(LDFLAGS) +CONSOLE_LINK_OPTS = $(LINK_OPTS) +LIBRARY_LINK = ar cr +LIBRARY_LINK_OPTS = +LIB_SUFFIX = a +LIBS_FOR_CONSOLE_APPLICATION = +LIBS_FOR_GUI_APPLICATION = +EXE = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/groupsock/Groupsock.cpp new/live/groupsock/Groupsock.cpp --- old/live/groupsock/Groupsock.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/groupsock/Groupsock.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -25,6 +25,11 @@ #endif #include <stdio.h> +////////// library version constants ////////// + +extern char const* const groupsockLibraryVersionStr = GROUPSOCK_LIBRARY_VERSION_STRING; +extern int const groupsockLibraryVersionInt = GROUPSOCK_LIBRARY_VERSION_INT; + ///////// OutputSocket ////////// OutputSocket::OutputSocket(UsageEnvironment& env, int family) 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 2023-11-30 09:22:23.000000000 +0100 +++ new/live/groupsock/include/groupsock_version.hh 2024-06-26 07:46:23.000000000 +0200 @@ -14,12 +14,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // Version information for the "groupsock" library -// Copyright (c) 1996-2023 Live Networks, Inc. All rights reserved. +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. #ifndef _GROUPSOCK_VERSION_HH #define _GROUPSOCK_VERSION_HH -#define GROUPSOCK_LIBRARY_VERSION_STRING "2023.11.30" -#define GROUPSOCK_LIBRARY_VERSION_INT 1701302400 +#define GROUPSOCK_LIBRARY_VERSION_STRING "2024.06.26" +#define GROUPSOCK_LIBRARY_VERSION_INT 1719360000 + +extern char const* const groupsockLibraryVersionStr; +extern int const groupsockLibraryVersionInt; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/MPEG2TransportStreamFramer.cpp new/live/liveMedia/MPEG2TransportStreamFramer.cpp --- old/live/liveMedia/MPEG2TransportStreamFramer.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/MPEG2TransportStreamFramer.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -257,7 +257,8 @@ if (fTSPacketDurationEstimate == 0.0) { // we've just started fTSPacketDurationEstimate = durationPerPacket; - } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0) { + } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0 + && durationPerPacket < 2*fTSPacketDurationEstimate) { fTSPacketDurationEstimate = durationPerPacket*NEW_DURATION_WEIGHT + fTSPacketDurationEstimate*(1-NEW_DURATION_WEIGHT); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/Media.cpp new/live/liveMedia/Media.cpp --- old/live/liveMedia/Media.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/Media.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -21,6 +21,11 @@ #include "Media.hh" #include "HashTable.hh" +////////// library version constants ////////// + +extern char const* const liveMediaLibraryVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; +extern int const liveMediaLibraryVersionInt = LIVEMEDIA_LIBRARY_VERSION_INT; + ////////// Medium ////////// Medium::Medium(UsageEnvironment& env) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/OnDemandServerMediaSubsession.cpp new/live/liveMedia/OnDemandServerMediaSubsession.cpp --- old/live/liveMedia/OnDemandServerMediaSubsession.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/OnDemandServerMediaSubsession.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -571,13 +571,17 @@ } if (!fAreCurrentlyPlaying && fMediaSource != NULL) { - if (fRTPSink != NULL) { - fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); - fAreCurrentlyPlaying = True; - } else if (fUDPSink != NULL) { - fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); - fAreCurrentlyPlaying = True; + MediaSink* sink; + if (fRTPSink != NULL) { sink = fRTPSink; } + else if (fUDPSink != NULL) { sink = fUDPSink; } + else return; + + if (!sink->startPlaying(*fMediaSource, afterPlayingStreamState, this)) { + fMediaSource->envir() << "sink->startPlaying() failed: " + << fMediaSource->envir().getResultMsg() << "\n"; + return; } + fAreCurrentlyPlaying = True; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/QuickTimeFileSink.cpp new/live/liveMedia/QuickTimeFileSink.cpp --- old/live/liveMedia/QuickTimeFileSink.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/QuickTimeFileSink.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -26,13 +26,15 @@ #include "H263plusVideoRTPSource.hh" // for the special header #include "MPEG4GenericRTPSource.hh" //for "samplingFrequencyFromAudioSpecificConfig()" #include "MPEG4LATMAudioRTPSource.hh" // for "parseGeneralConfigStr()" +#include "H264or5VideoStreamFramer.hh" // for "removeH264or5EmulationBytes()" #include "Base64.hh" #include <ctype.h> #define fourChar(x,y,z,w) ( ((x)<<24)|((y)<<16)|((z)<<8)|(w) ) -#define H264_IDR_FRAME 0x65 //bit 8 == 0, bits 7-6 (ref) == 3, bits 5-0 (type) == 5 +#define H264_IDR_FRAME 0x65 //bit 8 == 0, bits 7-6 (ref) == 3, bits 5-1 (type) == 5 +#define isIDRFrame(firstByte) (firstByte == H264_IDR_FRAME || ((firstByte&0x7E)>>1) == 19 || ((firstByte&0x7E)>>1) == 20) ////////// SubsessionIOState, ChunkDescriptor /////////// // A structure used to represent the I/O state of each input 'subsession': @@ -653,6 +655,10 @@ fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_avc1; fQTTimeScale = 600; fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS; + } else if (strcmp(fOurSubsession.codecName(), "H265") == 0) { + fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_hvc1; + fQTTimeScale = 600; + fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS; } else if (strcmp(fOurSubsession.codecName(), "MP4V-ES") == 0) { fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_mp4v; fQTTimeScale = 600; @@ -801,7 +807,10 @@ struct timeval const& presentationTime = buffer.presentationTime(); int64_t const destFileOffset = TellFile64(fOurSink.fOutFid); unsigned sampleNumberOfFrameStart = fQTTotNumSamples + 1; - Boolean avcHack = fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_avc1; + Boolean h264or5Hack = + fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_avc1 || + fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_hvc1; + // If we're not syncing streams, or this subsession is not video, then // just give this frame a fixed duration: @@ -809,7 +818,7 @@ || fQTcomponentSubtype != fourChar('v','i','d','e')) { unsigned const frameDuration = fQTTimeUnitsPerSample*fQTSamplesPerFrame; unsigned frameSizeToUse = frameSize; - if (avcHack) frameSizeToUse += 4; // H.264/AVC gets the frame size prefix + if (h264or5Hack) frameSizeToUse += 4; // H.264/5 gets the frame size prefix fQTTotNumSamples += useFrame1(frameSizeToUse, presentationTime, frameDuration, destFileOffset); } else { @@ -825,7 +834,7 @@ unsigned frameDuration = (unsigned)((2*duration*fQTTimeScale+1)/2); // round unsigned frameSizeToUse = fPrevFrameState.frameSize; - if (avcHack) frameSizeToUse += 4; // H.264/AVC gets the frame size prefix + if (h264or5Hack) frameSizeToUse += 4; // H.264/5 gets the frame size prefix unsigned numSamples = useFrame1(frameSizeToUse, ppt, frameDuration, fPrevFrameState.destFileOffset); @@ -833,7 +842,7 @@ sampleNumberOfFrameStart = fQTTotNumSamples + 1; } - if (avcHack && (*frameSource == H264_IDR_FRAME)) { + if (h264or5Hack && isIDRFrame(*frameSource)) { SyncFrame* newSyncFrame = new SyncFrame(fQTTotNumSamples + 1); if (fTailSyncFrame == NULL) { fHeadSyncFrame = newSyncFrame; @@ -849,7 +858,7 @@ fPrevFrameState.destFileOffset = destFileOffset; } - if (avcHack) fOurSink.addWord(frameSize); + if (h264or5Hack) fOurSink.addWord(frameSize); // Write the data into the file: fwrite(frameSource, 1, frameSize, fOurSink.fOutFid); @@ -1119,7 +1128,7 @@ // if audio is in sync, wait for the next IDR frame to start unsigned char* const frameSource = fBuffer->dataStart(); - if (*frameSource != H264_IDR_FRAME) return False; + if (!isIDRFrame(*frameSource)) return False; } // But now we are fHaveBeenSynced = True; @@ -1888,45 +1897,165 @@ addAtomEnd; addAtom(avcC); -// Begin by Base-64 decoding the "sprop" parameter sets strings: + // Begin by Base-64 decoding the "sprop" parameter sets strings: char* psets = strDup(fCurrentIOState->fOurSubsession.fmtp_spropparametersets()); if (psets == NULL) return 0; + char const* spsBase64 = psets; size_t comma_pos = strcspn(psets, ","); psets[comma_pos] = '\0'; - char const* sps_b64 = psets; - char const* pps_b64 = &psets[comma_pos+1]; - unsigned sps_count; - unsigned char* sps_data = base64Decode(sps_b64, sps_count, false); - unsigned pps_count; - unsigned char* pps_data = base64Decode(pps_b64, pps_count, false); -// Then add the decoded data: + char const* ppsBase64 = &psets[comma_pos+1]; + + unsigned spsSize; + unsigned char* sps = base64Decode(spsBase64, spsSize, false); + + unsigned ppsSize; + unsigned char* pps = base64Decode(ppsBase64, ppsSize, false); + + // We use some of the data from the "SPS". Remove any 'emulation bytes' from it first: + if (spsSize == 0) return 0; + u_int8_t* spsWEB = new u_int8_t[spsSize]; // "WEB" means "Without Emulation Bytes" + unsigned spsWEBSize = removeH264or5EmulationBytes(spsWEB, spsSize, sps, spsSize); + if (spsWEBSize < 4) { // Bad SPS size + delete[] spsWEB; + return 0; + } + + // Then add the decoded data: size += addByte(0x01); // configuration version - size += addByte(sps_data[1]); // profile - size += addByte(sps_data[2]); // profile compat - size += addByte(sps_data[3]); // level + size += addByte(spsWEB[1]); // profile + size += addByte(spsWEB[2]); // profile compat + size += addByte(spsWEB[3]); // level size += addByte(0xff); /* 0b11111100 | lengthsize = 0x11 */ - size += addByte(0xe0 | (sps_count > 0 ? 1 : 0) ); - if (sps_count > 0) { - size += addHalfWord(sps_count); - for (unsigned i = 0; i < sps_count; i++) { - size += addByte(sps_data[i]); + size += addByte(0xe0 | (spsSize > 0 ? 1 : 0) ); + if (spsSize > 0) { + size += addHalfWord(spsSize); + for (unsigned i = 0; i < spsSize; i++) { + size += addByte(sps[i]); } } - size += addByte(pps_count > 0 ? 1 : 0); - if (pps_count > 0) { - size += addHalfWord(pps_count); - for (unsigned i = 0; i < pps_count; i++) { - size += addByte(pps_data[i]); + size += addByte(ppsSize > 0 ? 1 : 0); + if (ppsSize > 0) { + size += addHalfWord(ppsSize); + for (unsigned i = 0; i < ppsSize; i++) { + size += addByte(pps[i]); } } -// Finally, delete the data that we allocated: - delete[] pps_data; delete[] sps_data; + // Finally, delete the data that we allocated: + delete[] spsWEB; + delete[] pps; delete[] sps; delete[] psets; addAtomEnd; +addAtom(hvc1); +// General sample description fields: + size += addWord(0x00000000); // Reserved + size += addWord(0x00000001); // Reserved+Data reference index +// Video sample description fields: + size += addWord(0x00000000); // Version+Revision level + size += add4ByteString("appl"); // Vendor + size += addWord(0x00000000); // Temporal quality + size += addWord(0x00000000); // Spatial quality + unsigned const widthAndHeight = (fMovieWidth<<16)|fMovieHeight; + size += addWord(widthAndHeight); // Width+height + size += addWord(0x00480000); // Horizontal resolution + size += addWord(0x00480000); // Vertical resolution + size += addWord(0x00000000); // Data size + size += addWord(0x00010548); // Frame count+Compressor name (start) + // "H.265" + size += addWord(0x2e323635); // Compressor name (continued) + size += addZeroWords(6); // Compressor name (continued - zero) + size += addWord(0x00000018); // Compressor name (final)+Depth + size += addHalfWord(0xffff); // Color table id + size += addAtom_hvcC(); +addAtomEnd; + +addAtom(hvcC); + // Begin by Base-64 decoding the "sprop" parameter sets strings: + char const* vpsBase64 = strDup(fCurrentIOState->fOurSubsession.fmtp_spropvps()); + char const* spsBase64 = strDup(fCurrentIOState->fOurSubsession.fmtp_spropsps()); + char const* ppsBase64 = strDup(fCurrentIOState->fOurSubsession.fmtp_sproppps()); + if (vpsBase64 == NULL || spsBase64 == NULL || ppsBase64 == NULL) return 0; + + unsigned vpsSize; + unsigned char* vps = base64Decode(vpsBase64, vpsSize, false); + + unsigned spsSize; + unsigned char* sps = base64Decode(spsBase64, spsSize, false); + + unsigned ppsSize; + unsigned char* pps = base64Decode(ppsBase64, ppsSize, false); + + // We use some of the data from the "VPS". Remove any 'emulation bytes' from it first: + if (vpsSize == 0) return 0; + u_int8_t* vpsWEB = new u_int8_t[vpsSize]; // "WEB" means "Without Emulation Bytes" + unsigned vpsWEBSize = removeH264or5EmulationBytes(vpsWEB, vpsSize, vps, vpsSize); + if (vpsWEBSize < 6/*'profile_tier_level' offset*/ + 12/*num 'profile_tier_level' bytes*/) { + // Bad VPS size + delete[] vpsWEB; + return 0; + } + + // Then add the decoded data: + size += addByte(0x01); // configurationVersion = 1 + + u_int8_t const* profileTierLevelHeaderBytes = &vpsWEB[6]; + size += addByte(profileTierLevelHeaderBytes[0]); + // general_profile_space + general_tier_flag + general_profile_idc + + u_int8_t const* general_profile_compatibility_flags = &profileTierLevelHeaderBytes[1]; + for (unsigned i = 0; i < 4; ++i) size += addByte(general_profile_compatibility_flags[i]); + // general_profile_compatibility_flags + + u_int8_t const* general_constraint_indicator_flags = &profileTierLevelHeaderBytes[5]; + for (unsigned i = 0; i < 6; ++i) size += addByte(general_constraint_indicator_flags[i]); + // general_constraint_indicator_flags + + size += addByte(profileTierLevelHeaderBytes[11]); // general_level_idc + size += addHalfWord(0xF000); // min_spatial_segmentation_idc = 0 ??? + size += addByte(0xFC); // parallelismType = 0 ??? + size += addByte(0xFD); // chroma_format_idc = 1 ??? + size += addByte(0xF8); // bit_depth_luma_minus8 = 0 ??? + size += addByte(0xF8); // bit_depth_chroma_minus8 = 0 ??? + size += addHalfWord(0x0000); // avgFrameRate = 0 + size += addByte(0x0F); + // constantFrameRate = 0; numTemporalLayers = 1; temporalIdNested = 1; lengthSizeMinusOne = 3 ??? + size += addByte(1 + (spsSize > 0) + (ppsSize > 0)); // numOfArrays + + if (vpsSize > 0) { + size += addByte(0x20); // array_completeness = 0; NAL_unit_type = VPS + size += addHalfWord(1); // numNalus + size += addHalfWord(vpsSize); + for (unsigned i = 0; i < vpsSize; i++) { + size += addByte(vps[i]); + } + } + + if (spsSize > 0) { + size += addByte(0x21); // array_completeness = 0; NAL_unit_type = SPS + size += addHalfWord(1); // numNalus + size += addHalfWord(spsSize); + for (unsigned i = 0; i < spsSize; i++) { + size += addByte(sps[i]); + } + } + + if (ppsSize > 0) { + size += addByte(0x22); // array_completeness = 0; NAL_unit_type = PPS + size += addHalfWord(1); // numNalus + size += addHalfWord(ppsSize); + for (unsigned i = 0; i < ppsSize; i++) { + size += addByte(pps[i]); + } + } + +// Finally, delete the data that we allocated: + delete[] vpsWEB; + delete[] vps; delete[] pps; delete[] sps; +addAtomEnd; + addAtom(mp4v); // General sample description fields: size += addWord(0x00000000); // Reserved diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTCP.cpp new/live/liveMedia/RTCP.cpp --- old/live/liveMedia/RTCP.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/RTCP.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -102,7 +102,7 @@ #ifdef DEBUG fprintf(stderr, "reap: removing SSRC 0x%x\n", oldSSRC); #endif - fOurRTCPInstance.removeSSRC(oldSSRC, True); + fOurRTCPInstance.removeSSRC(oldSSRC, False/*keep stats around*/); } } while (foundOldMember); } 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 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/RTSPClient.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -419,7 +419,6 @@ // Set the "User-Agent:" header to use in each request: char const* const libName = "LIVE555 Streaming Media v"; - char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; char const* libPrefix; char const* libSuffix; if (applicationName == NULL || applicationName[0] == '\0') { applicationName = libPrefix = libSuffix = ""; @@ -428,9 +427,9 @@ libSuffix = ")"; } unsigned userAgentNameSize - = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1; + = strlen(applicationName) + strlen(libPrefix) + strlen(libName) + strlen(liveMediaLibraryVersionStr) + strlen(libSuffix) + 1; char* userAgentName = new char[userAgentNameSize]; - sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, libVersionStr, libSuffix); + sprintf(userAgentName, "%s%s%s%s%s", applicationName, libPrefix, libName, liveMediaLibraryVersionStr, libSuffix); setUserAgentString(userAgentName); delete[] userAgentName; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPCommon.cpp new/live/liveMedia/RTSPCommon.cpp --- old/live/liveMedia/RTSPCommon.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/RTSPCommon.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -23,7 +23,7 @@ #include <string.h> #include <stdio.h> #include <ctype.h> // for "isxdigit() -#include <time.h> // for "strftime()" and "gmtime()" +#include <time.h> // for "gmtime()" static void decodeURL(char* url) { // Replace (in place) any %<hex><hex> sequences with the appropriate 8-bit character. @@ -361,13 +361,19 @@ time_tm = tm{}; } #else - if (gmtime_r(&tt, &time_tm) == nullptr) { + if (gmtime_r(&tt, &time_tm) == NULL) { time_tm = tm(); } #endif - strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", &time_tm); + static const char* day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static const char* month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + snprintf(buf, sizeof buf, "Date: %s, %s %02d %04d %02d:%02d:%02d GMT\r\n", + day[time_tm.tm_wday], month[time_tm.tm_mon], time_tm.tm_mday, + 1900 + time_tm.tm_year, + time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec); #else - // WinCE apparently doesn't have "time()", "strftime()", or "gmtime()", + // WinCE apparently doesn't have "time()", or "gmtime()", // so generate the "Date:" header a different, WinCE-specific way. // (Thanks to Pierre l'Hussiez for this code) // RSF: But where is the "Date: " string? This code doesn't look quite right... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/RTSPCommon.cpp.new new/live/liveMedia/RTSPCommon.cpp.new --- old/live/liveMedia/RTSPCommon.cpp.new 1970-01-01 01:00:00.000000000 +0100 +++ new/live/liveMedia/RTSPCommon.cpp.new 2024-06-26 07:46:23.000000000 +0200 @@ -0,0 +1,396 @@ +/********** +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for +more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +**********/ +// "liveMedia" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Common routines used by both RTSP clients and servers +// Implementation + +#include "RTSPCommon.hh" +#include "Locale.hh" +#include <string.h> +#include <stdio.h> +#include <ctype.h> // for "isxdigit() +#include <time.h> // for "gmtime()" + +static void decodeURL(char* url) { + // Replace (in place) any %<hex><hex> sequences with the appropriate 8-bit character. + char* cursor = url; + while (*cursor) { + if ((cursor[0] == '%') && + cursor[1] && isxdigit(cursor[1]) && + cursor[2] && isxdigit(cursor[2])) { + // We saw a % followed by 2 hex digits, so we copy the literal hex value into the URL, then advance the cursor past it: + char hex[3]; + hex[0] = cursor[1]; + hex[1] = cursor[2]; + hex[2] = '\0'; + *url++ = (char)strtol(hex, NULL, 16); + cursor += 3; + } else { + // Common case: This is a normal character or a bogus % expression, so just copy it + *url++ = *cursor++; + } + } + + *url = '\0'; +} + +Boolean parseRTSPRequestString(char const* reqStr, unsigned reqStrSize, + char* resultCmdName, + unsigned resultCmdNameMaxSize, + char* resultURLPreSuffix, + unsigned resultURLPreSuffixMaxSize, + char* resultURLSuffix, + unsigned resultURLSuffixMaxSize, + char* resultCSeq, + unsigned resultCSeqMaxSize, + char* resultSessionIdStr, + unsigned resultSessionIdStrMaxSize, + unsigned& contentLength, Boolean& urlIsRTSPS) { + // This parser is currently rather dumb; it should be made smarter ##### + urlIsRTSPS = False; // by default + + // "Be liberal in what you accept": Skip over any whitespace at the start of the request: + unsigned i; + for (i = 0; i < reqStrSize; ++i) { + char c = reqStr[i]; + if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0')) break; + } + if (i == reqStrSize) return False; // The request consisted of nothing but whitespace! + + // Then read everything up to the next space (or tab) as the command name: + Boolean parseSucceeded = False; + unsigned i1 = 0; + for (; i1 < resultCmdNameMaxSize-1 && i < reqStrSize; ++i,++i1) { + char c = reqStr[i]; + if (c == ' ' || c == '\t') { + parseSucceeded = True; + break; + } + + resultCmdName[i1] = c; + } + resultCmdName[i1] = '\0'; + if (!parseSucceeded) return False; + + // Skip over the prefix of any "rtsp://" or "rtsp:/" (or "rtsps://" or "rtsps:/") + // URL that follows: + unsigned j = i+1; + while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space + for (; (int)j < (int)(reqStrSize-8); ++j) { + if ((reqStr[j] == 'r' || reqStr[j] == 'R') + && (reqStr[j+1] == 't' || reqStr[j+1] == 'T') + && (reqStr[j+2] == 's' || reqStr[j+2] == 'S') + && (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')) { + if (reqStr[j+4] == 's' || reqStr[j+4] == 'S') { + urlIsRTSPS = True; + ++j; + } + if (reqStr[j+4] == ':' && reqStr[j+5] == '/') { + j += 6; + if (reqStr[j] == '/') { + // This is a "rtsp(s)://" URL; skip over the host:port part that follows: + ++j; + while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j; + } else { + // This is a "rtsp(s):/" URL; back up to the "/": + --j; + } + i = j; + break; + } + } + } + + // Look for the URL suffix (before the following "RTSP/"): + parseSucceeded = False; + for (unsigned k = i+1; (int)k < (int)(reqStrSize-5); ++k) { + if (reqStr[k] == 'R' && reqStr[k+1] == 'T' && + reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') { + while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/" + unsigned k1 = k; + while (k1 > i && reqStr[k1] != '/') --k1; + + // ASSERT: At this point + // i: first space or slash after "host" or "host:port" + // k: last non-space before "RTSP/" + // k1: last slash in the range [i,k] + + // The URL suffix comes from [k1+1,k] + // Copy "resultURLSuffix": + unsigned n = 0, k2 = k1+1; + if (k2 <= k) { + if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room + while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++]; + } + resultURLSuffix[n] = '\0'; + + // The URL 'pre-suffix' comes from [i+1,k1-1] + // Copy "resultURLPreSuffix": + n = 0; k2 = i+1; + if (k2+1 <= k1) { + if (k1 - i > resultURLPreSuffixMaxSize) return False; // there's no room + while (k2 <= k1-1) resultURLPreSuffix[n++] = reqStr[k2++]; + } + resultURLPreSuffix[n] = '\0'; + decodeURL(resultURLPreSuffix); + + i = k + 7; // to go past " RTSP/" + parseSucceeded = True; + break; + } + } + if (!parseSucceeded) return False; + + // Look for "CSeq:" (mandatory, case insensitive), skip whitespace, + // then read everything up to the next \r or \n as 'CSeq': + parseSucceeded = False; + for (j = i; (int)j < (int)(reqStrSize-5); ++j) { + if (_strncasecmp("CSeq:", &reqStr[j], 5) == 0) { + j += 5; + while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; + unsigned n; + for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) { + char c = reqStr[j]; + if (c == '\r' || c == '\n') { + parseSucceeded = True; + break; + } + + resultCSeq[n] = c; + } + resultCSeq[n] = '\0'; + break; + } + } + if (!parseSucceeded) return False; + + // Look for "Session:" (optional, case insensitive), skip whitespace, + // then read everything up to the next \r or \n as 'Session': + resultSessionIdStr[0] = '\0'; // default value (empty string) + for (j = i; (int)j < (int)(reqStrSize-8); ++j) { + if (_strncasecmp("Session:", &reqStr[j], 8) == 0) { + j += 8; + while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; + unsigned n; + for (n = 0; n < resultSessionIdStrMaxSize-1 && j < reqStrSize; ++n,++j) { + char c = reqStr[j]; + if (c == '\r' || c == '\n') { + break; + } + + resultSessionIdStr[n] = c; + } + resultSessionIdStr[n] = '\0'; + break; + } + } + + // Also: Look for "Content-Length:" (optional, case insensitive) + contentLength = 0; // default value + for (j = i; (int)j < (int)(reqStrSize-15); ++j) { + if (_strncasecmp("Content-Length:", &(reqStr[j]), 15) == 0) { + j += 15; + while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; + unsigned num; + if (sscanf(&reqStr[j], "%u", &num) == 1) { + contentLength = num; + } + } + } + return True; +} + +Boolean parseRangeParam(char const* paramStr, + double& rangeStart, double& rangeEnd, + char*& absStartTime, char*& absEndTime, + Boolean& startTimeIsNow) { + delete[] absStartTime; delete[] absEndTime; + absStartTime = absEndTime = NULL; // by default, unless "paramStr" is a "clock=..." string + startTimeIsNow = False; // by default + double start, end; + int numCharsMatched1 = 0, numCharsMatched2 = 0, numCharsMatched3 = 0, numCharsMatched4 = 0; + int startHour = 0, startMin = 0, endHour = 0, endMin = 0; + double startSec = 0.0, endSec = 0.0; + Locale l("C", Numeric); + if (sscanf(paramStr, "npt = %d:%d:%lf - %d:%d:%lf", &startHour, &startMin, &startSec, &endHour, &endMin, &endSec) == 6) { + rangeStart = startHour*3600 + startMin*60 + startSec; + rangeEnd = endHour*3600 + endMin*60 + endSec; + } else if (sscanf(paramStr, "npt =%lf - %d:%d:%lf", &start, &endHour, &endMin, &endSec) == 4) { + rangeStart = start; + rangeEnd = endHour*3600 + endMin*60 + endSec; + } else if (sscanf(paramStr, "npt = %d:%d:%lf -", &startHour, &startMin, &startSec) == 3) { + rangeStart = startHour*3600 + startMin*60 + startSec; + rangeEnd = 0.0; + } else if (sscanf(paramStr, "npt = %lf - %lf", &start, &end) == 2) { + rangeStart = start; + rangeEnd = end; + } else if (sscanf(paramStr, "npt = %n%lf -", &numCharsMatched1, &start) == 1) { + if (paramStr[numCharsMatched1] == '-') { + // special case for "npt = -<endtime>", which matches here: + rangeStart = 0.0; startTimeIsNow = True; + rangeEnd = -start; + } else { + rangeStart = start; + rangeEnd = 0.0; + } + } else if (sscanf(paramStr, "npt = now - %lf", &end) == 1) { + rangeStart = 0.0; startTimeIsNow = True; + rangeEnd = end; + } else if (sscanf(paramStr, "npt = now -%n", &numCharsMatched2) == 0 && numCharsMatched2 > 0) { + rangeStart = 0.0; startTimeIsNow = True; + rangeEnd = 0.0; + } else if (sscanf(paramStr, "clock = %n", &numCharsMatched3) == 0 && numCharsMatched3 > 0) { + rangeStart = rangeEnd = 0.0; + + char const* utcTimes = ¶mStr[numCharsMatched3]; + size_t len = strlen(utcTimes) + 1; + char* as = new char[len]; + char* ae = new char[len]; + int sscanfResult = sscanf(utcTimes, "%[^-]-%[^\r\n]", as, ae); + if (sscanfResult == 2) { + absStartTime = as; + absEndTime = ae; + } else if (sscanfResult == 1) { + absStartTime = as; + delete[] ae; + } else { + delete[] as; delete[] ae; + return False; + } + } else if (sscanf(paramStr, "smtpe = %n", &numCharsMatched4) == 0 && numCharsMatched4 > 0) { + // We accept "smtpe=" parameters, but currently do not interpret them. + } else { + return False; // The header is malformed + } + + return True; +} + +Boolean parseRangeHeader(char const* buf, + double& rangeStart, double& rangeEnd, + char*& absStartTime, char*& absEndTime, + Boolean& startTimeIsNow) { + // First, find "Range:" + while (1) { + if (*buf == '\0') return False; // not found + if (_strncasecmp(buf, "Range: ", 7) == 0) break; + ++buf; + } + + char const* fields = buf + 7; + while (*fields == ' ') ++fields; + return parseRangeParam(fields, rangeStart, rangeEnd, absStartTime, absEndTime, startTimeIsNow); +} + +Boolean parseScaleHeader(char const* buf, float& scale) { + // Initialize the result parameter to a default value: + scale = 1.0; + + // First, find "Scale:" + while (1) { + if (*buf == '\0') return False; // not found + if (_strncasecmp(buf, "Scale:", 6) == 0) break; + ++buf; + } + + char const* fields = buf + 6; + while (*fields == ' ') ++fields; + float sc; + if (sscanf(fields, "%f", &sc) == 1) { + scale = sc; + } else { + return False; // The header is malformed + } + + return True; +} + +// Used to implement "RTSPOptionIsSupported()": +static Boolean isSeparator(char c) { return c == ' ' || c == ',' || c == ';' || c == ':'; } + +Boolean RTSPOptionIsSupported(char const* commandName, char const* optionsResponseString) { + do { + if (commandName == NULL || optionsResponseString == NULL) break; + + unsigned const commandNameLen = strlen(commandName); + if (commandNameLen == 0) break; + + // "optionsResponseString" is assumed to be a list of command names, separated by " " and/or ",", ";", or ":" + // Scan through these, looking for "commandName". + while (1) { + // Skip over separators: + while (*optionsResponseString != '\0' && isSeparator(*optionsResponseString)) ++optionsResponseString; + if (*optionsResponseString == '\0') break; + + // At this point, "optionsResponseString" begins with a command name (with perhaps a separator afterwads). + if (strncmp(commandName, optionsResponseString, commandNameLen) == 0) { + // We have at least a partial match here. + optionsResponseString += commandNameLen; + if (*optionsResponseString == '\0' || isSeparator(*optionsResponseString)) return True; + } + + // No match. Skip over the rest of the command name: + while (*optionsResponseString != '\0' && !isSeparator(*optionsResponseString)) ++optionsResponseString; + } + } while (0); + + return False; +} + +char const* dateHeader() { + static char buf[200]; +#if !defined(_WIN32_WCE) + time_t tt = time(NULL); + tm time_tm; +#ifdef _WIN32 + if (gmtime_s(&time_tm, &tt) != 0) { + time_tm = tm{}; + } +#else + if (gmtime_r(&tt, &time_tm) == NULL) { + time_tm = tm(); + } +#endif + static const char* day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static const char* month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + snprintf(buf, sizeof buf, "Date: %s, %s %02d %04d %02d:%02d:%02d GMT\r\n", + day[time_tm.tm_wday], month[time_tm.tm_mon], time_tm.tm_mday, + 1900 + time_tm.tm_year, + time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec); +#else + // WinCE apparently doesn't have "time()", or "gmtime()", + // so generate the "Date:" header a different, WinCE-specific way. + // (Thanks to Pierre l'Hussiez for this code) + // RSF: But where is the "Date: " string? This code doesn't look quite right... + SYSTEMTIME SystemTime; + GetSystemTime(&SystemTime); + WCHAR dateFormat[] = L"ddd, MMM dd yyyy"; + WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n"; + WCHAR inBuf[200]; + DWORD locale = LOCALE_NEUTRAL; + + int ret = GetDateFormat(locale, 0, &SystemTime, + (LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf); + inBuf[ret - 1] = ' '; + ret = GetTimeFormat(locale, 0, &SystemTime, + (LPTSTR)timeFormat, + (LPTSTR)inBuf + ret, (sizeof inBuf) - ret); + wcstombs(buf, inBuf, wcslen(inBuf)); +#endif + return buf; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/SIPClient.cpp new/live/liveMedia/SIPClient.cpp --- old/live/liveMedia/SIPClient.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/SIPClient.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -107,7 +107,6 @@ // Set the "User-Agent:" header to use in each request: char const* const libName = "LIVE555 Streaming Media v"; - char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; char const* libPrefix; char const* libSuffix; if (applicationName == NULL || applicationName[0] == '\0') { applicationName = libPrefix = libSuffix = ""; @@ -116,10 +115,10 @@ libSuffix = ")"; } unsigned userAgentNameSize - = fApplicationNameSize + strlen(libPrefix) + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix) + 1; + = fApplicationNameSize + strlen(libPrefix) + strlen(libName) + strlen(liveMediaLibraryVersionStr) + strlen(libSuffix) + 1; char* userAgentName = new char[userAgentNameSize]; sprintf(userAgentName, "%s%s%s%s%s", - applicationName, libPrefix, libName, libVersionStr, libSuffix); + applicationName, libPrefix, libName, liveMediaLibraryVersionStr, libSuffix); setUserAgentString(userAgentName); delete[] userAgentName; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/ServerMediaSession.cpp new/live/liveMedia/ServerMediaSession.cpp --- old/live/liveMedia/ServerMediaSession.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/ServerMediaSession.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -56,7 +56,6 @@ } static char const* const libNameStr = "LIVE555 Streaming Media v"; -char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; ServerMediaSession::ServerMediaSession(UsageEnvironment& env, char const* streamName, @@ -71,8 +70,8 @@ char* libNamePlusVersionStr = NULL; // by default if (info == NULL || description == NULL) { - libNamePlusVersionStr = new char[strlen(libNameStr) + strlen(libVersionStr) + 1]; - sprintf(libNamePlusVersionStr, "%s%s", libNameStr, libVersionStr); + libNamePlusVersionStr = new char[strlen(libNameStr) + strlen(liveMediaLibraryVersionStr) + 1]; + sprintf(libNamePlusVersionStr, "%s%s", libNameStr, liveMediaLibraryVersionStr); } fInfoSDPString = strDup(info == NULL ? libNamePlusVersionStr : info); fDescriptionSDPString = strDup(description == NULL ? libNamePlusVersionStr : description); @@ -288,7 +287,7 @@ + 20 + 6 + 20 + 3/*IP4 or IP6*/ + ipAddressStrSize + strlen(fDescriptionSDPString) + strlen(fInfoSDPString) - + strlen(libNameStr) + strlen(libVersionStr) + + strlen(libNameStr) + strlen(liveMediaLibraryVersionStr) + strlen(sourceFilterLine) + strlen(rangeLine) + strlen(fDescriptionSDPString) @@ -306,7 +305,7 @@ ipAddressStr.val(), // o= <address> fDescriptionSDPString, // s= <description> fInfoSDPString, // i= <info> - libNameStr, libVersionStr, // a=tool: + libNameStr, liveMediaLibraryVersionStr, // a=tool: sourceFilterLine, // a=source-filter: incl (if a SSM session) rangeLine, // a=range: line fDescriptionSDPString, // a=x-qt-text-nam: line diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/TLSState.cpp new/live/liveMedia/TLSState.cpp --- old/live/liveMedia/TLSState.cpp 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/TLSState.cpp 2024-06-26 07:46:23.000000000 +0200 @@ -228,7 +228,7 @@ if (SSL_CTX_set_ecdh_auto(fCtx, 1) != 1) break; - if (SSL_CTX_use_certificate_file(fCtx, fCertificateFileName, SSL_FILETYPE_PEM) != 1) break; + if (SSL_CTX_use_certificate_chain_file(fCtx, fCertificateFileName) != 1) break; if (SSL_CTX_use_PrivateKey_file(fCtx, fPrivateKeyFileName, SSL_FILETYPE_PEM) != 1) break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/live/liveMedia/include/QuickTimeFileSink.hh new/live/liveMedia/include/QuickTimeFileSink.hh --- old/live/liveMedia/include/QuickTimeFileSink.hh 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/include/QuickTimeFileSink.hh 2024-06-26 07:46:23.000000000 +0200 @@ -151,6 +151,8 @@ _atom(h263); _atom(avc1); _atom(avcC); + _atom(hvc1); + _atom(hvcC); _atom(mp4v); _atom(rtp); _atom(tims); 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 2023-11-30 09:22:23.000000000 +0100 +++ new/live/liveMedia/include/liveMedia_version.hh 2024-06-26 07:46:23.000000000 +0200 @@ -14,12 +14,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // Version information for the "liveMedia" library -// Copyright (c) 1996-2023 Live Networks, Inc. All rights reserved. +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. #ifndef _LIVEMEDIA_VERSION_HH #define _LIVEMEDIA_VERSION_HH -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2023.11.30" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1701302400 +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2024.06.26" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1719360000 + +extern char const* const liveMediaLibraryVersionStr; +extern int const liveMediaLibraryVersionInt; #endif
participants (1)
-
Source-Sync