From ceeb4f462709695b145852de309d8cd25e2dca01 Mon Sep 17 00:00:00 2001 From: Roman Gaufman Date: Sun, 2 Sep 2018 23:16:00 +0100 Subject: [PATCH] Bump to version 2018.08.28 --- .../include/BasicUsageEnvironment_version.hh | 4 +- README.md | 12 +- .../include/UsageEnvironment_version.hh | 4 +- config.linux-with-shared-libraries | 10 +- groupsock/GroupsockHelper.cpp | 45 ++++- groupsock/include/GroupsockHelper.hh | 3 +- groupsock/include/groupsock_version.hh | 4 +- liveMedia/GenericMediaServer.cpp | 2 +- liveMedia/Makefile.tail | 6 +- liveMedia/MediaSession.cpp | 3 + liveMedia/RTCP.cpp | 2 +- liveMedia/RTSPServer.cpp | 9 +- liveMedia/RawVideoRTPSource.cpp | 182 ++++++++++++++++++ liveMedia/include/MultiFramedRTPSource.hh | 2 +- liveMedia/include/RawVideoRTPSource.hh | 60 ++++++ liveMedia/include/liveMedia.hh | 1 + liveMedia/include/liveMedia_version.hh | 4 +- liveMedia/stDjgzxL | 0 mediaServer/version.hh | 2 +- testProgs/playCommon.cpp | 2 +- 20 files changed, 330 insertions(+), 27 deletions(-) create mode 100644 liveMedia/RawVideoRTPSource.cpp create mode 100644 liveMedia/include/RawVideoRTPSource.hh delete mode 100644 liveMedia/stDjgzxL diff --git a/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh b/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh index 4c4494d7..f762bbaa 100644 --- a/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh +++ b/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh @@ -4,7 +4,7 @@ #ifndef _BASICUSAGEENVIRONMENT_VERSION_HH #define _BASICUSAGEENVIRONMENT_VERSION_HH -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2018.04.25" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1524614400 +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2018.08.28" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1535414400 #endif diff --git a/README.md b/README.md index 23cbde99..39aabe1b 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,17 @@ You will find various executables: # Changes to Master -See modifications.patch to see exactly what was changed compared to vanilla. - ### Buffer sizes - OutPacketBuffer::maxSize is increased to 2,000,000 bytes which makes live555 work better with buggy IP cameras. ### Force port re-use - Added -DALLOW_RTSP_SERVER_PORT_REUSE=1 to force reusing existing port (e.g. when restarting the proxy). Please ensure you never run multiple instances of the proxy on the same port! + +### Quit on TCP Errors +liveMedia/RTCP.cpp#422 is changed to exit(1); - this ensures that live555 does not flood the screen and/or log with: +The remote endpoint is using a buggy implementation of RTP/RTCP-over-TCP. Please upgrade it! + +### Add -d option +See Proxyserver_check_interPacketGap_2017.01.26.patch - This allows specifying a number of seconds of inactivity +before timing out the connection. \ No newline at end of file diff --git a/UsageEnvironment/include/UsageEnvironment_version.hh b/UsageEnvironment/include/UsageEnvironment_version.hh index 1376d862..8a87d4eb 100644 --- a/UsageEnvironment/include/UsageEnvironment_version.hh +++ b/UsageEnvironment/include/UsageEnvironment_version.hh @@ -4,7 +4,7 @@ #ifndef _USAGEENVIRONMENT_VERSION_HH #define _USAGEENVIRONMENT_VERSION_HH -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2018.04.25" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1524614400 +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2018.08.28" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1535414400 #endif diff --git a/config.linux-with-shared-libraries b/config.linux-with-shared-libraries index 980fa873..a107e462 100644 --- a/config.linux-with-shared-libraries +++ b/config.linux-with-shared-libraries @@ -3,9 +3,9 @@ # 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=62 -libliveMedia_VERSION_REVISION=5 -libliveMedia_VERSION_AGE=0 +libliveMedia_VERSION_CURRENT=63 +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=1 @@ -18,9 +18,9 @@ libUsageEnvironment_VERSION_REVISION=0 libUsageEnvironment_VERSION_AGE=1 libUsageEnvironment_LIB_SUFFIX=so.$(shell expr $(libUsageEnvironment_VERSION_CURRENT) - $(libUsageEnvironment_VERSION_AGE)).$(libUsageEnvironment_VERSION_AGE).$(libUsageEnvironment_VERSION_REVISION) -libgroupsock_VERSION_CURRENT=9 +libgroupsock_VERSION_CURRENT=10 libgroupsock_VERSION_REVISION=1 -libgroupsock_VERSION_AGE=1 +libgroupsock_VERSION_AGE=2 libgroupsock_LIB_SUFFIX=so.$(shell expr $(libgroupsock_VERSION_CURRENT) - $(libgroupsock_VERSION_AGE)).$(libgroupsock_VERSION_AGE).$(libgroupsock_VERSION_REVISION) ##### diff --git a/groupsock/GroupsockHelper.cpp b/groupsock/GroupsockHelper.cpp index 4cf045ef..75ef08dd 100644 --- a/groupsock/GroupsockHelper.cpp +++ b/groupsock/GroupsockHelper.cpp @@ -27,6 +27,9 @@ extern "C" int initializeWinsockIfNecessary(); #include #include #include +#if !defined(_WIN32) +#include +#endif #include #define initializeWinsockIfNecessary() 1 #endif @@ -217,8 +220,38 @@ Boolean makeSocketBlocking(int sock, unsigned writeTimeoutInMilliseconds) { return result; } +Boolean setSocketKeepAlive(int sock) { +#if defined(__WIN32__) || defined(_WIN32) + // How do we do this in Windows? For now, just make this a no-op in Windows: +#else + int const keepalive_enabled = 1; + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepalive_enabled, sizeof keepalive_enabled) < 0) { + return False; + } + +#ifdef TCP_KEEPIDLE + int const keepalive_time = 180; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&keepalive_time, sizeof keepalive_time) < 0) { + return False; + } +#endif + + int const keepalive_count = 5; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void*)&keepalive_count, sizeof keepalive_count) < 0) { + return False; + } + + int const keepalive_interval = 20; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&keepalive_interval, sizeof keepalive_interval) < 0) { + return False; + } +#endif + + return True; +} + int setupStreamSocket(UsageEnvironment& env, - Port port, Boolean makeNonBlocking) { + Port port, Boolean makeNonBlocking, Boolean setKeepAlive) { if (!initializeWinsockIfNecessary()) { socketErr(env, "Failed to initialize 'winsock': "); return -1; @@ -284,6 +317,16 @@ int setupStreamSocket(UsageEnvironment& env, } } + // Set the keep alive mechanism for the TCP socket, to avoid "ghost sockets" + // that remain after an interrupted communication. + if (setKeepAlive) { + if (!setSocketKeepAlive(newSocket)) { + socketErr(env, "failed to set keep alive: "); + closeSocket(newSocket); + return -1; + } + } + return newSocket; } diff --git a/groupsock/include/GroupsockHelper.hh b/groupsock/include/GroupsockHelper.hh index 2989ce72..ae1d6c3f 100644 --- a/groupsock/include/GroupsockHelper.hh +++ b/groupsock/include/GroupsockHelper.hh @@ -27,7 +27,7 @@ along with this library; if not, write to the Free Software Foundation, Inc., int setupDatagramSocket(UsageEnvironment& env, Port port); int setupStreamSocket(UsageEnvironment& env, - Port port, Boolean makeNonBlocking = True); + Port port, Boolean makeNonBlocking = True, Boolean setKeepAlive = False); int readSocket(UsageEnvironment& env, int socket, unsigned char* buffer, unsigned bufferSize, @@ -59,6 +59,7 @@ unsigned increaseReceiveBufferTo(UsageEnvironment& env, Boolean makeSocketNonBlocking(int sock); Boolean makeSocketBlocking(int sock, unsigned writeTimeoutInMilliseconds = 0); // A "writeTimeoutInMilliseconds" value of 0 means: Don't timeout +Boolean setSocketKeepAlive(int sock); Boolean socketJoinGroup(UsageEnvironment& env, int socket, netAddressBits groupAddress); diff --git a/groupsock/include/groupsock_version.hh b/groupsock/include/groupsock_version.hh index 7646c42b..1da03622 100644 --- a/groupsock/include/groupsock_version.hh +++ b/groupsock/include/groupsock_version.hh @@ -4,7 +4,7 @@ #ifndef _GROUPSOCK_VERSION_HH #define _GROUPSOCK_VERSION_HH -#define GROUPSOCK_LIBRARY_VERSION_STRING "2018.04.25" -#define GROUPSOCK_LIBRARY_VERSION_INT 1524614400 +#define GROUPSOCK_LIBRARY_VERSION_STRING "2018.08.28" +#define GROUPSOCK_LIBRARY_VERSION_INT 1535414400 #endif diff --git a/liveMedia/GenericMediaServer.cpp b/liveMedia/GenericMediaServer.cpp index f286ca6a..46905163 100644 --- a/liveMedia/GenericMediaServer.cpp +++ b/liveMedia/GenericMediaServer.cpp @@ -149,7 +149,7 @@ int GenericMediaServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) { NoReuse dummy(env); // Don't use this socket if there's already a local server using it #endif - ourSocket = setupStreamSocket(env, ourPort); + ourSocket = setupStreamSocket(env, ourPort, True, True); if (ourSocket < 0) break; // Make sure we have a big send buffer: diff --git a/liveMedia/Makefile.tail b/liveMedia/Makefile.tail index 92dbc834..e0851533 100644 --- a/liveMedia/Makefile.tail +++ b/liveMedia/Makefile.tail @@ -27,7 +27,7 @@ MISC_SINK_OBJS = MediaSink.$(OBJ) FileSink.$(OBJ) BasicUDPSink.$(OBJ) AMRAudioFi MISC_FILTER_OBJS = uLawAudioFilter.$(OBJ) TRANSPORT_STREAM_TRICK_PLAY_OBJS = MPEG2IndexFromTransportStream.$(OBJ) MPEG2TransportStreamIndexFile.$(OBJ) MPEG2TransportStreamTrickModeFilter.$(OBJ) -RTP_SOURCE_OBJS = RTPSource.$(OBJ) MultiFramedRTPSource.$(OBJ) SimpleRTPSource.$(OBJ) H261VideoRTPSource.$(OBJ) H264VideoRTPSource.$(OBJ) H265VideoRTPSource.$(OBJ) QCELPAudioRTPSource.$(OBJ) AMRAudioRTPSource.$(OBJ) JPEGVideoRTPSource.$(OBJ) VorbisAudioRTPSource.$(OBJ) TheoraVideoRTPSource.$(OBJ) VP8VideoRTPSource.$(OBJ) VP9VideoRTPSource.$(OBJ) +RTP_SOURCE_OBJS = RTPSource.$(OBJ) MultiFramedRTPSource.$(OBJ) SimpleRTPSource.$(OBJ) H261VideoRTPSource.$(OBJ) H264VideoRTPSource.$(OBJ) H265VideoRTPSource.$(OBJ) QCELPAudioRTPSource.$(OBJ) AMRAudioRTPSource.$(OBJ) JPEGVideoRTPSource.$(OBJ) VorbisAudioRTPSource.$(OBJ) TheoraVideoRTPSource.$(OBJ) VP8VideoRTPSource.$(OBJ) VP9VideoRTPSource.$(OBJ) RawVideoRTPSource.$(OBJ) RTP_SINK_OBJS = RTPSink.$(OBJ) MultiFramedRTPSink.$(OBJ) AudioRTPSink.$(OBJ) VideoRTPSink.$(OBJ) TextRTPSink.$(OBJ) RTP_INTERFACE_OBJS = RTPInterface.$(OBJ) RTP_OBJS = $(RTP_SOURCE_OBJS) $(RTP_SINK_OBJS) $(RTP_INTERFACE_OBJS) @@ -98,6 +98,8 @@ VP8VideoRTPSource.$(CPP): include/VP8VideoRTPSource.hh include/VP8VideoRTPSource.hh: include/MultiFramedRTPSource.hh VP9VideoRTPSource.$(CPP): include/VP9VideoRTPSource.hh include/VP9VideoRTPSource.hh: include/MultiFramedRTPSource.hh +RawVideoRTPSource.$(CPP): include/RawVideoRTPSource.hh +include/RawVideoRTPSource.hh: include/MultiFramedRTPSource.hh ByteStreamFileSource.$(CPP): include/ByteStreamFileSource.hh include/InputFile.hh include/ByteStreamFileSource.hh: include/FramedFileSource.hh ByteStreamMultiFileSource.$(CPP): include/ByteStreamMultiFileSource.hh @@ -383,7 +385,7 @@ ourMD5.$(CPP): include/ourMD5.hh Base64.$(CPP): include/Base64.hh Locale.$(CPP): include/Locale.hh -include/liveMedia.hh:: include/MPEG1or2AudioRTPSink.hh include/MP3ADURTPSink.hh include/MPEG1or2VideoRTPSink.hh include/MPEG4ESVideoRTPSink.hh include/BasicUDPSink.hh include/AMRAudioFileSink.hh include/H264VideoFileSink.hh include/H265VideoFileSink.hh include/OggFileSink.hh include/GSMAudioRTPSink.hh include/H263plusVideoRTPSink.hh include/H264VideoRTPSink.hh include/H265VideoRTPSink.hh include/DVVideoRTPSource.hh include/DVVideoRTPSink.hh include/DVVideoStreamFramer.hh include/H264VideoStreamFramer.hh include/H265VideoStreamFramer.hh include/H264VideoStreamDiscreteFramer.hh include/H265VideoStreamDiscreteFramer.hh include/JPEGVideoRTPSink.hh include/SimpleRTPSink.hh include/uLawAudioFilter.hh include/MPEG2IndexFromTransportStream.hh include/MPEG2TransportStreamTrickModeFilter.hh include/ByteStreamMultiFileSource.hh include/ByteStreamMemoryBufferSource.hh include/BasicUDPSource.hh include/SimpleRTPSource.hh include/MPEG1or2AudioRTPSource.hh include/MPEG4LATMAudioRTPSource.hh include/MPEG4LATMAudioRTPSink.hh include/MPEG4ESVideoRTPSource.hh include/MPEG4GenericRTPSource.hh include/MP3ADURTPSource.hh include/QCELPAudioRTPSource.hh include/AMRAudioRTPSource.hh include/JPEGVideoRTPSource.hh include/JPEGVideoSource.hh include/MPEG1or2VideoRTPSource.hh include/VorbisAudioRTPSource.hh include/TheoraVideoRTPSource.hh include/VP8VideoRTPSource.hh include/VP9VideoRTPSource.hh +include/liveMedia.hh:: include/MPEG1or2AudioRTPSink.hh include/MP3ADURTPSink.hh include/MPEG1or2VideoRTPSink.hh include/MPEG4ESVideoRTPSink.hh include/BasicUDPSink.hh include/AMRAudioFileSink.hh include/H264VideoFileSink.hh include/H265VideoFileSink.hh include/OggFileSink.hh include/GSMAudioRTPSink.hh include/H263plusVideoRTPSink.hh include/H264VideoRTPSink.hh include/H265VideoRTPSink.hh include/DVVideoRTPSource.hh include/DVVideoRTPSink.hh include/DVVideoStreamFramer.hh include/H264VideoStreamFramer.hh include/H265VideoStreamFramer.hh include/H264VideoStreamDiscreteFramer.hh include/H265VideoStreamDiscreteFramer.hh include/JPEGVideoRTPSink.hh include/SimpleRTPSink.hh include/uLawAudioFilter.hh include/MPEG2IndexFromTransportStream.hh include/MPEG2TransportStreamTrickModeFilter.hh include/ByteStreamMultiFileSource.hh include/ByteStreamMemoryBufferSource.hh include/BasicUDPSource.hh include/SimpleRTPSource.hh include/MPEG1or2AudioRTPSource.hh include/MPEG4LATMAudioRTPSource.hh include/MPEG4LATMAudioRTPSink.hh include/MPEG4ESVideoRTPSource.hh include/MPEG4GenericRTPSource.hh include/MP3ADURTPSource.hh include/QCELPAudioRTPSource.hh include/AMRAudioRTPSource.hh include/JPEGVideoRTPSource.hh include/JPEGVideoSource.hh include/MPEG1or2VideoRTPSource.hh include/VorbisAudioRTPSource.hh include/TheoraVideoRTPSource.hh include/VP8VideoRTPSource.hh include/VP9VideoRTPSource.hh include/RawVideoRTPSource.hh include/liveMedia.hh:: include/MPEG2TransportStreamFromPESSource.hh include/MPEG2TransportStreamFromESSource.hh include/MPEG2TransportStreamFramer.hh include/ADTSAudioFileSource.hh include/H261VideoRTPSource.hh include/H263plusVideoRTPSource.hh include/H264VideoRTPSource.hh include/H265VideoRTPSource.hh include/MP3FileSource.hh include/MP3ADU.hh include/MP3ADUinterleaving.hh include/MP3Transcoder.hh include/MPEG1or2DemuxedElementaryStream.hh include/MPEG1or2AudioStreamFramer.hh include/MPEG1or2VideoStreamDiscreteFramer.hh include/MPEG4VideoStreamDiscreteFramer.hh include/H263plusVideoStreamFramer.hh include/AC3AudioStreamFramer.hh include/AC3AudioRTPSource.hh include/AC3AudioRTPSink.hh include/VorbisAudioRTPSink.hh include/TheoraVideoRTPSink.hh include/VP8VideoRTPSink.hh include/VP9VideoRTPSink.hh include/MPEG4GenericRTPSink.hh include/DeviceSource.hh include/AudioInputDevice.hh include/WAVAudioFileSource.hh include/StreamReplicator.hh include/RTSPRegisterSender.hh diff --git a/liveMedia/MediaSession.cpp b/liveMedia/MediaSession.cpp index 734efe91..3a09af91 100644 --- a/liveMedia/MediaSession.cpp +++ b/liveMedia/MediaSession.cpp @@ -1267,6 +1267,9 @@ Boolean MediaSubsession::createSourceObjects(int useSpecialRTPoffset) { } else if (strcmp(fCodecName, "THEORA") == 0) { // Theora video fReadSource = fRTPSource = TheoraVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat); + } else if (strcmp(fCodecName, "RAW") == 0) { // Uncompressed raw video (RFC 4175) + fReadSource = fRTPSource + = RawVideoRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, fRTPTimestampFrequency); } else if (strcmp(fCodecName, "VP8") == 0) { // VP8 video fReadSource = fRTPSource = VP8VideoRTPSource::createNew(env(), fRTPSocket, diff --git a/liveMedia/RTCP.cpp b/liveMedia/RTCP.cpp index 1a98b18a..495f3c05 100644 --- a/liveMedia/RTCP.cpp +++ b/liveMedia/RTCP.cpp @@ -419,7 +419,7 @@ void RTCPInstance::incomingReportHandler1() { envir() << "RTCPInstance error: Hit limit when reading incoming packet over TCP. (fNumBytesAlreadyRead (" << fNumBytesAlreadyRead << ") >= maxRTCPPacketSize (" << maxRTCPPacketSize << ")). The remote endpoint is using a buggy implementation of RTP/RTCP-over-TCP. Please upgrade it!\n"; - break; + exit(1); } unsigned numBytesRead; diff --git a/liveMedia/RTSPServer.cpp b/liveMedia/RTSPServer.cpp index fcff8b23..87d723cd 100644 --- a/liveMedia/RTSPServer.cpp +++ b/liveMedia/RTSPServer.cpp @@ -699,6 +699,7 @@ void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) { char cseq[RTSP_PARAM_STRING_MAX]; char sessionIdStr[RTSP_PARAM_STRING_MAX]; unsigned contentLength = 0; + Boolean playAfterSetup = False; fLastCRLF[2] = '\0'; // temporarily, for parsing Boolean parseSucceeded = parseRTSPRequestString((char*)fRequestBuffer, fLastCRLF+2 - fRequestBuffer, cmdName, sizeof cmdName, @@ -708,7 +709,13 @@ void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) { sessionIdStr, sizeof sessionIdStr, contentLength); fLastCRLF[2] = '\r'; // restore its value - Boolean playAfterSetup = False; + // Check first for a bogus "Content-Length" value that would cause a pointer wraparound: + if (tmpPtr + 2 + contentLength < tmpPtr + 2) { +#ifdef DEBUG + fprintf(stderr, "parseRTSPRequestString() returned a bogus \"Content-Length:\" value: 0x%x (%d)\n", contentLength, (int)contentLength); +#endif + parseSucceeded = False; + } if (parseSucceeded) { #ifdef DEBUG fprintf(stderr, "parseRTSPRequestString() succeeded, returning cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\", CSeq \"%s\", Content-Length %u, with %d bytes following the message.\n", cmdName, urlPreSuffix, urlSuffix, cseq, contentLength, ptr + newBytesRead - (tmpPtr + 2)); diff --git a/liveMedia/RawVideoRTPSource.cpp b/liveMedia/RawVideoRTPSource.cpp new file mode 100644 index 00000000..e584c435 --- /dev/null +++ b/liveMedia/RawVideoRTPSource.cpp @@ -0,0 +1,182 @@ +/********** +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 .) + +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-2018 Live Networks, Inc. All rights reserved. +// Raw Video RTP Sources (RFC 4175) +// Implementation + +#include "RawVideoRTPSource.hh" + +////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory ////////// + +class RawVideoBufferedPacket: public BufferedPacket { +public: + RawVideoBufferedPacket(RawVideoRTPSource* ourSource); + virtual ~RawVideoBufferedPacket(); + +private: // redefined virtual functions + virtual void getNextEnclosedFrameParameters(unsigned char*& framePtr, + unsigned dataSize, + unsigned& frameSize, + unsigned& frameDurationInMicroseconds); +private: + RawVideoRTPSource* fOurSource; +}; + +class RawVideoBufferedPacketFactory: public BufferedPacketFactory { +private: // redefined virtual functions + virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); +}; + + +////////// LineHeader ////////// + +struct LineHeader { + u_int16_t length; + u_int16_t fieldIdAndLineNumber; + u_int16_t offsetWithinLine; +}; + + +///////// RawVideoRTPSource implementation (RFC 4175) //////// + +RawVideoRTPSource* +RawVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency) { + return new RawVideoRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); +} + +RawVideoRTPSource +::RawVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency) + : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, + new RawVideoBufferedPacketFactory), + fNumLines(0), fNextLine(0), fLineHeaders(NULL) { +} + +RawVideoRTPSource::~RawVideoRTPSource() { + delete[] fLineHeaders; +} + +u_int16_t RawVideoRTPSource::currentLineNumber() const { + if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! + return fLineHeaders[fNextLine-1].fieldIdAndLineNumber&0x7FFF; +} + +u_int8_t RawVideoRTPSource::currentLineFieldId() const { + if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! + return (fLineHeaders[fNextLine-1].fieldIdAndLineNumber&0x8000)>>15; +} + +u_int16_t RawVideoRTPSource::currentOffsetWithinLine() const { + if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! + return fLineHeaders[fNextLine-1].offsetWithinLine; +} + +Boolean RawVideoRTPSource +::processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize) { + + unsigned char* headerStart = packet->data(); + unsigned packetSize = packet->dataSize(); + + // The first 2 bytes of the header are the "Extended Sequence Number". + // In the current implementation, we ignore this. + if (packetSize < 2) return False; + headerStart += 2; + unsigned char* lineHeaderStart = headerStart; + packetSize -= 2; + + // The rest of the header should consist of N*6 bytes (with N >= 1) for each line included. + // Count how many of these there are: + unsigned numLines = 0; + while (1) { + if (packetSize < 6) return False; // there's not enough room for another line header + ++numLines; + Boolean continuationBit = (headerStart[4]&0x80)>>7; + headerStart += 6; + packetSize -= 6; + + // Check the "C" (continuation) bit of this header to see whether any more line headers follow: + if (continuationBit == 0) break; // no more line headers follow + } + + // We now know how many lines are contained in this payload. Allocate and fill in "fLineHeaders": + fNumLines = numLines; // ASSERT: >= 1 + fNextLine = 0; + delete[] fLineHeaders; fLineHeaders = new LineHeader[fNumLines]; + unsigned totalLength = 0; + for (unsigned i = 0; i < fNumLines; ++i) { + fLineHeaders[i].length = (lineHeaderStart[0]<<8) + lineHeaderStart[1]; + totalLength += fLineHeaders[i].length; + fLineHeaders[i].fieldIdAndLineNumber = (lineHeaderStart[2]<<8) + lineHeaderStart[3]; + fLineHeaders[i].offsetWithinLine = ((lineHeaderStart[4]&0x7F)<<8) + lineHeaderStart[5]; + lineHeaderStart += 6; + } + + // Make sure that we have enough bytes for all of the line lengths promised: + if (totalLength > packetSize) { + fNumLines = 0; + delete[] fLineHeaders; + return False; + } + + // Everything looks good: + fCurrentPacketBeginsFrame + = (fLineHeaders[0].fieldIdAndLineNumber&0x7FFF) == 0 && fLineHeaders[0].offsetWithinLine == 0; + fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); + resultSpecialHeaderSize = headerStart - packet->data(); + return True; +} + +char const* RawVideoRTPSource::MIMEtype() const { + return "video/RAW"; +} + + +////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory implementation ////////// + +RawVideoBufferedPacket +::RawVideoBufferedPacket(RawVideoRTPSource* ourSource) + : fOurSource(ourSource) { +} + +RawVideoBufferedPacket::~RawVideoBufferedPacket() { +} + +void RawVideoBufferedPacket::getNextEnclosedFrameParameters(unsigned char*& /*framePtr*/, + unsigned dataSize, + unsigned& frameSize, + unsigned& frameDurationInMicroseconds) { + frameDurationInMicroseconds = 0; // because all lines within the same packet are from the same frame + + if (fOurSource->fNextLine >= fOurSource->fNumLines) { + fOurSource->envir() << "RawVideoBufferedPacket::nextEnclosedFrameParameters(" + << dataSize << "): data error (" + << fOurSource->fNextLine << " >= " << fOurSource->fNumLines << ")!\n"; + frameSize = dataSize; + return; + } + + frameSize = fOurSource->fLineHeaders[fOurSource->fNextLine++].length; +} + +BufferedPacket* RawVideoBufferedPacketFactory +::createNewPacket(MultiFramedRTPSource* ourSource) { + return new RawVideoBufferedPacket((RawVideoRTPSource*)ourSource); +} diff --git a/liveMedia/include/MultiFramedRTPSource.hh b/liveMedia/include/MultiFramedRTPSource.hh index 3d664a19..cc41fa28 100644 --- a/liveMedia/include/MultiFramedRTPSource.hh +++ b/liveMedia/include/MultiFramedRTPSource.hh @@ -81,7 +81,7 @@ private: // A 'packet data' class that's used to implement the above. // Note that this can be subclassed - if desired - to redefine -// "nextEnclosedFrameSize()". +// "nextEnclosedFrameParameters()". class BufferedPacket { public: diff --git a/liveMedia/include/RawVideoRTPSource.hh b/liveMedia/include/RawVideoRTPSource.hh new file mode 100644 index 00000000..27ddbf61 --- /dev/null +++ b/liveMedia/include/RawVideoRTPSource.hh @@ -0,0 +1,60 @@ +/********** +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 .) + +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-2018 Live Networks, Inc. All rights reserved. +// Raw Video RTP Sources (RFC 4175) +// C++ header + +#ifndef _RAW_VIDEO_RTP_SOURCE_HH +#define _RAW_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class RawVideoRTPSource: public MultiFramedRTPSource { +public: + static RawVideoRTPSource* createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + + u_int16_t currentLineNumber() const; // of the most recently-read/processed scan line + u_int8_t currentLineFieldId() const; // of the most recently-read/processed scan line (0 or 1) + u_int16_t currentOffsetWithinLine() const; // of the most recently-read/processed scan line + +protected: + RawVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + // called only by createNew() + + virtual ~RawVideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + unsigned fNumLines; // in the most recently read packet + unsigned fNextLine; // index of the next AU Header to read + struct LineHeader* fLineHeaders; + + friend class RawVideoBufferedPacket; +}; + +#endif diff --git a/liveMedia/include/liveMedia.hh b/liveMedia/include/liveMedia.hh index 204c8dd6..d1fa0b30 100644 --- a/liveMedia/include/liveMedia.hh +++ b/liveMedia/include/liveMedia.hh @@ -68,6 +68,7 @@ along with this library; if not, write to the Free Software Foundation, Inc., #include "TheoraVideoRTPSource.hh" #include "VP8VideoRTPSource.hh" #include "VP9VideoRTPSource.hh" +#include "RawVideoRTPSource.hh" #include "MPEG2TransportStreamFromPESSource.hh" #include "MPEG2TransportStreamFromESSource.hh" #include "MPEG2TransportStreamFramer.hh" diff --git a/liveMedia/include/liveMedia_version.hh b/liveMedia/include/liveMedia_version.hh index 5e431d4a..774c5622 100644 --- a/liveMedia/include/liveMedia_version.hh +++ b/liveMedia/include/liveMedia_version.hh @@ -4,7 +4,7 @@ #ifndef _LIVEMEDIA_VERSION_HH #define _LIVEMEDIA_VERSION_HH -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2018.04.25" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1524614400 +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2018.08.28" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1535414400 #endif diff --git a/liveMedia/stDjgzxL b/liveMedia/stDjgzxL deleted file mode 100644 index e69de29b..00000000 diff --git a/mediaServer/version.hh b/mediaServer/version.hh index 5951bd67..ee13f1d8 100644 --- a/mediaServer/version.hh +++ b/mediaServer/version.hh @@ -5,6 +5,6 @@ #ifndef _MEDIA_SERVER_VERSION_HH #define _MEDIA_SERVER_VERSION_HH -#define MEDIA_SERVER_VERSION_STRING "0.91" +#define MEDIA_SERVER_VERSION_STRING "0.92" #endif diff --git a/testProgs/playCommon.cpp b/testProgs/playCommon.cpp index 3d162d06..774c06f3 100644 --- a/testProgs/playCommon.cpp +++ b/testProgs/playCommon.cpp @@ -1138,7 +1138,7 @@ void sessionAfterPlaying(void* /*clientData*/) { // We've been asked to play the stream(s) over again. // First, reset state from the current session: if (env != NULL) { - env->taskScheduler().unscheduleDelayedTask(periodicFileOutputTask); + // Keep this running: env->taskScheduler().unscheduleDelayedTask(periodicFileOutputTask); env->taskScheduler().unscheduleDelayedTask(sessionTimerTask); env->taskScheduler().unscheduleDelayedTask(sessionTimeoutBrokenServerTask); env->taskScheduler().unscheduleDelayedTask(arrivalCheckTimerTask);