From c3c24a6e2ec61b3a703df1f5aad20df64a262c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E4=BD=B3=E9=BE=99?= <2601721443@qq.com> Date: Thu, 21 Mar 2024 16:36:26 +0800 Subject: [PATCH] 1 --- CMakeLists.txt | 52 + auto_cmake.bat | 6 + includes/getData.hpp | 16 + includes/getopt.h | 115 + .../BasicUsageEnvironment/BasicHashTable.hh | 104 + .../BasicUsageEnvironment.hh | 86 + .../BasicUsageEnvironment0.hh | 131 + .../BasicUsageEnvironment_version.hh | 25 + .../BasicUsageEnvironment/DelayQueue.hh | 181 + .../BasicUsageEnvironment/HandlerSet.hh | 77 + .../EpollTaskScheduler/EpollTaskScheduler.hh | 56 + includes/live555/UsageEnvironment/Boolean.hh | 37 + .../live555/UsageEnvironment/HashTable.hh | 76 + .../UsageEnvironment/UsageEnvironment.hh | 176 + .../UsageEnvironment_version.hh | 25 + includes/live555/UsageEnvironment/strDup.hh | 37 + includes/live555/groupsock/GroupEId.hh | 64 + includes/live555/groupsock/Groupsock.hh | 201 + includes/live555/groupsock/GroupsockHelper.hh | 166 + includes/live555/groupsock/IOHandlers.hh | 31 + includes/live555/groupsock/NetAddress.hh | 209 + includes/live555/groupsock/NetCommon.h | 126 + includes/live555/groupsock/NetInterface.hh | 109 + includes/live555/groupsock/TunnelEncaps.hh | 101 + .../live555/groupsock/groupsock_version.hh | 25 + .../AC3AudioFileServerMediaSubsession.hh | 48 + includes/live555/liveMedia/AC3AudioRTPSink.hh | 57 + .../live555/liveMedia/AC3AudioRTPSource.hh | 51 + .../live555/liveMedia/AC3AudioStreamFramer.hh | 70 + .../ADTSAudioFileServerMediaSubsession.hh | 48 + .../live555/liveMedia/ADTSAudioFileSource.hh | 56 + .../ADTSAudioStreamDiscreteFramer.hh | 61 + .../AMRAudioFileServerMediaSubsession.hh | 48 + .../live555/liveMedia/AMRAudioFileSink.hh | 51 + .../live555/liveMedia/AMRAudioFileSource.hh | 48 + includes/live555/liveMedia/AMRAudioRTPSink.hh | 65 + .../live555/liveMedia/AMRAudioRTPSource.hh | 53 + includes/live555/liveMedia/AMRAudioSource.hh | 52 + includes/live555/liveMedia/AVIFileSink.hh | 115 + .../live555/liveMedia/AudioInputDevice.hh | 71 + includes/live555/liveMedia/AudioRTPSink.hh | 42 + includes/live555/liveMedia/Base64.hh | 43 + includes/live555/liveMedia/BasicUDPSink.hh | 62 + includes/live555/liveMedia/BasicUDPSource.hh | 56 + includes/live555/liveMedia/BitVector.hh | 67 + .../live555/liveMedia/ByteStreamFileSource.hh | 82 + .../liveMedia/ByteStreamMemoryBufferSource.hh | 70 + .../liveMedia/ByteStreamMultiFileSource.hh | 69 + .../DVVideoFileServerMediaSubsession.hh | 51 + includes/live555/liveMedia/DVVideoRTPSink.hh | 57 + .../live555/liveMedia/DVVideoRTPSource.hh | 51 + .../live555/liveMedia/DVVideoStreamFramer.hh | 72 + includes/live555/liveMedia/DeviceSource.hh | 66 + .../live555/liveMedia/DigestAuthentication.hh | 75 + .../liveMedia/FileServerMediaSubsession.hh | 43 + includes/live555/liveMedia/FileSink.hh | 71 + .../live555/liveMedia/FramedFileSource.hh | 37 + includes/live555/liveMedia/FramedFilter.hh | 52 + includes/live555/liveMedia/FramedSource.hh | 95 + includes/live555/liveMedia/GSMAudioRTPSink.hh | 44 + .../live555/liveMedia/GenericMediaServer.hh | 224 + .../live555/liveMedia/H261VideoRTPSource.hh | 56 + .../H263plusVideoFileServerMediaSubsession.hh | 48 + .../live555/liveMedia/H263plusVideoRTPSink.hh | 54 + .../liveMedia/H263plusVideoRTPSource.hh | 60 + .../liveMedia/H263plusVideoStreamFramer.hh | 64 + .../H264VideoFileServerMediaSubsession.hh | 61 + .../live555/liveMedia/H264VideoFileSink.hh | 47 + .../live555/liveMedia/H264VideoRTPSink.hh | 59 + .../live555/liveMedia/H264VideoRTPSource.hh | 70 + .../H264VideoStreamDiscreteFramer.hh | 48 + .../liveMedia/H264VideoStreamFramer.hh | 45 + .../live555/liveMedia/H264or5VideoFileSink.hh | 46 + .../live555/liveMedia/H264or5VideoRTPSink.hh | 60 + .../H264or5VideoStreamDiscreteFramer.hh | 56 + .../liveMedia/H264or5VideoStreamFramer.hh | 92 + .../H265VideoFileServerMediaSubsession.hh | 61 + .../live555/liveMedia/H265VideoFileSink.hh | 51 + .../live555/liveMedia/H265VideoRTPSink.hh | 62 + .../live555/liveMedia/H265VideoRTPSource.hh | 67 + .../H265VideoStreamDiscreteFramer.hh | 48 + .../liveMedia/H265VideoStreamFramer.hh | 45 + includes/live555/liveMedia/HLSSegmenter.hh | 76 + includes/live555/liveMedia/HMAC_SHA1.hh | 34 + includes/live555/liveMedia/HMAC_hash.hh | 37 + includes/live555/liveMedia/InputFile.hh | 67 + .../live555/liveMedia/JPEG2000VideoRTPSink.hh | 46 + .../liveMedia/JPEG2000VideoRTPSource.hh | 53 + .../live555/liveMedia/JPEGVideoRTPSink.hh | 52 + .../live555/liveMedia/JPEGVideoRTPSource.hh | 59 + includes/live555/liveMedia/JPEGVideoSource.hh | 55 + includes/live555/liveMedia/Locale.hh | 75 + includes/live555/liveMedia/MIKEY.hh | 75 + includes/live555/liveMedia/MP3ADU.hh | 94 + includes/live555/liveMedia/MP3ADURTPSink.hh | 55 + includes/live555/liveMedia/MP3ADURTPSource.hh | 49 + .../live555/liveMedia/MP3ADUTranscoder.hh | 64 + .../live555/liveMedia/MP3ADUinterleaving.hh | 129 + .../MP3AudioFileServerMediaSubsession.hh | 73 + includes/live555/liveMedia/MP3FileSource.hh | 71 + includes/live555/liveMedia/MP3Transcoder.hh | 44 + .../live555/liveMedia/MPEG1or2AudioRTPSink.hh | 48 + .../liveMedia/MPEG1or2AudioRTPSource.hh | 51 + .../liveMedia/MPEG1or2AudioStreamFramer.hh | 70 + includes/live555/liveMedia/MPEG1or2Demux.hh | 158 + .../MPEG1or2DemuxedElementaryStream.hh | 69 + .../MPEG1or2DemuxedServerMediaSubsession.hh | 63 + .../liveMedia/MPEG1or2FileServerDemux.hh | 70 + .../MPEG1or2VideoFileServerMediaSubsession.hh | 59 + .../live555/liveMedia/MPEG1or2VideoRTPSink.hh | 69 + .../liveMedia/MPEG1or2VideoRTPSource.hh | 53 + .../MPEG1or2VideoStreamDiscreteFramer.hh | 76 + .../liveMedia/MPEG1or2VideoStreamFramer.hh | 56 + .../MPEG2IndexFromTransportStream.hh | 95 + ...MPEG2TransportFileServerMediaSubsession.hh | 131 + .../MPEG2TransportStreamAccumulator.hh | 60 + .../liveMedia/MPEG2TransportStreamDemux.hh | 50 + .../liveMedia/MPEG2TransportStreamFramer.hh | 78 + .../MPEG2TransportStreamFromESSource.hh | 66 + .../MPEG2TransportStreamFromPESSource.hh | 62 + .../MPEG2TransportStreamIndexFile.hh | 96 + .../MPEG2TransportStreamMultiplexor.hh | 120 + .../MPEG2TransportStreamTrickModeFilter.hh | 99 + .../MPEG2TransportUDPServerMediaSubsession.hh | 55 + .../live555/liveMedia/MPEG4ESVideoRTPSink.hh | 72 + .../liveMedia/MPEG4ESVideoRTPSource.hh | 51 + .../live555/liveMedia/MPEG4GenericRTPSink.hh | 70 + .../liveMedia/MPEG4GenericRTPSource.hh | 78 + .../liveMedia/MPEG4LATMAudioRTPSink.hh | 69 + .../liveMedia/MPEG4LATMAudioRTPSource.hh | 101 + .../MPEG4VideoFileServerMediaSubsession.hh | 61 + .../MPEG4VideoStreamDiscreteFramer.hh | 73 + .../liveMedia/MPEG4VideoStreamFramer.hh | 75 + .../liveMedia/MPEGVideoStreamFramer.hh | 85 + includes/live555/liveMedia/MatroskaFile.hh | 218 + .../liveMedia/MatroskaFileServerDemux.hh | 88 + includes/live555/liveMedia/Media.hh | 137 + includes/live555/liveMedia/MediaSession.hh | 370 ++ includes/live555/liveMedia/MediaSink.hh | 135 + includes/live555/liveMedia/MediaSource.hh | 59 + .../liveMedia/MediaTranscodingTable.hh | 66 + .../live555/liveMedia/MultiFramedRTPSink.hh | 140 + .../live555/liveMedia/MultiFramedRTPSource.hh | 159 + includes/live555/liveMedia/OggFile.hh | 179 + .../live555/liveMedia/OggFileServerDemux.hh | 85 + includes/live555/liveMedia/OggFileSink.hh | 79 + .../OnDemandServerMediaSubsession.hh | 233 + includes/live555/liveMedia/OutputFile.hh | 31 + .../liveMedia/PassiveServerMediaSubsession.hh | 83 + .../liveMedia/ProxyServerMediaSession.hh | 238 + .../live555/liveMedia/QCELPAudioRTPSource.hh | 39 + .../live555/liveMedia/QuickTimeFileSink.hh | 192 + .../liveMedia/QuickTimeGenericRTPSource.hh | 68 + includes/live555/liveMedia/RTCP.hh | 249 + includes/live555/liveMedia/RTPInterface.hh | 115 + includes/live555/liveMedia/RTPSink.hh | 250 + includes/live555/liveMedia/RTPSource.hh | 272 + includes/live555/liveMedia/RTSPClient.hh | 415 ++ includes/live555/liveMedia/RTSPCommon.hh | 65 + .../live555/liveMedia/RTSPRegisterSender.hh | 138 + includes/live555/liveMedia/RTSPServer.hh | 397 ++ .../liveMedia/RawVideoFrameParameters.hh | 37 + includes/live555/liveMedia/RawVideoRTPSink.hh | 71 + .../live555/liveMedia/RawVideoRTPSource.hh | 60 + includes/live555/liveMedia/SIPClient.hh | 150 + .../liveMedia/SRTPCryptographicContext.hh | 152 + .../live555/liveMedia/ServerMediaSession.hh | 200 + includes/live555/liveMedia/SimpleRTPSink.hh | 76 + includes/live555/liveMedia/SimpleRTPSource.hh | 65 + .../live555/liveMedia/StreamReplicator.hh | 84 + includes/live555/liveMedia/T140TextRTPSink.hh | 103 + includes/live555/liveMedia/TLSState.hh | 100 + includes/live555/liveMedia/TextRTPSink.hh | 41 + .../live555/liveMedia/TheoraVideoRTPSink.hh | 72 + .../live555/liveMedia/TheoraVideoRTPSource.hh | 53 + includes/live555/liveMedia/VP8VideoRTPSink.hh | 50 + .../live555/liveMedia/VP8VideoRTPSource.hh | 50 + includes/live555/liveMedia/VP9VideoRTPSink.hh | 50 + .../live555/liveMedia/VP9VideoRTPSource.hh | 50 + includes/live555/liveMedia/VideoRTPSink.hh | 41 + .../live555/liveMedia/VorbisAudioRTPSink.hh | 85 + .../live555/liveMedia/VorbisAudioRTPSource.hh | 66 + .../WAVAudioFileServerMediaSubsession.hh | 68 + .../live555/liveMedia/WAVAudioFileSource.hh | 86 + includes/live555/liveMedia/export.h | 30 + includes/live555/liveMedia/liveMedia.hh | 137 + .../live555/liveMedia/liveMedia_version.hh | 25 + includes/live555/liveMedia/ourMD5.hh | 38 + includes/live555/liveMedia/uLawAudioFilter.hh | 208 + includes/myws.hpp | 7 + includes/nlohmann/adl_serializer.hpp | 55 + .../nlohmann/byte_container_with_subtype.hpp | 103 + includes/nlohmann/detail/abi_macros.hpp | 100 + .../nlohmann/detail/conversions/from_json.hpp | 497 ++ .../nlohmann/detail/conversions/to_chars.hpp | 1118 ++++ .../nlohmann/detail/conversions/to_json.hpp | 446 ++ includes/nlohmann/detail/exceptions.hpp | 257 + includes/nlohmann/detail/hash.hpp | 129 + .../nlohmann/detail/input/binary_reader.hpp | 3009 ++++++++++ .../nlohmann/detail/input/input_adapters.hpp | 492 ++ includes/nlohmann/detail/input/json_sax.hpp | 727 +++ includes/nlohmann/detail/input/lexer.hpp | 1633 +++++ includes/nlohmann/detail/input/parser.hpp | 519 ++ includes/nlohmann/detail/input/position_t.hpp | 37 + .../detail/iterators/internal_iterator.hpp | 35 + .../nlohmann/detail/iterators/iter_impl.hpp | 751 +++ .../detail/iterators/iteration_proxy.hpp | 242 + .../detail/iterators/iterator_traits.hpp | 61 + .../iterators/json_reverse_iterator.hpp | 130 + .../detail/iterators/primitive_iterator.hpp | 132 + .../detail/json_custom_base_class.hpp | 39 + includes/nlohmann/detail/json_pointer.hpp | 988 ++++ includes/nlohmann/detail/json_ref.hpp | 78 + includes/nlohmann/detail/macro_scope.hpp | 482 ++ includes/nlohmann/detail/macro_unscope.hpp | 45 + .../nlohmann/detail/meta/call_std/begin.hpp | 17 + .../nlohmann/detail/meta/call_std/end.hpp | 17 + includes/nlohmann/detail/meta/cpp_future.hpp | 171 + includes/nlohmann/detail/meta/detected.hpp | 70 + .../nlohmann/detail/meta/identity_tag.hpp | 21 + includes/nlohmann/detail/meta/is_sax.hpp | 159 + includes/nlohmann/detail/meta/std_fs.hpp | 29 + includes/nlohmann/detail/meta/type_traits.hpp | 795 +++ includes/nlohmann/detail/meta/void_t.hpp | 24 + .../nlohmann/detail/output/binary_writer.hpp | 1838 ++++++ .../detail/output/output_adapters.hpp | 147 + .../nlohmann/detail/output/serializer.hpp | 988 ++++ includes/nlohmann/detail/string_concat.hpp | 146 + includes/nlohmann/detail/string_escape.hpp | 72 + includes/nlohmann/detail/value_t.hpp | 118 + includes/nlohmann/json.hpp | 5258 +++++++++++++++++ includes/nlohmann/json_fwd.hpp | 75 + includes/nlohmann/ordered_map.hpp | 359 ++ .../nlohmann/thirdparty/hedley/hedley.hpp | 2045 +++++++ .../thirdparty/hedley/hedley_undef.hpp | 158 + includes/parse_cl.h | 69 + includes/rtcp/rtc/av1rtppacketizer.hpp | 56 + includes/rtcp/rtc/candidate.hpp | 77 + includes/rtcp/rtc/channel.hpp | 61 + includes/rtcp/rtc/common.hpp | 86 + includes/rtcp/rtc/configuration.hpp | 122 + includes/rtcp/rtc/datachannel.hpp | 80 + includes/rtcp/rtc/description.hpp | 324 + includes/rtcp/rtc/frameinfo.hpp | 23 + includes/rtcp/rtc/global.hpp | 59 + includes/rtcp/rtc/h264rtpdepacketizer.hpp | 43 + includes/rtcp/rtc/h264rtppacketizer.hpp | 58 + includes/rtcp/rtc/h265nalunit.hpp | 186 + includes/rtcp/rtc/h265rtppacketizer.hpp | 56 + includes/rtcp/rtc/mediahandler.hpp | 58 + includes/rtcp/rtc/message.hpp | 84 + includes/rtcp/rtc/nalunit.hpp | 227 + includes/rtcp/rtc/peerconnection.hpp | 130 + includes/rtcp/rtc/plihandler.hpp | 36 + includes/rtcp/rtc/reliability.hpp | 43 + includes/rtcp/rtc/rtc.h | 520 ++ includes/rtcp/rtc/rtc.hpp | 43 + includes/rtcp/rtc/rtcpnackresponder.hpp | 76 + includes/rtcp/rtc/rtcpreceivingsession.hpp | 54 + includes/rtcp/rtc/rtcpsrreporter.hpp | 46 + includes/rtcp/rtc/rtp.hpp | 380 ++ includes/rtcp/rtc/rtpdepacketizer.hpp | 34 + includes/rtcp/rtc/rtppacketizationconfig.hpp | 99 + includes/rtcp/rtc/rtppacketizer.hpp | 88 + includes/rtcp/rtc/track.hpp | 63 + includes/rtcp/rtc/utils.hpp | 159 + includes/rtcp/rtc/version.h | 9 + includes/rtcp/rtc/websocket.hpp | 67 + includes/rtcp/rtc/websocketserver.hpp | 48 + includes/sender.hpp | 7 + libs/BasicUsageEnvironment.lib | Bin 0 -> 361438 bytes libs/EpollTaskScheduler.lib | Bin 0 -> 161724 bytes libs/UsageEnvironment.lib | Bin 0 -> 48016 bytes libs/datachannel-.lib | Bin 0 -> 86515330 bytes libs/datachannel.dll | Bin 0 -> 5859840 bytes libs/datachannel.lib | Bin 0 -> 651074 bytes libs/datachannel.pdb | Bin 0 -> 26030080 bytes libs/groupsock.lib | Bin 0 -> 490470 bytes libs/json.lib | Bin 0 -> 3964352 bytes libs/liveMedia.lib | Bin 0 -> 10476836 bytes libs/ws2_32.dll | Bin 0 -> 426688 bytes rtsp.json | 27 + src/getData.cpp | 650 ++ src/getopt.cpp | 513 ++ src/main.cpp | 15 + src/myws.cpp | 532 ++ src/parse_cl.cpp | 168 + src/sender.cpp | 108 + 288 files changed, 46403 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 auto_cmake.bat create mode 100644 includes/getData.hpp create mode 100644 includes/getopt.h create mode 100644 includes/live555/BasicUsageEnvironment/BasicHashTable.hh create mode 100644 includes/live555/BasicUsageEnvironment/BasicUsageEnvironment.hh create mode 100644 includes/live555/BasicUsageEnvironment/BasicUsageEnvironment0.hh create mode 100644 includes/live555/BasicUsageEnvironment/BasicUsageEnvironment_version.hh create mode 100644 includes/live555/BasicUsageEnvironment/DelayQueue.hh create mode 100644 includes/live555/BasicUsageEnvironment/HandlerSet.hh create mode 100644 includes/live555/EpollTaskScheduler/EpollTaskScheduler.hh create mode 100644 includes/live555/UsageEnvironment/Boolean.hh create mode 100644 includes/live555/UsageEnvironment/HashTable.hh create mode 100644 includes/live555/UsageEnvironment/UsageEnvironment.hh create mode 100644 includes/live555/UsageEnvironment/UsageEnvironment_version.hh create mode 100644 includes/live555/UsageEnvironment/strDup.hh create mode 100644 includes/live555/groupsock/GroupEId.hh create mode 100644 includes/live555/groupsock/Groupsock.hh create mode 100644 includes/live555/groupsock/GroupsockHelper.hh create mode 100644 includes/live555/groupsock/IOHandlers.hh create mode 100644 includes/live555/groupsock/NetAddress.hh create mode 100644 includes/live555/groupsock/NetCommon.h create mode 100644 includes/live555/groupsock/NetInterface.hh create mode 100644 includes/live555/groupsock/TunnelEncaps.hh create mode 100644 includes/live555/groupsock/groupsock_version.hh create mode 100644 includes/live555/liveMedia/AC3AudioFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/AC3AudioRTPSink.hh create mode 100644 includes/live555/liveMedia/AC3AudioRTPSource.hh create mode 100644 includes/live555/liveMedia/AC3AudioStreamFramer.hh create mode 100644 includes/live555/liveMedia/ADTSAudioFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/ADTSAudioFileSource.hh create mode 100644 includes/live555/liveMedia/ADTSAudioStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/AMRAudioFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/AMRAudioFileSink.hh create mode 100644 includes/live555/liveMedia/AMRAudioFileSource.hh create mode 100644 includes/live555/liveMedia/AMRAudioRTPSink.hh create mode 100644 includes/live555/liveMedia/AMRAudioRTPSource.hh create mode 100644 includes/live555/liveMedia/AMRAudioSource.hh create mode 100644 includes/live555/liveMedia/AVIFileSink.hh create mode 100644 includes/live555/liveMedia/AudioInputDevice.hh create mode 100644 includes/live555/liveMedia/AudioRTPSink.hh create mode 100644 includes/live555/liveMedia/Base64.hh create mode 100644 includes/live555/liveMedia/BasicUDPSink.hh create mode 100644 includes/live555/liveMedia/BasicUDPSource.hh create mode 100644 includes/live555/liveMedia/BitVector.hh create mode 100644 includes/live555/liveMedia/ByteStreamFileSource.hh create mode 100644 includes/live555/liveMedia/ByteStreamMemoryBufferSource.hh create mode 100644 includes/live555/liveMedia/ByteStreamMultiFileSource.hh create mode 100644 includes/live555/liveMedia/DVVideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/DVVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/DVVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/DVVideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/DeviceSource.hh create mode 100644 includes/live555/liveMedia/DigestAuthentication.hh create mode 100644 includes/live555/liveMedia/FileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/FileSink.hh create mode 100644 includes/live555/liveMedia/FramedFileSource.hh create mode 100644 includes/live555/liveMedia/FramedFilter.hh create mode 100644 includes/live555/liveMedia/FramedSource.hh create mode 100644 includes/live555/liveMedia/GSMAudioRTPSink.hh create mode 100644 includes/live555/liveMedia/GenericMediaServer.hh create mode 100644 includes/live555/liveMedia/H261VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/H263plusVideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/H263plusVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/H263plusVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/H263plusVideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/H264VideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/H264VideoFileSink.hh create mode 100644 includes/live555/liveMedia/H264VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/H264VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/H264VideoStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/H264VideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/H264or5VideoFileSink.hh create mode 100644 includes/live555/liveMedia/H264or5VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/H264or5VideoStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/H264or5VideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/H265VideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/H265VideoFileSink.hh create mode 100644 includes/live555/liveMedia/H265VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/H265VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/H265VideoStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/H265VideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/HLSSegmenter.hh create mode 100644 includes/live555/liveMedia/HMAC_SHA1.hh create mode 100644 includes/live555/liveMedia/HMAC_hash.hh create mode 100644 includes/live555/liveMedia/InputFile.hh create mode 100644 includes/live555/liveMedia/JPEG2000VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/JPEG2000VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/JPEGVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/JPEGVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/JPEGVideoSource.hh create mode 100644 includes/live555/liveMedia/Locale.hh create mode 100644 includes/live555/liveMedia/MIKEY.hh create mode 100644 includes/live555/liveMedia/MP3ADU.hh create mode 100644 includes/live555/liveMedia/MP3ADURTPSink.hh create mode 100644 includes/live555/liveMedia/MP3ADURTPSource.hh create mode 100644 includes/live555/liveMedia/MP3ADUTranscoder.hh create mode 100644 includes/live555/liveMedia/MP3ADUinterleaving.hh create mode 100644 includes/live555/liveMedia/MP3AudioFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MP3FileSource.hh create mode 100644 includes/live555/liveMedia/MP3Transcoder.hh create mode 100644 includes/live555/liveMedia/MPEG1or2AudioRTPSink.hh create mode 100644 includes/live555/liveMedia/MPEG1or2AudioRTPSource.hh create mode 100644 includes/live555/liveMedia/MPEG1or2AudioStreamFramer.hh create mode 100644 includes/live555/liveMedia/MPEG1or2Demux.hh create mode 100644 includes/live555/liveMedia/MPEG1or2DemuxedElementaryStream.hh create mode 100644 includes/live555/liveMedia/MPEG1or2DemuxedServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MPEG1or2FileServerDemux.hh create mode 100644 includes/live555/liveMedia/MPEG1or2VideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MPEG1or2VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/MPEG1or2VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/MPEG1or2VideoStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/MPEG1or2VideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/MPEG2IndexFromTransportStream.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamAccumulator.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamDemux.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamFramer.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamFromESSource.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamFromPESSource.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamIndexFile.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamMultiplexor.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportStreamTrickModeFilter.hh create mode 100644 includes/live555/liveMedia/MPEG2TransportUDPServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MPEG4ESVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/MPEG4ESVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/MPEG4GenericRTPSink.hh create mode 100644 includes/live555/liveMedia/MPEG4GenericRTPSource.hh create mode 100644 includes/live555/liveMedia/MPEG4LATMAudioRTPSink.hh create mode 100644 includes/live555/liveMedia/MPEG4LATMAudioRTPSource.hh create mode 100644 includes/live555/liveMedia/MPEG4VideoFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/MPEG4VideoStreamDiscreteFramer.hh create mode 100644 includes/live555/liveMedia/MPEG4VideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/MPEGVideoStreamFramer.hh create mode 100644 includes/live555/liveMedia/MatroskaFile.hh create mode 100644 includes/live555/liveMedia/MatroskaFileServerDemux.hh create mode 100644 includes/live555/liveMedia/Media.hh create mode 100644 includes/live555/liveMedia/MediaSession.hh create mode 100644 includes/live555/liveMedia/MediaSink.hh create mode 100644 includes/live555/liveMedia/MediaSource.hh create mode 100644 includes/live555/liveMedia/MediaTranscodingTable.hh create mode 100644 includes/live555/liveMedia/MultiFramedRTPSink.hh create mode 100644 includes/live555/liveMedia/MultiFramedRTPSource.hh create mode 100644 includes/live555/liveMedia/OggFile.hh create mode 100644 includes/live555/liveMedia/OggFileServerDemux.hh create mode 100644 includes/live555/liveMedia/OggFileSink.hh create mode 100644 includes/live555/liveMedia/OnDemandServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/OutputFile.hh create mode 100644 includes/live555/liveMedia/PassiveServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/ProxyServerMediaSession.hh create mode 100644 includes/live555/liveMedia/QCELPAudioRTPSource.hh create mode 100644 includes/live555/liveMedia/QuickTimeFileSink.hh create mode 100644 includes/live555/liveMedia/QuickTimeGenericRTPSource.hh create mode 100644 includes/live555/liveMedia/RTCP.hh create mode 100644 includes/live555/liveMedia/RTPInterface.hh create mode 100644 includes/live555/liveMedia/RTPSink.hh create mode 100644 includes/live555/liveMedia/RTPSource.hh create mode 100644 includes/live555/liveMedia/RTSPClient.hh create mode 100644 includes/live555/liveMedia/RTSPCommon.hh create mode 100644 includes/live555/liveMedia/RTSPRegisterSender.hh create mode 100644 includes/live555/liveMedia/RTSPServer.hh create mode 100644 includes/live555/liveMedia/RawVideoFrameParameters.hh create mode 100644 includes/live555/liveMedia/RawVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/RawVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/SIPClient.hh create mode 100644 includes/live555/liveMedia/SRTPCryptographicContext.hh create mode 100644 includes/live555/liveMedia/ServerMediaSession.hh create mode 100644 includes/live555/liveMedia/SimpleRTPSink.hh create mode 100644 includes/live555/liveMedia/SimpleRTPSource.hh create mode 100644 includes/live555/liveMedia/StreamReplicator.hh create mode 100644 includes/live555/liveMedia/T140TextRTPSink.hh create mode 100644 includes/live555/liveMedia/TLSState.hh create mode 100644 includes/live555/liveMedia/TextRTPSink.hh create mode 100644 includes/live555/liveMedia/TheoraVideoRTPSink.hh create mode 100644 includes/live555/liveMedia/TheoraVideoRTPSource.hh create mode 100644 includes/live555/liveMedia/VP8VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/VP8VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/VP9VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/VP9VideoRTPSource.hh create mode 100644 includes/live555/liveMedia/VideoRTPSink.hh create mode 100644 includes/live555/liveMedia/VorbisAudioRTPSink.hh create mode 100644 includes/live555/liveMedia/VorbisAudioRTPSource.hh create mode 100644 includes/live555/liveMedia/WAVAudioFileServerMediaSubsession.hh create mode 100644 includes/live555/liveMedia/WAVAudioFileSource.hh create mode 100644 includes/live555/liveMedia/export.h create mode 100644 includes/live555/liveMedia/liveMedia.hh create mode 100644 includes/live555/liveMedia/liveMedia_version.hh create mode 100644 includes/live555/liveMedia/ourMD5.hh create mode 100644 includes/live555/liveMedia/uLawAudioFilter.hh create mode 100644 includes/myws.hpp create mode 100644 includes/nlohmann/adl_serializer.hpp create mode 100644 includes/nlohmann/byte_container_with_subtype.hpp create mode 100644 includes/nlohmann/detail/abi_macros.hpp create mode 100644 includes/nlohmann/detail/conversions/from_json.hpp create mode 100644 includes/nlohmann/detail/conversions/to_chars.hpp create mode 100644 includes/nlohmann/detail/conversions/to_json.hpp create mode 100644 includes/nlohmann/detail/exceptions.hpp create mode 100644 includes/nlohmann/detail/hash.hpp create mode 100644 includes/nlohmann/detail/input/binary_reader.hpp create mode 100644 includes/nlohmann/detail/input/input_adapters.hpp create mode 100644 includes/nlohmann/detail/input/json_sax.hpp create mode 100644 includes/nlohmann/detail/input/lexer.hpp create mode 100644 includes/nlohmann/detail/input/parser.hpp create mode 100644 includes/nlohmann/detail/input/position_t.hpp create mode 100644 includes/nlohmann/detail/iterators/internal_iterator.hpp create mode 100644 includes/nlohmann/detail/iterators/iter_impl.hpp create mode 100644 includes/nlohmann/detail/iterators/iteration_proxy.hpp create mode 100644 includes/nlohmann/detail/iterators/iterator_traits.hpp create mode 100644 includes/nlohmann/detail/iterators/json_reverse_iterator.hpp create mode 100644 includes/nlohmann/detail/iterators/primitive_iterator.hpp create mode 100644 includes/nlohmann/detail/json_custom_base_class.hpp create mode 100644 includes/nlohmann/detail/json_pointer.hpp create mode 100644 includes/nlohmann/detail/json_ref.hpp create mode 100644 includes/nlohmann/detail/macro_scope.hpp create mode 100644 includes/nlohmann/detail/macro_unscope.hpp create mode 100644 includes/nlohmann/detail/meta/call_std/begin.hpp create mode 100644 includes/nlohmann/detail/meta/call_std/end.hpp create mode 100644 includes/nlohmann/detail/meta/cpp_future.hpp create mode 100644 includes/nlohmann/detail/meta/detected.hpp create mode 100644 includes/nlohmann/detail/meta/identity_tag.hpp create mode 100644 includes/nlohmann/detail/meta/is_sax.hpp create mode 100644 includes/nlohmann/detail/meta/std_fs.hpp create mode 100644 includes/nlohmann/detail/meta/type_traits.hpp create mode 100644 includes/nlohmann/detail/meta/void_t.hpp create mode 100644 includes/nlohmann/detail/output/binary_writer.hpp create mode 100644 includes/nlohmann/detail/output/output_adapters.hpp create mode 100644 includes/nlohmann/detail/output/serializer.hpp create mode 100644 includes/nlohmann/detail/string_concat.hpp create mode 100644 includes/nlohmann/detail/string_escape.hpp create mode 100644 includes/nlohmann/detail/value_t.hpp create mode 100644 includes/nlohmann/json.hpp create mode 100644 includes/nlohmann/json_fwd.hpp create mode 100644 includes/nlohmann/ordered_map.hpp create mode 100644 includes/nlohmann/thirdparty/hedley/hedley.hpp create mode 100644 includes/nlohmann/thirdparty/hedley/hedley_undef.hpp create mode 100644 includes/parse_cl.h create mode 100644 includes/rtcp/rtc/av1rtppacketizer.hpp create mode 100644 includes/rtcp/rtc/candidate.hpp create mode 100644 includes/rtcp/rtc/channel.hpp create mode 100644 includes/rtcp/rtc/common.hpp create mode 100644 includes/rtcp/rtc/configuration.hpp create mode 100644 includes/rtcp/rtc/datachannel.hpp create mode 100644 includes/rtcp/rtc/description.hpp create mode 100644 includes/rtcp/rtc/frameinfo.hpp create mode 100644 includes/rtcp/rtc/global.hpp create mode 100644 includes/rtcp/rtc/h264rtpdepacketizer.hpp create mode 100644 includes/rtcp/rtc/h264rtppacketizer.hpp create mode 100644 includes/rtcp/rtc/h265nalunit.hpp create mode 100644 includes/rtcp/rtc/h265rtppacketizer.hpp create mode 100644 includes/rtcp/rtc/mediahandler.hpp create mode 100644 includes/rtcp/rtc/message.hpp create mode 100644 includes/rtcp/rtc/nalunit.hpp create mode 100644 includes/rtcp/rtc/peerconnection.hpp create mode 100644 includes/rtcp/rtc/plihandler.hpp create mode 100644 includes/rtcp/rtc/reliability.hpp create mode 100644 includes/rtcp/rtc/rtc.h create mode 100644 includes/rtcp/rtc/rtc.hpp create mode 100644 includes/rtcp/rtc/rtcpnackresponder.hpp create mode 100644 includes/rtcp/rtc/rtcpreceivingsession.hpp create mode 100644 includes/rtcp/rtc/rtcpsrreporter.hpp create mode 100644 includes/rtcp/rtc/rtp.hpp create mode 100644 includes/rtcp/rtc/rtpdepacketizer.hpp create mode 100644 includes/rtcp/rtc/rtppacketizationconfig.hpp create mode 100644 includes/rtcp/rtc/rtppacketizer.hpp create mode 100644 includes/rtcp/rtc/track.hpp create mode 100644 includes/rtcp/rtc/utils.hpp create mode 100644 includes/rtcp/rtc/version.h create mode 100644 includes/rtcp/rtc/websocket.hpp create mode 100644 includes/rtcp/rtc/websocketserver.hpp create mode 100644 includes/sender.hpp create mode 100644 libs/BasicUsageEnvironment.lib create mode 100644 libs/EpollTaskScheduler.lib create mode 100644 libs/UsageEnvironment.lib create mode 100644 libs/datachannel-.lib create mode 100644 libs/datachannel.dll create mode 100644 libs/datachannel.lib create mode 100644 libs/datachannel.pdb create mode 100644 libs/groupsock.lib create mode 100644 libs/json.lib create mode 100644 libs/liveMedia.lib create mode 100644 libs/ws2_32.dll create mode 100644 rtsp.json create mode 100644 src/getData.cpp create mode 100644 src/getopt.cpp create mode 100644 src/main.cpp create mode 100644 src/myws.cpp create mode 100644 src/parse_cl.cpp create mode 100644 src/sender.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0439fc1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.7) + +set(PROJECT_NAME project) +project(${PROJECT_NAME}) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +add_definitions(-DLIVEMEDIA_API=) +add_definitions(-DNO_OPENSSL=1) +# target_compile_definitions(${PROJECT_NAME} INTERFACE LIVEMEDIA_API=) + + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/live555/groupsock) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/live555/UsageEnvironment) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/live555/BasicUsageEnvironment) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/live555/liveMedia) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/live555/EpollTaskScheduler) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/rtcp) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/rtcp/rtc) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/nlohmann) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/nlohmann/detail) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes/nlohmann/thirdparty) + +set(LIBS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs) + +# static +# for live555 +link_directories(${LIBS_PATH}) +link_libraries(UsageEnvironment) +link_libraries(BasicUsageEnvironment) +link_libraries(groupsock) +link_libraries(liveMedia) +link_libraries(EpollTaskScheduler) +# sender of RTCP +link_libraries(datachannel) +link_libraries(json) + +aux_source_directory(./src DIR_SRCS) +add_executable(${PROJECT_NAME} ${DIR_SRCS}) + +# shared +# for sender +find_package(Threads REQUIRED) +target_link_libraries(${PROJECT_NAME} Threads::Threads) +# target_link_libraries(${PROJECT_NAME} datachannel) +target_link_libraries(${PROJECT_NAME} ws2_32) + + +file(COPY ${CMAKE_SOURCE_DIR}/libs/datachannel.dll DESTINATION ${CMAKE_BINARY_DIR}) +file(COPY ${CMAKE_SOURCE_DIR}/rtsp.json DESTINATION ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/auto_cmake.bat b/auto_cmake.bat new file mode 100644 index 0000000..e44b672 --- /dev/null +++ b/auto_cmake.bat @@ -0,0 +1,6 @@ +for /F %%i in ('cd') do ( set dir=%%i) + +rmdir /s /q build +mkdir build +cmake -B build -G "NMake Makefiles" && cd ./build && nmake +cd %dir% \ No newline at end of file diff --git a/includes/getData.hpp b/includes/getData.hpp new file mode 100644 index 0000000..d47c796 --- /dev/null +++ b/includes/getData.hpp @@ -0,0 +1,16 @@ + +#ifndef _GET_RTCP +#define _GET_RTCP +#include "BasicUsageEnvironment.hh" +#include "liveMedia.hh" + +typedef void(callback)(u_int8_t* data, unsigned len, const char* name); + +extern int getData(int argc, char **argv); +extern void openURL(UsageEnvironment &env, + char const *progName, + u_int32_t ssrc, + char const *rtspURL, + callback* cb); + +#endif diff --git a/includes/getopt.h b/includes/getopt.h new file mode 100644 index 0000000..b42babd --- /dev/null +++ b/includes/getopt.h @@ -0,0 +1,115 @@ +/* Getopt for Microsoft C +This code is a modification of the Free Software Foundation, Inc. +Getopt library for parsing command line argument the purpose was +to provide a Microsoft Visual C friendly derivative. This code +provides functionality for both Unicode and Multibyte builds. + +Date: 02/03/2011 - Ludvik Jerabek - Initial Release +Version: 1.0 +Comment: Supports getopt, getopt_long, and getopt_long_only +and POSIXLY_CORRECT environment flag +License: LGPL + +Revisions: + +02/03/2011 - Ludvik Jerabek - Initial Release +02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 +07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs +08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception +08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB +02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file +08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi +10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features +06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable +24/10/2020 - Paul-Louis Ageneau - Removed Unicode version + +**DISCLAIMER** +THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT +APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY +USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST +PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON +YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE +EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ +#ifndef __GETOPT_H_ + #define __GETOPT_H_ + + #ifdef _GETOPT_API + #undef _GETOPT_API + #endif + + #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) + #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" + #elif defined(STATIC_GETOPT) + #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") + #define _GETOPT_API + #elif defined(EXPORTS_GETOPT) + #pragma message("Exporting getopt library") + #define _GETOPT_API __declspec(dllexport) + #else + #pragma message("Importing getopt library") + #define _GETOPT_API __declspec(dllimport) + #endif + + // Change behavior for C\C++ + #ifdef __cplusplus + #define _BEGIN_EXTERN_C extern "C" { + #define _END_EXTERN_C } + #define _GETOPT_THROW throw() + #else + #define _BEGIN_EXTERN_C + #define _END_EXTERN_C + #define _GETOPT_THROW + #endif + + // Standard GNU options + #define null_argument 0 /*Argument Null*/ + #define no_argument 0 /*Argument Switch Only*/ + #define required_argument 1 /*Argument Required*/ + #define optional_argument 2 /*Argument Optional*/ + + // Shorter Options + #define ARG_NULL 0 /*Argument Null*/ + #define ARG_NONE 0 /*Argument Switch Only*/ + #define ARG_REQ 1 /*Argument Required*/ + #define ARG_OPT 2 /*Argument Optional*/ + + #include + +_BEGIN_EXTERN_C + + extern _GETOPT_API int optind; + extern _GETOPT_API int opterr; + extern _GETOPT_API int optopt; + + struct option_a + { + const char* name; + int has_arg; + int *flag; + int val; + }; + extern _GETOPT_API char *optarg_a; + extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; + +_END_EXTERN_C + + #undef _BEGIN_EXTERN_C + #undef _END_EXTERN_C + #undef _GETOPT_THROW + #undef _GETOPT_API + + #define getopt getopt_a + #define getopt_long getopt_long_a + #define getopt_long_only getopt_long_only_a + #define option option_a + #define optarg optarg_a + +#endif // __GETOPT_H_ diff --git a/includes/live555/BasicUsageEnvironment/BasicHashTable.hh b/includes/live555/BasicUsageEnvironment/BasicHashTable.hh new file mode 100644 index 0000000..1c9a923 --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/BasicHashTable.hh @@ -0,0 +1,104 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Basic Hash Table implementation +// C++ header + +#ifndef _BASIC_HASH_TABLE_HH +#define _BASIC_HASH_TABLE_HH + +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif +#ifndef _NET_COMMON_H +#include // to ensure that "uintptr_t" is defined +#endif + +// A simple hash table implementation, inspired by the hash table +// implementation used in Tcl 7.6: + +#define SMALL_HASH_TABLE_SIZE 4 + +class LIVEMEDIA_API BasicHashTable: public HashTable { +private: + class TableEntry; // forward + +public: + BasicHashTable(int keyType); + virtual ~BasicHashTable(); + + // Used to iterate through the members of the table: + class Iterator; friend class Iterator; // to make Sun's C++ compiler happy + class Iterator: public HashTable::Iterator { + public: + Iterator(BasicHashTable const& table); + + private: // implementation of inherited pure virtual functions + void* next(char const*& key); // returns 0 if none + + private: + BasicHashTable const& fTable; + unsigned fNextIndex; // index of next bucket to be enumerated after this + TableEntry* fNextEntry; // next entry in the current bucket + }; + +private: // implementation of inherited pure virtual functions + virtual void* Add(char const* key, void* value); + // Returns the old value if different, otherwise 0 + virtual Boolean Remove(char const* key); + virtual void* Lookup(char const* key) const; + // Returns 0 if not found + virtual unsigned numEntries() const; + +private: + class TableEntry { + public: + TableEntry* fNext; + char const* key; + void* value; + }; + + TableEntry* lookupKey(char const* key, unsigned& index) const; + // returns entry matching "key", or NULL if none + Boolean keyMatches(char const* key1, char const* key2) const; + // used to implement "lookupKey()" + + TableEntry* insertNewEntry(unsigned index, char const* key); + // creates a new entry, and inserts it in the table + void assignKey(TableEntry* entry, char const* key); + // used to implement "insertNewEntry()" + + void deleteEntry(unsigned index, TableEntry* entry); + void deleteKey(TableEntry* entry); + // used to implement "deleteEntry()" + + void rebuild(); // rebuilds the table as its size increases + + unsigned hashIndexFromKey(char const* key) const; + // used to implement many of the routines above + + unsigned randomIndex(uintptr_t i) const { + return (unsigned)(((i*1103515245) >> fDownShift) & fMask); + } + +private: + TableEntry** fBuckets; // pointer to bucket array + TableEntry* fStaticBuckets[SMALL_HASH_TABLE_SIZE];// used for small tables + unsigned fNumBuckets, fNumEntries, fRebuildSize, fDownShift, fMask; + int fKeyType; +}; + +#endif diff --git a/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment.hh b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment.hh new file mode 100644 index 0000000..875af9a --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment.hh @@ -0,0 +1,86 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Basic Usage Environment: for a simple, non-scripted, console application +// C++ header + +#ifndef _BASIC_USAGE_ENVIRONMENT_HH +#define _BASIC_USAGE_ENVIRONMENT_HH + +#ifndef _BASIC_USAGE_ENVIRONMENT0_HH +#include "BasicUsageEnvironment0.hh" +#endif + +class LIVEMEDIA_API BasicUsageEnvironment: public BasicUsageEnvironment0 { +public: + static BasicUsageEnvironment* createNew(TaskScheduler& taskScheduler); + + // redefined virtual functions: + virtual int getErrno() const; + + virtual UsageEnvironment& operator<<(char const* str); + virtual UsageEnvironment& operator<<(int i); + virtual UsageEnvironment& operator<<(unsigned u); + virtual UsageEnvironment& operator<<(double d); + virtual UsageEnvironment& operator<<(void* p); + +protected: + BasicUsageEnvironment(TaskScheduler& taskScheduler); + // called only by "createNew()" (or subclass constructors) + virtual ~BasicUsageEnvironment(); +}; + + +class LIVEMEDIA_API BasicTaskScheduler: public BasicTaskScheduler0 { +public: + static BasicTaskScheduler* createNew(unsigned maxSchedulerGranularity = 10000/*microseconds*/); + // "maxSchedulerGranularity" (default value: 10 ms) specifies the maximum time that we wait (in "select()") before + // returning to the event loop to handle non-socket or non-timer-based events, such as 'triggered events'. + // You can change this is you wish (but only if you know what you're doing!), or set it to 0, to specify no such maximum time. + // (You should set it to 0 only if you know that you will not be using 'event triggers'.) + virtual ~BasicTaskScheduler(); + +protected: + BasicTaskScheduler(unsigned maxSchedulerGranularity); + // called only by "createNew()" + + static void schedulerTickTask(void* clientData); + void schedulerTickTask(); + +protected: + // Redefined virtual functions: + virtual void SingleStep(unsigned maxDelayTime); + + virtual void setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData); + virtual void moveSocketHandling(int oldSocketNum, int newSocketNum); + +protected: + unsigned fMaxSchedulerGranularity; + + // To implement background operations: + int fMaxNumSockets; + fd_set fReadSet; + fd_set fWriteSet; + fd_set fExceptionSet; + +private: +#if defined(__WIN32__) || defined(_WIN32) + // Hack to work around a bug in Windows' "select()" implementation: + int fDummySocketNum; +#endif +}; + +#endif diff --git a/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment0.hh b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment0.hh new file mode 100644 index 0000000..08e826f --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment0.hh @@ -0,0 +1,131 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Basic Usage Environment: for a simple, non-scripted, console application +// C++ header + +#ifndef _BASIC_USAGE_ENVIRONMENT0_HH +#define _BASIC_USAGE_ENVIRONMENT0_HH + +#ifndef _BASICUSAGEENVIRONMENT_VERSION_HH +#include "BasicUsageEnvironment_version.hh" +#endif + +#ifndef _USAGE_ENVIRONMENT_HH +#include "UsageEnvironment.hh" +#endif + +#ifndef _DELAY_QUEUE_HH +#include "DelayQueue.hh" +#endif + +#ifndef NO_STD_LIB +#ifndef _LIBCPP_ATOMIC +#include +#endif +#endif + +#define RESULT_MSG_BUFFER_MAX 1000 + +// An abstract base class, useful for subclassing +// (e.g., to redefine the implementation of "operator<<") +class LIVEMEDIA_API BasicUsageEnvironment0: public UsageEnvironment { +public: + // redefined virtual functions: + virtual MsgString getResultMsg() const; + + virtual void setResultMsg(MsgString msg); + virtual void setResultMsg(MsgString msg1, + MsgString msg2); + virtual void setResultMsg(MsgString msg1, + MsgString msg2, + MsgString msg3); + virtual void setResultErrMsg(MsgString msg, int err = 0); + + virtual void appendToResultMsg(MsgString msg); + + virtual void reportBackgroundError(); + +protected: + BasicUsageEnvironment0(TaskScheduler& taskScheduler); + virtual ~BasicUsageEnvironment0(); + +private: + void reset(); + + char fResultMsgBuffer[RESULT_MSG_BUFFER_MAX]; + unsigned fCurBufferSize; + unsigned fBufferMaxSize; +}; + +class HandlerSet; // forward + +// Note: You may redefine MAX_NUM_EVENT_TRIGGERS, +// but it must be <= the number of bits in an "EventTriggerId" +#ifndef MAX_NUM_EVENT_TRIGGERS +#define MAX_NUM_EVENT_TRIGGERS 32 +#endif +#define EVENT_TRIGGER_ID_HIGH_BIT (1 << (MAX_NUM_EVENT_TRIGGERS-1)) + +// An abstract base class, useful for subclassing +// (e.g., to redefine the implementation of socket event handling) +class LIVEMEDIA_API BasicTaskScheduler0: public TaskScheduler { +public: + virtual ~BasicTaskScheduler0(); + + virtual void SingleStep(unsigned maxDelayTime = 0) = 0; + // "maxDelayTime" is in microseconds. It allows a subclass to impose a limit + // on how long "select()" can delay, in case it wants to also do polling. + // 0 (the default value) means: There's no maximum; just look at the delay queue + +public: + // Redefined virtual functions: + virtual TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc, + void* clientData); + virtual void unscheduleDelayedTask(TaskToken& prevTask); + + virtual void doEventLoop(char volatile* watchVariable); + + virtual EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc); + virtual void deleteEventTrigger(EventTriggerId eventTriggerId); + virtual void triggerEvent(EventTriggerId eventTriggerId, void* clientData = NULL); + +protected: + BasicTaskScheduler0(); + +protected: + // To implement delayed operations: + intptr_t fTokenCounter; + DelayQueue fDelayQueue; + + // To implement background reads: + HandlerSet* fHandlers; + int fLastHandledSocketNum; + + // To implement event triggers: +#ifndef NO_STD_LIB + std::atomic_flag fTriggersAwaitingHandling[MAX_NUM_EVENT_TRIGGERS]; +#else + Boolean volatile fTriggersAwaitingHandling[MAX_NUM_EVENT_TRIGGERS]; +#endif + u_int32_t fLastUsedTriggerMask; // implemented as a 32-bit bitmap + TaskFunc* fTriggeredEventHandlers[MAX_NUM_EVENT_TRIGGERS]; + void* fTriggeredEventClientDatas[MAX_NUM_EVENT_TRIGGERS]; + unsigned fLastUsedTriggerNum; // in the range [0,MAX_NUM_EVENT_TRIGGERS) + Boolean fEventTriggersAreBeingUsed; +}; + +#endif diff --git a/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment_version.hh b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment_version.hh new file mode 100644 index 0000000..3cc3230 --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/BasicUsageEnvironment_version.hh @@ -0,0 +1,25 @@ +/********** +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 +**********/ +// Version information for the "BasicUsageEnvironment" library +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. + +#ifndef _BASICUSAGEENVIRONMENT_VERSION_HH +#define _BASICUSAGEENVIRONMENT_VERSION_HH + +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2024.02.15" +#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1707955200 + +#endif diff --git a/includes/live555/BasicUsageEnvironment/DelayQueue.hh b/includes/live555/BasicUsageEnvironment/DelayQueue.hh new file mode 100644 index 0000000..195e7cc --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/DelayQueue.hh @@ -0,0 +1,181 @@ +/********** +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 +**********/ + // Copyright (c) 1996-2024, Live Networks, Inc. All rights reserved +// Delay queue +// C++ header + +#ifndef _DELAY_QUEUE_HH +#define _DELAY_QUEUE_HH + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif + +#ifdef TIME_BASE +typedef TIME_BASE time_base_seconds; +#else +typedef long time_base_seconds; +#endif + +///// A "Timeval" can be either an absolute time, or a time interval ///// + +class LIVEMEDIA_API Timeval { +public: + time_base_seconds seconds() const { + return fTv.tv_sec; + } + time_base_seconds seconds() { + return fTv.tv_sec; + } + time_base_seconds useconds() const { + return fTv.tv_usec; + } + time_base_seconds useconds() { + return fTv.tv_usec; + } + + int operator>=(Timeval const& arg2) const; + int operator<=(Timeval const& arg2) const { + return arg2 >= *this; + } + int operator<(Timeval const& arg2) const { + return !(*this >= arg2); + } + int operator>(Timeval const& arg2) const { + return arg2 < *this; + } + int operator==(Timeval const& arg2) const { + return *this >= arg2 && arg2 >= *this; + } + int operator!=(Timeval const& arg2) const { + return !(*this == arg2); + } + + void operator+=(class DelayInterval const& arg2); + void operator-=(class DelayInterval const& arg2); + // returns ZERO iff arg2 >= arg1 + +protected: + Timeval(time_base_seconds seconds, time_base_seconds useconds) { + fTv.tv_sec = seconds; fTv.tv_usec = useconds; + } + +private: + time_base_seconds& secs() { + return (time_base_seconds&)fTv.tv_sec; + } + time_base_seconds& usecs() { + return (time_base_seconds&)fTv.tv_usec; + } + + struct timeval fTv; +}; + +#ifndef max +inline Timeval max(Timeval const& arg1, Timeval const& arg2) { + return arg1 >= arg2 ? arg1 : arg2; +} +#endif +#ifndef min +inline Timeval min(Timeval const& arg1, Timeval const& arg2) { + return arg1 <= arg2 ? arg1 : arg2; +} +#endif + +class DelayInterval operator-(Timeval const& arg1, Timeval const& arg2); +// returns ZERO iff arg2 >= arg1 + + +///// DelayInterval ///// + +class LIVEMEDIA_API DelayInterval: public Timeval { +public: + DelayInterval(time_base_seconds seconds, time_base_seconds useconds) + : Timeval(seconds, useconds) {} +}; + +DelayInterval operator*(short arg1, DelayInterval const& arg2); + +extern DelayInterval const DELAY_ZERO; +extern DelayInterval const DELAY_SECOND; +extern DelayInterval const DELAY_MINUTE; +extern DelayInterval const DELAY_HOUR; +extern DelayInterval const DELAY_DAY; + +///// _EventTime ///// + +class LIVEMEDIA_API _EventTime: public Timeval { +public: + _EventTime(unsigned secondsSinceEpoch = 0, + unsigned usecondsSinceEpoch = 0) + // We use the Unix standard epoch: January 1, 1970 + : Timeval(secondsSinceEpoch, usecondsSinceEpoch) {} +}; + +_EventTime TimeNow(); + +extern _EventTime const THE_END_OF_TIME; + + +///// DelayQueueEntry ///// + +class LIVEMEDIA_API DelayQueueEntry { +public: + virtual ~DelayQueueEntry(); + + intptr_t token() { + return fToken; + } + +protected: // abstract base class + DelayQueueEntry(DelayInterval delay, intptr_t token); + + virtual void handleTimeout(); + +private: + friend class DelayQueue; + DelayQueueEntry* fNext; + DelayQueueEntry* fPrev; + DelayInterval fDeltaTimeRemaining; + + intptr_t fToken; +}; + +///// DelayQueue ///// + +class LIVEMEDIA_API DelayQueue: public DelayQueueEntry { +public: + DelayQueue(); + virtual ~DelayQueue(); + + void addEntry(DelayQueueEntry* newEntry); // returns a token for the entry + void updateEntry(DelayQueueEntry* entry, DelayInterval newDelay); + void updateEntry(intptr_t tokenToFind, DelayInterval newDelay); + void removeEntry(DelayQueueEntry* entry); // but doesn't delete it + DelayQueueEntry* removeEntry(intptr_t tokenToFind); // but doesn't delete it + + DelayInterval const& timeToNextAlarm(); + void handleAlarm(); + +private: + DelayQueueEntry* head() { return fNext; } + DelayQueueEntry* findEntryByToken(intptr_t token); + void synchronize(); // bring the 'time remaining' fields up-to-date + + _EventTime fLastSyncTime; +}; + +#endif diff --git a/includes/live555/BasicUsageEnvironment/HandlerSet.hh b/includes/live555/BasicUsageEnvironment/HandlerSet.hh new file mode 100644 index 0000000..a07846f --- /dev/null +++ b/includes/live555/BasicUsageEnvironment/HandlerSet.hh @@ -0,0 +1,77 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Basic Usage Environment: for a simple, non-scripted, console application +// C++ header + +#ifndef _HANDLER_SET_HH +#define _HANDLER_SET_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +////////// HandlerSet (etc.) definition ////////// + +class LIVEMEDIA_API HandlerDescriptor { + HandlerDescriptor(HandlerDescriptor* nextHandler); + virtual ~HandlerDescriptor(); + +public: + int socketNum; + int conditionSet; + TaskScheduler::BackgroundHandlerProc* handlerProc; + void* clientData; + +private: + // Descriptors are linked together in a doubly-linked list: + friend class HandlerSet; + friend class HandlerIterator; + HandlerDescriptor* fNextHandler; + HandlerDescriptor* fPrevHandler; +}; + +class LIVEMEDIA_API HandlerSet { +public: + HandlerSet(); + virtual ~HandlerSet(); + + void assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData); + void clearHandler(int socketNum); + void moveHandler(int oldSocketNum, int newSocketNum); + +private: + HandlerDescriptor* lookupHandler(int socketNum); + +private: + friend class HandlerIterator; + HandlerDescriptor fHandlers; +}; + +class LIVEMEDIA_API HandlerIterator { +public: + HandlerIterator(HandlerSet& handlerSet); + virtual ~HandlerIterator(); + + HandlerDescriptor* next(); // returns NULL if none + void reset(); + +private: + HandlerSet& fOurSet; + HandlerDescriptor* fNextPtr; +}; + +#endif diff --git a/includes/live555/EpollTaskScheduler/EpollTaskScheduler.hh b/includes/live555/EpollTaskScheduler/EpollTaskScheduler.hh new file mode 100644 index 0000000..2025057 --- /dev/null +++ b/includes/live555/EpollTaskScheduler/EpollTaskScheduler.hh @@ -0,0 +1,56 @@ +/********** +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 2.1 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 +**********/ +// Copyright (c) 1996-2016 Live Networks, Inc. All rights reserved. +// Basic Usage Environment: for a simple, non-scripted, console application +// C++ header + +#ifndef _EPOLL_TASK_SCHEDULER_HH +#define _EPOLL_TASK_SCHEDULER_HH + +#include "BasicUsageEnvironment.hh" +#include "HandlerSet.hh" + +class EpollTaskScheduler : public BasicTaskScheduler0 { +public: + static EpollTaskScheduler* createNew(unsigned maxSchedulerGranularity = 10000 /*microseconds*/); + virtual ~EpollTaskScheduler(); + +private: + EpollTaskScheduler(unsigned maxSchedulerGranularity); + + static void schedulerTickTask(void* clientData); + void schedulerTickTask(); + + const HandlerDescriptor* lookupHandlerDescriptor(int socketNum) const; + +private: + virtual void SingleStep(unsigned maxDelayTime); + + virtual void setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData); + virtual void moveSocketHandling(int oldSocketNum, int newSocketNum); + +private: + unsigned fMaxSchedulerGranularity; + +private: +#if defined(__WIN32__) || defined(_WIN32) + void* fEpollHandle; +#else + int fEpollHandle; +#endif +}; + +#endif diff --git a/includes/live555/UsageEnvironment/Boolean.hh b/includes/live555/UsageEnvironment/Boolean.hh new file mode 100644 index 0000000..3d8401e --- /dev/null +++ b/includes/live555/UsageEnvironment/Boolean.hh @@ -0,0 +1,37 @@ +/********** +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 +**********/ +#ifndef _BOOLEAN_HH +#define _BOOLEAN_HH + +#if defined(__BORLANDC__) || (!defined(USE_LIVE555_BOOLEAN) && defined(_MSC_VER) && _MSC_VER >= 1400) +// Use the "bool" type defined by the Borland compiler, and MSVC++ 8.0, Visual Studio 2005 and higher +typedef bool Boolean; +#define False false +#define True true +#else +typedef unsigned char Boolean; +#ifndef __MSHTML_LIBRARY_DEFINED__ +#ifndef False +const Boolean False = 0; +#endif +#ifndef True +const Boolean True = 1; +#endif + +#endif +#endif + +#endif diff --git a/includes/live555/UsageEnvironment/HashTable.hh b/includes/live555/UsageEnvironment/HashTable.hh new file mode 100644 index 0000000..a934af4 --- /dev/null +++ b/includes/live555/UsageEnvironment/HashTable.hh @@ -0,0 +1,76 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Generic Hash Table +// C++ header + +#ifndef _HASH_TABLE_HH +#define _HASH_TABLE_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +class LIVEMEDIA_API HashTable { +public: + virtual ~HashTable(); + + // The following must be implemented by a particular + // implementation (subclass): + static HashTable* create(int keyType); + + virtual void* Add(char const* key, void* value) = 0; + // Returns the old value if different, otherwise 0 + virtual Boolean Remove(char const* key) = 0; + virtual void* Lookup(char const* key) const = 0; + // Returns 0 if not found + virtual unsigned numEntries() const = 0; + Boolean IsEmpty() const { return numEntries() == 0; } + + // Used to iterate through the members of the table: + class Iterator { + public: + // The following must be implemented by a particular + // implementation (subclass): + static Iterator* create(HashTable const& hashTable); + + virtual ~Iterator(); + + virtual void* next(char const*& key) = 0; // returns 0 if none + + protected: + Iterator(); // abstract base class + }; + + // A shortcut that can be used to successively remove each of + // the entries in the table (e.g., so that their values can be + // deleted, if they happen to be pointers to allocated memory). + void* RemoveNext(); + + // Returns the first entry in the table. + // (This is useful for deleting each entry in the table, if the entry's destructor also removes itself from the table.) + void* getFirst(); + +protected: + HashTable(); // abstract base class +}; + +// Warning: The following are deliberately the same as in +// Tcl's hash table implementation +int const STRING_HASH_KEYS = 0; +int const ONE_WORD_HASH_KEYS = 1; + +#endif diff --git a/includes/live555/UsageEnvironment/UsageEnvironment.hh b/includes/live555/UsageEnvironment/UsageEnvironment.hh new file mode 100644 index 0000000..d8c5625 --- /dev/null +++ b/includes/live555/UsageEnvironment/UsageEnvironment.hh @@ -0,0 +1,176 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Usage Environment +// C++ header + +#ifndef _USAGE_ENVIRONMENT_HH +#define _USAGE_ENVIRONMENT_HH + +#ifndef _USAGEENVIRONMENT_VERSION_HH +#include "UsageEnvironment_version.hh" +#endif + +#ifndef _NETCOMMON_H +#include "NetCommon.h" +#endif + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +#ifndef _STRDUP_HH +// "strDup()" is used often, so include this here, so everyone gets it: +#include "strDup.hh" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef __BORLANDC__ +#define _setmode setmode +#define _O_BINARY O_BINARY +#endif + +class TaskScheduler; // forward + +// An abstract base class, subclassed for each use of the library + +class LIVEMEDIA_API UsageEnvironment { +public: + Boolean reclaim(); + // returns True iff we were actually able to delete our object + + // task scheduler: + TaskScheduler& taskScheduler() const {return fScheduler;} + + // result message handling: + typedef char const* MsgString; + virtual MsgString getResultMsg() const = 0; + + virtual void setResultMsg(MsgString msg) = 0; + virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0; + virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0; + virtual void setResultErrMsg(MsgString msg, int err = 0) = 0; + // like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.) + + virtual void appendToResultMsg(MsgString msg) = 0; + + virtual void reportBackgroundError() = 0; + // used to report a (previously set) error message within + // a background event + + virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library. + + // 'errno' + virtual int getErrno() const = 0; + + // 'console' output: + virtual UsageEnvironment& operator<<(char const* str) = 0; + virtual UsageEnvironment& operator<<(int i) = 0; + virtual UsageEnvironment& operator<<(unsigned u) = 0; + virtual UsageEnvironment& operator<<(double d) = 0; + virtual UsageEnvironment& operator<<(void* p) = 0; + + // a pointer to additional, optional, client-specific state + void* liveMediaPriv; + void* groupsockPriv; + +protected: + UsageEnvironment(TaskScheduler& scheduler); // abstract base class + virtual ~UsageEnvironment(); // we are deleted only by reclaim() + +private: + TaskScheduler& fScheduler; +}; + + +typedef void TaskFunc(void* clientData); +typedef void* TaskToken; +typedef u_int32_t EventTriggerId; + +class LIVEMEDIA_API TaskScheduler { +public: + virtual ~TaskScheduler(); + + virtual TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc, + void* clientData) = 0; + // Schedules a task to occur (after a delay) when we next + // reach a scheduling point. + // (Does not delay if "microseconds" <= 0) + // Returns a token that can be used in a subsequent call to + // unscheduleDelayedTask() or rescheduleDelayedTask() + // (but only if the task has not yet occurred). + + virtual void unscheduleDelayedTask(TaskToken& prevTask) = 0; + // (Has no effect if "prevTask" == NULL) + // Sets "prevTask" to NULL afterwards. + // Note: This MUST NOT be called if the scheduled task has already occurred. + + virtual void rescheduleDelayedTask(TaskToken& task, + int64_t microseconds, TaskFunc* proc, + void* clientData); + // Combines "unscheduleDelayedTask()" with "scheduleDelayedTask()" + // (setting "task" to the new task token). + // Note: This MUST NOT be called if the scheduled task has already occurred. + + // For handling socket operations in the background (from the event loop): + typedef void BackgroundHandlerProc(void* clientData, int mask); + // Possible bits to set in "mask". (These are deliberately defined + // the same as those in Tcl, to make a Tcl-based subclass easy.) + #define SOCKET_READABLE (1<<1) + #define SOCKET_WRITABLE (1<<2) + #define SOCKET_EXCEPTION (1<<3) + virtual void setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData) = 0; + void disableBackgroundHandling(int socketNum) { setBackgroundHandling(socketNum, 0, NULL, NULL); } + virtual void moveSocketHandling(int oldSocketNum, int newSocketNum) = 0; + // Changes any socket handling for "oldSocketNum" so that occurs with "newSocketNum" instead. + + virtual void doEventLoop(char volatile* watchVariable = NULL) = 0; + // Causes further execution to take place within the event loop. + // Delayed tasks, background I/O handling, and other events are handled, sequentially (as a single thread of control). + // (If "watchVariable" is not NULL, then we return from this routine when *watchVariable != 0) + + virtual EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc) = 0; + // Creates a 'trigger' for an event, which - if it occurs - will be handled (from the event loop) using "eventHandlerProc". + // (Returns 0 iff no such trigger can be created (e.g., because of implementation limits on the number of triggers).) + virtual void deleteEventTrigger(EventTriggerId eventTriggerId) = 0; + + virtual void triggerEvent(EventTriggerId eventTriggerId, void* clientData = NULL) = 0; + // Causes the (previously-registered) handler function for the specified event to be handled (from the event loop). + // The handler function is called with "clientData" as parameter. + // Note: This function (unlike other library functions) may be called from an external thread + // - to signal an external event. + // (In fact, this is the *only* LIVE555 function that can be called from a non-LIVE555 thread.) + // (However, "triggerEvent()" should not be called with the same 'event trigger id' from + // different threads. Also, once "triggerEvent()" is called with one 'event trigger id', + // it should not be called again with the same 'event trigger id' until after its event + // has been handled.) + + // The following two functions are deprecated, and are provided for backwards-compatibility only: + void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void* clientData) { + setBackgroundHandling(socketNum, SOCKET_READABLE, handlerProc, clientData); + } + void turnOffBackgroundReadHandling(int socketNum) { disableBackgroundHandling(socketNum); } + + virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library. + +protected: + TaskScheduler(); // abstract base class +}; + +#endif diff --git a/includes/live555/UsageEnvironment/UsageEnvironment_version.hh b/includes/live555/UsageEnvironment/UsageEnvironment_version.hh new file mode 100644 index 0000000..0eab4bc --- /dev/null +++ b/includes/live555/UsageEnvironment/UsageEnvironment_version.hh @@ -0,0 +1,25 @@ +/********** +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 +**********/ +// Version information for the "UsageEnvironment" library +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. + +#ifndef _USAGEENVIRONMENT_VERSION_HH +#define _USAGEENVIRONMENT_VERSION_HH + +#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2024.02.15" +#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1707955200 + +#endif diff --git a/includes/live555/UsageEnvironment/strDup.hh b/includes/live555/UsageEnvironment/strDup.hh new file mode 100644 index 0000000..eb7149d --- /dev/null +++ b/includes/live555/UsageEnvironment/strDup.hh @@ -0,0 +1,37 @@ +/********** +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 +**********/ + +#ifndef _STRDUP_HH +#define _STRDUP_HH + +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// A C++ equivalent to the standard C routine "strdup()". +// This generates a char* that can be deleted using "delete[]" +// Header + +#include + +LIVEMEDIA_API char* strDup(char const* str); +// Note: strDup(NULL) returns NULL + +LIVEMEDIA_API char* strDupSize(char const* str); +// Like "strDup()", except that it *doesn't* copy the original. +// (Instead, it just allocates a string of the same size as the original.) + +LIVEMEDIA_API char* strDupSize(char const* str, size_t& resultBufSize); +// An alternative form of "strDupSize()" that also returns the size of the allocated buffer. + +#endif diff --git a/includes/live555/groupsock/GroupEId.hh b/includes/live555/groupsock/GroupEId.hh new file mode 100644 index 0000000..42c9083 --- /dev/null +++ b/includes/live555/groupsock/GroupEId.hh @@ -0,0 +1,64 @@ +/********** +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 +**********/ +// "multikit" Multicast Application Shell +// Copyright (c) 1996-2024, Live Networks, Inc. All rights reserved +// "Group Endpoint Id" +// C++ header + +#ifndef _GROUPEID_HH +#define _GROUPEID_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif + +class LIVEMEDIA_API GroupEId { +public: + GroupEId(struct sockaddr_storage const& groupAddr, + portNumBits portNum, u_int8_t ttl); + // used for a 'source-independent multicast' group + GroupEId(struct sockaddr_storage const& groupAddr, + struct sockaddr_storage const& sourceFilterAddr, + portNumBits portNum); + // used for a 'source-specific multicast' group + GroupEId(); // tmp default constructor, until "Groupsock" interface uses "sockaddr_storage" + + struct sockaddr_storage const& groupAddress() const { return fGroupAddress; } + struct sockaddr_storage const& sourceFilterAddress() const { return fSourceFilterAddress; } + + Boolean isSSM() const; + + portNumBits portNum() const; + + u_int8_t ttl() const { return fTTL; } + +private: + void init(struct sockaddr_storage const& groupAddr, + struct sockaddr_storage const& sourceFilterAddr, + portNumBits portNum, + u_int8_t ttl); + +private: + struct sockaddr_storage fGroupAddress; // also includes port number (in network byte order) + struct sockaddr_storage fSourceFilterAddress; + u_int8_t fTTL; +}; + +#endif diff --git a/includes/live555/groupsock/Groupsock.hh b/includes/live555/groupsock/Groupsock.hh new file mode 100644 index 0000000..e3f3677 --- /dev/null +++ b/includes/live555/groupsock/Groupsock.hh @@ -0,0 +1,201 @@ +/********** +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 +**********/ +// "groupsock" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// 'Group sockets' +// C++ header + +#ifndef _GROUPSOCK_HH +#define _GROUPSOCK_HH + +#ifndef _GROUPSOCK_VERSION_HH +#include "groupsock_version.hh" +#endif + +#ifndef _NET_INTERFACE_HH +#include "NetInterface.hh" +#endif + +#ifndef _GROUPEID_HH +#include "GroupEId.hh" +#endif + +// An "OutputSocket" is (by default) used only to send packets. +// No packets are received on it (unless a subclass arranges this) + +class LIVEMEDIA_API OutputSocket: public Socket { +public: + OutputSocket(UsageEnvironment& env, int family); + virtual ~OutputSocket(); + + virtual Boolean write(struct sockaddr_storage const& addressAndPort, u_int8_t ttl, + unsigned char* buffer, unsigned bufferSize); + +protected: + OutputSocket(UsageEnvironment& env, Port port, int family); + + portNumBits sourcePortNum() const {return fSourcePort.num();} + +private: // redefined virtual function + virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, + unsigned& bytesRead, + struct sockaddr_storage& fromAddressAndPort); + +private: + Port fSourcePort; + unsigned fLastSentTTL; +}; + +class LIVEMEDIA_API destRecord { +public: + destRecord(struct sockaddr_storage const& addr, Port const& port, u_int8_t ttl, unsigned sessionId, + destRecord* next); + virtual ~destRecord(); + +public: + destRecord* fNext; + GroupEId fGroupEId; + unsigned fSessionId; +}; + +// A "Groupsock" is used to both send and receive packets. +// As the name suggests, it was originally designed to send/receive +// multicast, but it can send/receive unicast as well. + +class LIVEMEDIA_API Groupsock: public OutputSocket { +public: + Groupsock(UsageEnvironment& env, struct sockaddr_storage const& groupAddr, + Port port, u_int8_t ttl); + // used for a 'source-independent multicast' group + Groupsock(UsageEnvironment& env, struct sockaddr_storage const& groupAddr, + struct sockaddr_storage const& sourceFilterAddr, + Port port); + // used for a 'source-specific multicast' group + + virtual ~Groupsock(); + + virtual destRecord* createNewDestRecord(struct sockaddr_storage const& addr, Port const& port, u_int8_t ttl, unsigned sessionId, destRecord* next); + // Can be redefined by subclasses that also subclass "destRecord" + + void changeDestinationParameters(struct sockaddr_storage const& newDestAddr, + Port newDestPort, int newDestTTL, + unsigned sessionId = 0); + // By default, the destination address, port and ttl for + // outgoing packets are those that were specified in + // the constructor. This works OK for multicast sockets, + // but for unicast we usually want the destination port + // number, at least, to be different from the source port. + // (If a parameter is 0 (or ~0 for ttl), then no change is made to that parameter.) + // (If no existing "destRecord" exists with this "sessionId", then we add a new "destRecord".) + unsigned lookupSessionIdFromDestination(struct sockaddr_storage const& destAddrAndPort) const; + // returns 0 if not found + + // As a special case, we also allow multiple destinations (addresses & ports) + // (This can be used to implement multi-unicast.) + virtual void addDestination(struct sockaddr_storage const& addr, Port const& port, + unsigned sessionId); + virtual void removeDestination(unsigned sessionId); + void removeAllDestinations(); + Boolean hasMultipleDestinations() const { return fDests != NULL && fDests->fNext != NULL; } + + struct sockaddr_storage const& groupAddress() const { + return fIncomingGroupEId.groupAddress(); + } + struct sockaddr_storage const& sourceFilterAddress() const { + return fIncomingGroupEId.sourceFilterAddress(); + } + + Boolean isSSM() const { + return fIncomingGroupEId.isSSM(); + } + + u_int8_t ttl() const { return fIncomingGroupEId.ttl(); } + + void multicastSendOnly(); // send, but don't receive any multicast packets + + virtual Boolean output(UsageEnvironment& env, unsigned char* buffer, unsigned bufferSize); + + static NetInterfaceTrafficStats statsIncoming; + static NetInterfaceTrafficStats statsOutgoing; + NetInterfaceTrafficStats statsGroupIncoming; // *not* static + NetInterfaceTrafficStats statsGroupOutgoing; // *not* static + + Boolean wasLoopedBackFromUs(UsageEnvironment& env, + struct sockaddr_storage const& fromAddressAndPort); + +public: // redefined virtual functions + virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, + unsigned& bytesRead, + struct sockaddr_storage& fromAddressAndPort); + +protected: + destRecord* lookupDestRecordFromDestination(struct sockaddr_storage const& targetAddrAndPort) const; + +private: + void removeDestinationFrom(destRecord*& dests, unsigned sessionId); + // used to implement (the public) "removeDestination()", and "changeDestinationParameters()" +protected: + destRecord* fDests; +private: + GroupEId fIncomingGroupEId; +}; + +UsageEnvironment& operator<<(UsageEnvironment& s, const Groupsock& g); + +// A data structure for looking up a 'groupsock' +// by (multicast address, port), or by socket number +class LIVEMEDIA_API GroupsockLookupTable { +public: + Groupsock* Fetch(UsageEnvironment& env, struct sockaddr_storage const& groupAddress, + Port port, u_int8_t ttl, Boolean& isNew); + // Creates a new Groupsock if none already exists + Groupsock* Fetch(UsageEnvironment& env, struct sockaddr_storage const& groupAddress, + struct sockaddr_storage const& sourceFilterAddr, + Port port, Boolean& isNew); + // Creates a new Groupsock if none already exists + Groupsock* Lookup(struct sockaddr_storage const& groupAddress, Port port); + // Returns NULL if none already exists + Groupsock* Lookup(struct sockaddr_storage const& groupAddress, + struct sockaddr_storage const& sourceFilterAddr, + Port port); + // Returns NULL if none already exists + Groupsock* Lookup(UsageEnvironment& env, int sock); + // Returns NULL if none already exists + Boolean Remove(Groupsock const* groupsock); + + // Used to iterate through the groupsocks in the table + class Iterator { + public: + Iterator(GroupsockLookupTable& groupsocks); + + Groupsock* next(); // NULL iff none + + private: + AddressPortLookupTable::Iterator fIter; + }; + +private: + Groupsock* AddNew(UsageEnvironment& env, + struct sockaddr_storage const& groupAddress, + struct sockaddr_storage const& sourceFilterAddress, + Port port, u_int8_t ttl); + +private: + friend class Iterator; + AddressPortLookupTable fTable; +}; + +#endif diff --git a/includes/live555/groupsock/GroupsockHelper.hh b/includes/live555/groupsock/GroupsockHelper.hh new file mode 100644 index 0000000..0744064 --- /dev/null +++ b/includes/live555/groupsock/GroupsockHelper.hh @@ -0,0 +1,166 @@ +/********** +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 +**********/ +// "groupsock" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Helper routines to implement 'group sockets' +// C++ header + +#ifndef _GROUPSOCK_HELPER_HH +#define _GROUPSOCK_HELPER_HH + +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +LIVEMEDIA_API int setupDatagramSocket(UsageEnvironment& env, Port port, int domain); +LIVEMEDIA_API int setupStreamSocket(UsageEnvironment& env, Port port, int domain, + Boolean makeNonBlocking = True, Boolean setKeepAlive = False); + +LIVEMEDIA_API int readSocket(UsageEnvironment& env, + int socket, unsigned char* buffer, unsigned bufferSize, + struct sockaddr_storage& fromAddress /*set only if we're a datagram socket*/); + +LIVEMEDIA_API Boolean writeSocket(UsageEnvironment& env, + int socket, struct sockaddr_storage const& addressAndPort, + u_int8_t ttlArg, + unsigned char* buffer, unsigned bufferSize); + +LIVEMEDIA_API Boolean writeSocket(UsageEnvironment& env, + int socket, struct sockaddr_storage const& addressAndPort, + unsigned char* buffer, unsigned bufferSize); + // An optimized version of "writeSocket" that omits the "setsockopt()" call to set the TTL. + +LIVEMEDIA_API void ignoreSigPipeOnSocket(int socketNum); + +LIVEMEDIA_API unsigned getSendBufferSize(UsageEnvironment& env, int socket); +LIVEMEDIA_API unsigned getReceiveBufferSize(UsageEnvironment& env, int socket); +LIVEMEDIA_API unsigned setSendBufferTo(UsageEnvironment& env, + int socket, unsigned requestedSize); +LIVEMEDIA_API unsigned setReceiveBufferTo(UsageEnvironment& env, + int socket, unsigned requestedSize); +LIVEMEDIA_API unsigned increaseSendBufferTo(UsageEnvironment& env, + int socket, unsigned requestedSize); +LIVEMEDIA_API unsigned increaseReceiveBufferTo(UsageEnvironment& env, + int socket, unsigned requestedSize); + +LIVEMEDIA_API Boolean makeSocketNonBlocking(int sock); +LIVEMEDIA_API Boolean makeSocketBlocking(int sock, unsigned writeTimeoutInMilliseconds = 0); + // A "writeTimeoutInMilliseconds" value of 0 means: Don't timeout +LIVEMEDIA_API Boolean setSocketKeepAlive(int sock); + +LIVEMEDIA_API Boolean socketJoinGroup(UsageEnvironment& env, int socket, + struct sockaddr_storage const& groupAddress); +LIVEMEDIA_API Boolean socketLeaveGroup(UsageEnvironment&, int socket, + struct sockaddr_storage const& groupAddress); + +// source-specific multicast join/leave +LIVEMEDIA_API Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket, + struct sockaddr_storage const& groupAddress, + struct sockaddr_storage const& sourceFilterAddr); +LIVEMEDIA_API Boolean socketLeaveGroupSSM(UsageEnvironment&, int socket, + struct sockaddr_storage const& groupAddress, + struct sockaddr_storage const& sourceFilterAddr); + +LIVEMEDIA_API Boolean getSourcePort(UsageEnvironment& env, int socket, int domain, Port& port); + +LIVEMEDIA_API ipv4AddressBits ourIPv4Address(UsageEnvironment& env); // in network order +LIVEMEDIA_API ipv6AddressBits const& ourIPv6Address(UsageEnvironment& env); + +LIVEMEDIA_API Boolean weHaveAnIPv4Address(UsageEnvironment& env); +LIVEMEDIA_API Boolean weHaveAnIPv6Address(UsageEnvironment& env); +LIVEMEDIA_API Boolean weHaveAnIPAddress(UsageEnvironment& env); + // returns True if we have either an IPv4 or an IPv6 address + +// IPv4 addresses of our sending and receiving interfaces. (By default, these +// are INADDR_ANY (i.e., 0), specifying the default interface.) +LIVEMEDIA_API extern ipv4AddressBits SendingInterfaceAddr; +LIVEMEDIA_API extern ipv4AddressBits ReceivingInterfaceAddr; +LIVEMEDIA_API extern in6_addr ReceivingInterfaceAddr6; + +// Allocates a randomly-chosen IPv4 SSM (multicast) address: +LIVEMEDIA_API ipv4AddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env); + +// Returns a simple "hh:mm:ss" string, for use in debugging output (e.g.) +LIVEMEDIA_API char const* timestampString(); + + +#ifdef HAVE_SOCKADDR_LEN +#define SET_SOCKADDR_SIN_LEN(var) var.sin_len = sizeof var +#define SET_SOCKADDR_SIN6_LEN(var) var.sin6_len = sizeof var +#else +#define SET_SOCKADDR_SIN_LEN(var) +#define SET_SOCKADDR_SIN6_LEN(var) +#endif + +#define MAKE_SOCKADDR_IN(var,adr,prt) /*adr,prt must be in network order*/\ + struct sockaddr_in var;\ + var.sin_family = AF_INET;\ + var.sin_addr.s_addr = (adr);\ + var.sin_port = (prt);\ + SET_SOCKADDR_SIN_LEN(var); +#define MAKE_SOCKADDR_IN6(var,adr,prt) /*adr,prt must be in network order*/\ + struct sockaddr_in6 var;\ + memset(&var, 0, sizeof var);\ + var.sin6_family = AF_INET6;\ + var.sin6_addr=adr;\ + var.sin6_port = (prt);\ + SET_SOCKADDR_SIN6_LEN(var); + + +// By default, we create sockets with the SO_REUSE_* flag set. +// If, instead, you want to create sockets without the SO_REUSE_* flags, +// Then enclose the creation code with: +// { +// NoReuse dummy; +// ... +// } +class LIVEMEDIA_API NoReuse { +public: + NoReuse(UsageEnvironment& env); + ~NoReuse(); + +private: + UsageEnvironment& fEnv; +}; + + +// Define the "UsageEnvironment"-specific "groupsockPriv" structure: + +struct LIVEMEDIA_API _groupsockPriv { // There should be only one of these allocated + HashTable* socketTable; + int reuseFlag; +}; +LIVEMEDIA_API _groupsockPriv* groupsockPriv(UsageEnvironment& env); // allocates it if necessary +LIVEMEDIA_API void reclaimGroupsockPriv(UsageEnvironment& env); + + +#if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__) +// For Windoze, we need to implement our own gettimeofday() +extern LIVEMEDIA_API int gettimeofday(struct timeval*, int*); +#else +#include +#endif + +// The following are implemented in inet.c: +extern "C" LIVEMEDIA_API void our_srandom(int x); +extern "C" LIVEMEDIA_API long our_random(); +extern "C" LIVEMEDIA_API u_int32_t our_random32(); // because "our_random()" returns a 31-bit number + +#endif diff --git a/includes/live555/groupsock/IOHandlers.hh b/includes/live555/groupsock/IOHandlers.hh new file mode 100644 index 0000000..f3daadf --- /dev/null +++ b/includes/live555/groupsock/IOHandlers.hh @@ -0,0 +1,31 @@ +/********** +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 +**********/ +// "groupsock" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// IO event handlers +// C++ header + +#ifndef _IO_HANDLERS_HH +#define _IO_HANDLERS_HH + +#ifndef _NET_INTERFACE_HH +#include "NetInterface.hh" +#endif + +// Handles incoming data on sockets: +LIVEMEDIA_API void socketReadHandler(Socket* sock, int mask); + +#endif diff --git a/includes/live555/groupsock/NetAddress.hh b/includes/live555/groupsock/NetAddress.hh new file mode 100644 index 0000000..b79fce1 --- /dev/null +++ b/includes/live555/groupsock/NetAddress.hh @@ -0,0 +1,209 @@ +/********** +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 +**********/ +// "groupsock" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Network Addresses +// C++ header + +#ifndef _NET_ADDRESS_HH +#define _NET_ADDRESS_HH + +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif + +#ifndef _USAGE_ENVIRONMENT_HH +#include "UsageEnvironment.hh" +#endif + +// Definition of a type representing a low-level network address. + // Note that the type "netAddressBits" is no longer defined; use "ipv4AddressBits" instead. +typedef u_int32_t ipv4AddressBits; +typedef u_int8_t ipv6AddressBits[16]; // 128 bits + +class LIVEMEDIA_API NetAddress { +public: + NetAddress(u_int8_t const* data, + unsigned length = 4 /* default: 32 bits (for IPv4); use 16 (128 bits) for IPv6 */); + NetAddress(unsigned length = 4); // sets address data to all-zeros + NetAddress(NetAddress const& orig); + NetAddress& operator=(NetAddress const& rightSide); + virtual ~NetAddress(); + + unsigned length() const { return fLength; } + u_int8_t const* data() const // always in network byte order + { return fData; } + +private: + void assign(u_int8_t const* data, unsigned length); + void clean(); + + unsigned fLength; + u_int8_t* fData; +}; + +LIVEMEDIA_API struct sockaddr_storage const& nullAddress(int addressFamily = AF_INET); +LIVEMEDIA_API Boolean addressIsNull(sockaddr_storage const& address); + +LIVEMEDIA_API SOCKLEN_T addressSize(sockaddr_storage const& address); + +LIVEMEDIA_API void copyAddress(struct sockaddr_storage& to, NetAddress const* from); + +LIVEMEDIA_API Boolean operator==(struct sockaddr_storage const& left, struct sockaddr_storage const& right); + // compares the family and address parts only; not the port number or anything else + +class LIVEMEDIA_API NetAddressList { +public: + NetAddressList(char const* hostname, int addressFamily = AF_UNSPEC); + NetAddressList(NetAddressList const& orig); + NetAddressList& operator=(NetAddressList const& rightSide); + virtual ~NetAddressList(); + + unsigned numAddresses() const { return fNumAddresses; } + + NetAddress const* firstAddress() const; + + // Used to iterate through the addresses in a list: + class Iterator { + public: + Iterator(NetAddressList const& addressList); + NetAddress const* nextAddress(); // NULL iff none + private: + NetAddressList const& fAddressList; + unsigned fNextIndex; + }; + +private: + void assign(unsigned numAddresses, NetAddress** addressArray); + void clean(); + + friend class Iterator; + unsigned fNumAddresses; + NetAddress** fAddressArray; +}; + +typedef u_int16_t portNumBits; + +class LIVEMEDIA_API Port { +public: + Port(portNumBits num /* in host byte order */); + + portNumBits num() const { return fPortNum; } // in network byte order + +private: + portNumBits fPortNum; // stored in network byte order +#ifdef IRIX + portNumBits filler; // hack to overcome a bug in IRIX C++ compiler +#endif +}; + +UsageEnvironment& operator<<(UsageEnvironment& s, const Port& p); + + +// A generic table for looking up objects by (address1, address2, port) +class LIVEMEDIA_API AddressPortLookupTable { +public: + AddressPortLookupTable(); + virtual ~AddressPortLookupTable(); + + void* Add(struct sockaddr_storage const& address1, + struct sockaddr_storage const& address2, + Port port, + void* value); + // Returns the old value if different, otherwise 0 + void* Add(struct sockaddr_storage const& address1, + Port port, + void* value) { + return Add(address1, nullAddress(), port, value); + } + + Boolean Remove(struct sockaddr_storage const& address1, + struct sockaddr_storage const& address2, + Port port); + Boolean Remove(struct sockaddr_storage const& address1, + Port port) { + return Remove(address1, nullAddress(), port); + } + + void* Lookup(struct sockaddr_storage const& address1, + struct sockaddr_storage const& address2, + Port port); + // Returns 0 if not found + void* Lookup(struct sockaddr_storage const& address1, + Port port) { + return Lookup(address1, nullAddress(), port); + } + + void* RemoveNext() { return fTable->RemoveNext(); } + + // Used to iterate through the entries in the table + class Iterator { + public: + Iterator(AddressPortLookupTable& table); + virtual ~Iterator(); + + void* next(); // NULL iff none + + private: + HashTable::Iterator* fIter; + }; + +private: + friend class Iterator; + HashTable* fTable; +}; + + +LIVEMEDIA_API Boolean IsMulticastAddress(struct sockaddr_storage const& address); + + +// A mechanism for displaying an IP (v4 or v6) address in ASCII. +// (This encapsulates the "inet_ntop()" function.) +class LIVEMEDIA_API AddressString { +public: + // IPv4 input: + AddressString(struct sockaddr_in const& addr); + AddressString(struct in_addr const& addr); + AddressString(ipv4AddressBits const& addr); // "addr" is assumed to be in network byte order + + // IPv6 input: + AddressString(struct sockaddr_in6 const& addr); + AddressString(struct in6_addr const& addr); + AddressString(ipv6AddressBits const& addr); + + // IPv4 or IPv6 input: + AddressString(struct sockaddr_storage const& addr); + + virtual ~AddressString(); + + char const* val() const { return fVal; } + +private: + void init(ipv4AddressBits const& addr); // used to implement the IPv4 constructors + void init(ipv6AddressBits const& addr); // used to implement the IPv6 constructors + +private: + char* fVal; // The result ASCII string: allocated by the constructor; deleted by the destructor +}; + +LIVEMEDIA_API portNumBits portNum(struct sockaddr_storage const& address); +LIVEMEDIA_API void setPortNum(struct sockaddr_storage& address, portNumBits portNum/*in network order*/); + +#endif diff --git a/includes/live555/groupsock/NetCommon.h b/includes/live555/groupsock/NetCommon.h new file mode 100644 index 0000000..b194e44 --- /dev/null +++ b/includes/live555/groupsock/NetCommon.h @@ -0,0 +1,126 @@ +/********** +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 +**********/ +/* "groupsock" interface + * Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. + * Common include files, typically used for networking + */ + +#ifndef _NET_COMMON_H +#define _NET_COMMON_H + +#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_WCE) +/* Windows */ +#if defined(WINNT) || defined(_WINNT) || defined(__BORLANDC__) || defined(__MINGW32__) || defined(_WIN32_WCE) || defined (_MSC_VER) +#define _MSWSOCK_ +#include +#include +#endif +#include +#include +#include + +#define closeSocket closesocket +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif +#ifdef EINPROGRESS +#undef EINPROGRESS +#endif +#ifdef EAGAIN +#undef EAGAIN +#endif +#ifdef EINTR +#undef EINTR +#endif +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEWOULDBLOCK +#define EAGAIN WSAEWOULDBLOCK +#define EINTR WSAEINTR + +#if defined(_WIN32_WCE) +#define NO_STRSTREAM 1 +#endif + +/* Definitions of size-specific types: */ +typedef __int64 int64_t; +typedef unsigned __int64 u_int64_t; + +typedef int int32_t; +typedef unsigned u_int32_t; + +typedef short int16_t; +typedef unsigned short u_int16_t; + +typedef unsigned char u_int8_t; + +// For "uintptr_t" and "intptr_t", we assume that if they're not already defined, then this must be +// an old, 32-bit version of Windows: +#if !defined(_MSC_STDINT_H_) && !defined(_UINTPTR_T_DEFINED) && !defined(_UINTPTR_T_DECLARED) && !defined(_UINTPTR_T) +typedef unsigned uintptr_t; +#endif +#if !defined(_MSC_STDINT_H_) && !defined(_INTPTR_T_DEFINED) && !defined(_INTPTR_T_DECLARED) && !defined(_INTPTR_T) +typedef int intptr_t; +#endif + +#elif defined(VXWORKS) +/* VxWorks */ +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned char u_int8_t; + +#else +/* Unix */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_QNX4) +#include +#include +#endif + +#define closeSocket close + +#ifdef SOLARIS +#define u_int64_t uint64_t +#define u_int32_t uint32_t +#define u_int16_t uint16_t +#define u_int8_t uint8_t +#endif +#endif + +#ifndef SOCKLEN_T +#define SOCKLEN_T int +#endif + +#endif diff --git a/includes/live555/groupsock/NetInterface.hh b/includes/live555/groupsock/NetInterface.hh new file mode 100644 index 0000000..0f089c9 --- /dev/null +++ b/includes/live555/groupsock/NetInterface.hh @@ -0,0 +1,109 @@ +/********** +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 +**********/ +// "groupsock" +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Network Interfaces +// C++ header + +#ifndef _NET_INTERFACE_HH +#define _NET_INTERFACE_HH + +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif + +class LIVEMEDIA_API NetInterface { +public: + virtual ~NetInterface(); + + static UsageEnvironment* DefaultUsageEnvironment; + // if non-NULL, used for each new interface + +protected: + NetInterface(); // virtual base class +}; + +class LIVEMEDIA_API Socket: public NetInterface { +public: + virtual ~Socket(); + void reset(); // closes the socket, and sets "fSocketNum" to -1 + + virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, + unsigned& bytesRead, + struct sockaddr_storage& fromAddress) = 0; + // Returns False on error; resultData == NULL if data ignored + + int socketNum() const { return fSocketNum; } + + Port port() const { + return fPort; + } + + UsageEnvironment& env() const { return fEnv; } + + static int DebugLevel; + +protected: + Socket(UsageEnvironment& env, Port port, int family); // virtual base class + + Boolean changePort(Port newPort); // will also cause socketNum() to change + +private: + int fSocketNum; + UsageEnvironment& fEnv; + Port fPort; + int fFamily; +}; + +UsageEnvironment& operator<<(UsageEnvironment& s, const Socket& sock); + +// A data structure for looking up a Socket by port: + +class LIVEMEDIA_API SocketLookupTable { +public: + virtual ~SocketLookupTable(); + + Socket* Fetch(UsageEnvironment& env, Port port, Boolean& isNew); + // Creates a new Socket if none already exists + Boolean Remove(Socket const* sock); + +protected: + SocketLookupTable(); // abstract base class + virtual Socket* CreateNew(UsageEnvironment& env, Port port) = 0; + +private: + HashTable* fTable; +}; + +// A data structure for counting traffic: + +class LIVEMEDIA_API NetInterfaceTrafficStats { +public: + NetInterfaceTrafficStats(); + + void countPacket(unsigned packetSize); + + float totNumPackets() const {return fTotNumPackets;} + float totNumBytes() const {return fTotNumBytes;} + + Boolean haveSeenTraffic() const; + +private: + float fTotNumPackets; + float fTotNumBytes; +}; + +#endif diff --git a/includes/live555/groupsock/TunnelEncaps.hh b/includes/live555/groupsock/TunnelEncaps.hh new file mode 100644 index 0000000..b35c864 --- /dev/null +++ b/includes/live555/groupsock/TunnelEncaps.hh @@ -0,0 +1,101 @@ +/********** +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 +**********/ +// "mTunnel" multicast access service +// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. +// Encapsulation trailer for tunnels +// C++ header + +#ifndef _TUNNEL_ENCAPS_HH +#define _TUNNEL_ENCAPS_HH + +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif + +typedef u_int16_t Cookie; + +class LIVEMEDIA_API TunnelEncapsulationTrailer { + // The trailer is layed out as follows: + // bytes 0-1: source 'cookie' + // bytes 2-3: destination 'cookie' + // bytes 4-7: address + // bytes 8-9: port + // byte 10: ttl + // byte 11: command + + // Optionally, there may also be a 4-byte 'auxilliary address' + // (e.g., for 'source-specific multicast' preceding this) + // bytes -4 through -1: auxilliary address + + public: + Cookie& srcCookie() + { return *(Cookie*)byteOffset(0); } + Cookie& dstCookie() + { return *(Cookie*)byteOffset(2); } + u_int32_t& address() + { return *(u_int32_t*)byteOffset(4); } + Port& port() + { return *(Port*)byteOffset(8); } + u_int8_t& ttl() + { return *(u_int8_t*)byteOffset(10); } + u_int8_t& command() + { return *(u_int8_t*)byteOffset(11); } + + u_int32_t& auxAddress() + { return *(u_int32_t*)byteOffset(-4); } + + private: + inline char* byteOffset(int charIndex) + { return ((char*)this) + charIndex; } +}; + +const unsigned TunnelEncapsulationTrailerSize = 12; // bytes +const unsigned TunnelEncapsulationTrailerAuxSize = 4; // bytes +const unsigned TunnelEncapsulationTrailerMaxSize + = TunnelEncapsulationTrailerSize + TunnelEncapsulationTrailerAuxSize; + +// Command codes: +// 0: unused +const u_int8_t TunnelDataCmd = 1; +const u_int8_t TunnelJoinGroupCmd = 2; +const u_int8_t TunnelLeaveGroupCmd = 3; +const u_int8_t TunnelTearDownCmd = 4; +const u_int8_t TunnelProbeCmd = 5; +const u_int8_t TunnelProbeAckCmd = 6; +const u_int8_t TunnelProbeNackCmd = 7; +const u_int8_t TunnelJoinRTPGroupCmd = 8; +const u_int8_t TunnelLeaveRTPGroupCmd = 9; +// 0x0A through 0x10: currently unused. +const u_int8_t TunnelExtensionFlag = 0x80; // a flag, not a cmd code +const u_int8_t TunnelDataAuxCmd + = (TunnelExtensionFlag|TunnelDataCmd); +const u_int8_t TunnelJoinGroupAuxCmd + = (TunnelExtensionFlag|TunnelJoinGroupCmd); +const u_int8_t TunnelLeaveGroupAuxCmd + = (TunnelExtensionFlag|TunnelLeaveGroupCmd); +// Note: the TearDown, Probe, ProbeAck, ProbeNack cmds have no Aux version +// 0x84 through 0x87: currently unused. +const u_int8_t TunnelJoinRTPGroupAuxCmd + = (TunnelExtensionFlag|TunnelJoinRTPGroupCmd); +const u_int8_t TunnelLeaveRTPGroupAuxCmd + = (TunnelExtensionFlag|TunnelLeaveRTPGroupCmd); +// 0x8A through 0xFF: currently unused + +inline Boolean TunnelIsAuxCmd(u_int8_t cmd) { + return (cmd&TunnelExtensionFlag) != 0; +} + +#endif diff --git a/includes/live555/groupsock/groupsock_version.hh b/includes/live555/groupsock/groupsock_version.hh new file mode 100644 index 0000000..9e8e762 --- /dev/null +++ b/includes/live555/groupsock/groupsock_version.hh @@ -0,0 +1,25 @@ +/********** +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 +**********/ +// Version information for the "groupsock" library +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. + +#ifndef _GROUPSOCK_VERSION_HH +#define _GROUPSOCK_VERSION_HH + +#define GROUPSOCK_LIBRARY_VERSION_STRING "2024.02.15" +#define GROUPSOCK_LIBRARY_VERSION_INT 1707955200 + +#endif diff --git a/includes/live555/liveMedia/AC3AudioFileServerMediaSubsession.hh b/includes/live555/liveMedia/AC3AudioFileServerMediaSubsession.hh new file mode 100644 index 0000000..e68ec4d --- /dev/null +++ b/includes/live555/liveMedia/AC3AudioFileServerMediaSubsession.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an AC3 audio file. +// C++ header + +#ifndef _AC3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _AC3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API AC3AudioFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static AC3AudioFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + +private: + AC3AudioFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~AC3AudioFileServerMediaSubsession(); + +private: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); +}; + +#endif diff --git a/includes/live555/liveMedia/AC3AudioRTPSink.hh b/includes/live555/liveMedia/AC3AudioRTPSink.hh new file mode 100644 index 0000000..e13f9ed --- /dev/null +++ b/includes/live555/liveMedia/AC3AudioRTPSink.hh @@ -0,0 +1,57 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for AC3 audio +// C++ header + +#ifndef _AC3_AUDIO_RTP_SINK_HH +#define _AC3_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API AC3AudioRTPSink: public AudioRTPSink { +public: + static AC3AudioRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, + u_int32_t rtpTimestampFrequency); + +protected: + AC3AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, + u_int32_t rtpTimestampFrequency); + // called only by createNew() + + virtual ~AC3AudioRTPSink(); + +private: // redefined virtual functions: + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned specialHeaderSize() const; + +private: + unsigned char fTotNumFragmentsUsed; // used only if a frame gets fragmented across multiple packets +}; + +#endif diff --git a/includes/live555/liveMedia/AC3AudioRTPSource.hh b/includes/live555/liveMedia/AC3AudioRTPSource.hh new file mode 100644 index 0000000..0b92fdd --- /dev/null +++ b/includes/live555/liveMedia/AC3AudioRTPSource.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// AC3 Audio RTP Sources +// C++ header + +#ifndef _AC3_AUDIO_RTP_SOURCE_HH +#define _AC3_AUDIO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API AC3AudioRTPSource: public MultiFramedRTPSource { +public: + static AC3AudioRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + +protected: + virtual ~AC3AudioRTPSource(); + +private: + AC3AudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/AC3AudioStreamFramer.hh b/includes/live555/liveMedia/AC3AudioStreamFramer.hh new file mode 100644 index 0000000..1b77ca8 --- /dev/null +++ b/includes/live555/liveMedia/AC3AudioStreamFramer.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an AC3 audio elementary stream into frames +// C++ header + +#ifndef _AC3_AUDIO_STREAM_FRAMER_HH +#define _AC3_AUDIO_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API AC3AudioStreamFramer: public FramedFilter { +public: + static AC3AudioStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + unsigned char streamCode = 0); + // If "streamCode" != 0, then we assume that there's a 1-byte code at the beginning of each chunk of data that we read from + // our source. If that code is not the value we want, we discard the chunk of data. + // However, if "streamCode" == 0 (the default), then we don't expect this 1-byte code. + + unsigned samplingRate(); + + void flushInput(); // called if there is a discontinuity (seeking) in the input + +private: + AC3AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, + unsigned char streamCode); + // called only by createNew() + virtual ~AC3AudioStreamFramer(); + + static void handleNewData(void* clientData, + unsigned char* ptr, unsigned size, + struct timeval presentationTime); + void handleNewData(unsigned char* ptr, unsigned size); + + void parseNextFrame(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + struct timeval currentFramePlayTime() const; + +private: + struct timeval fNextFramePresentationTime; + +private: // parsing state + class AC3AudioStreamParser* fParser; + unsigned char fOurStreamCode; + friend class AC3AudioStreamParser; // hack +}; + +#endif diff --git a/includes/live555/liveMedia/ADTSAudioFileServerMediaSubsession.hh b/includes/live555/liveMedia/ADTSAudioFileServerMediaSubsession.hh new file mode 100644 index 0000000..5c1d61e --- /dev/null +++ b/includes/live555/liveMedia/ADTSAudioFileServerMediaSubsession.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an AAC audio file in ADTS format +// C++ header + +#ifndef _ADTS_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _ADTS_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API ADTSAudioFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static ADTSAudioFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + +protected: + ADTSAudioFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~ADTSAudioFileServerMediaSubsession(); + +protected: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); +}; + +#endif diff --git a/includes/live555/liveMedia/ADTSAudioFileSource.hh b/includes/live555/liveMedia/ADTSAudioFileSource.hh new file mode 100644 index 0000000..6863748 --- /dev/null +++ b/includes/live555/liveMedia/ADTSAudioFileSource.hh @@ -0,0 +1,56 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A source object for AAC audio files in ADTS format +// C++ header + +#ifndef _ADTS_AUDIO_FILE_SOURCE_HH +#define _ADTS_AUDIO_FILE_SOURCE_HH + +#ifndef _FRAMED_FILE_SOURCE_HH +#include "FramedFileSource.hh" +#endif + +class LIVEMEDIA_API ADTSAudioFileSource: public FramedFileSource { +public: + static ADTSAudioFileSource* createNew(UsageEnvironment& env, + char const* fileName); + + unsigned samplingFrequency() const { return fSamplingFrequency; } + unsigned numChannels() const { return fNumChannels; } + char const* configStr() const { return fConfigStr; } + // returns the 'AudioSpecificConfig' for this stream (in ASCII form) + +private: + ADTSAudioFileSource(UsageEnvironment& env, FILE* fid, u_int8_t profile, + u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration); + // called only by createNew() + + virtual ~ADTSAudioFileSource(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + unsigned fSamplingFrequency; + unsigned fNumChannels; + unsigned fuSecsPerFrame; + char fConfigStr[5]; +}; + +#endif diff --git a/includes/live555/liveMedia/ADTSAudioStreamDiscreteFramer.hh b/includes/live555/liveMedia/ADTSAudioStreamDiscreteFramer.hh new file mode 100644 index 0000000..f1640eb --- /dev/null +++ b/includes/live555/liveMedia/ADTSAudioStreamDiscreteFramer.hh @@ -0,0 +1,61 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that reads (discrete) AAC audio frames, and outputs each frame with +// a preceding ADTS header. +// C++ header + +#ifndef _ADTS_AUDIO_STREAM_DISCRETE_FRAMER_HH +#define _ADTS_AUDIO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +#define ADTS_HEADER_SIZE 7 // we don't include a checksum + +class LIVEMEDIA_API ADTSAudioStreamDiscreteFramer: public FramedFilter { +public: + static ADTSAudioStreamDiscreteFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, char const* configStr); + // "configStr" should be a 4-character hexadecimal string for a 2-byte value + +protected: + ADTSAudioStreamDiscreteFramer(UsageEnvironment& env, FramedSource* inputSource, + u_int8_t profile, u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration); + // called only by createNew() + virtual ~ADTSAudioStreamDiscreteFramer(); + +protected: + // redefined virtual functions: + virtual void doGetNextFrame(); + +protected: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + u_int8_t fADTSHeader[ADTS_HEADER_SIZE]; +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioFileServerMediaSubsession.hh b/includes/live555/liveMedia/AMRAudioFileServerMediaSubsession.hh new file mode 100644 index 0000000..7e28907 --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioFileServerMediaSubsession.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an AMR audio file. +// C++ header + +#ifndef _AMR_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _AMR_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API AMRAudioFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static AMRAudioFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + +private: + AMRAudioFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~AMRAudioFileServerMediaSubsession(); + +private: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioFileSink.hh b/includes/live555/liveMedia/AMRAudioFileSink.hh new file mode 100644 index 0000000..a836a7d --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioFileSink.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// AMR Audio File Sinks +// C++ header + +#ifndef _AMR_AUDIO_FILE_SINK_HH +#define _AMR_AUDIO_FILE_SINK_HH + +#ifndef _FILE_SINK_HH +#include "FileSink.hh" +#endif + +class LIVEMEDIA_API AMRAudioFileSink: public FileSink { +public: + static AMRAudioFileSink* createNew(UsageEnvironment& env, char const* fileName, + unsigned bufferSize = 10000, + Boolean oneFilePerFrame = False); + // (See "FileSink.hh" for a description of these parameters.) + +protected: + AMRAudioFileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, + char const* perFrameFileNamePrefix); + // called only by createNew() + virtual ~AMRAudioFileSink(); + +protected: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + virtual void afterGettingFrame(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime); + +protected: + Boolean fHaveWrittenHeader; +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioFileSource.hh b/includes/live555/liveMedia/AMRAudioFileSource.hh new file mode 100644 index 0000000..da446ba --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioFileSource.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A source object for AMR audio files (as defined in RFC 4867, section 5) +// C++ header + +#ifndef _AMR_AUDIO_FILE_SOURCE_HH +#define _AMR_AUDIO_FILE_SOURCE_HH + +#ifndef _AMR_AUDIO_SOURCE_HH +#include "AMRAudioSource.hh" +#endif + +class LIVEMEDIA_API AMRAudioFileSource: public AMRAudioSource { +public: + static AMRAudioFileSource* createNew(UsageEnvironment& env, + char const* fileName); + +private: + AMRAudioFileSource(UsageEnvironment& env, FILE* fid, + Boolean isWideband, unsigned numChannels); + // called only by createNew() + + virtual ~AMRAudioFileSource(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + FILE* fFid; +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioRTPSink.hh b/includes/live555/liveMedia/AMRAudioRTPSink.hh new file mode 100644 index 0000000..ab8dad4 --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioRTPSink.hh @@ -0,0 +1,65 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for AMR audio (RFC 4867) +// C++ header + +#ifndef _AMR_AUDIO_RTP_SINK_HH +#define _AMR_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API AMRAudioRTPSink: public AudioRTPSink { +public: + static AMRAudioRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + Boolean sourceIsWideband = False, + unsigned numChannelsInSource = 1); + + Boolean sourceIsWideband() const { return fSourceIsWideband; } + +protected: + AMRAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + Boolean sourceIsWideband, unsigned numChannelsInSource); + // called only by createNew() + + virtual ~AMRAudioRTPSink(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean + frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + + virtual unsigned specialHeaderSize() const; + virtual char const* auxSDPLine(); + +private: + Boolean fSourceIsWideband; + char* fFmtpSDPLine; +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioRTPSource.hh b/includes/live555/liveMedia/AMRAudioRTPSource.hh new file mode 100644 index 0000000..6f33ce9 --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioRTPSource.hh @@ -0,0 +1,53 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// AMR Audio RTP Sources (RFC 4867) +// C++ header + +#ifndef _AMR_AUDIO_RTP_SOURCE_HH +#define _AMR_AUDIO_RTP_SOURCE_HH + +#ifndef _RTP_SOURCE_HH +#include "RTPSource.hh" +#endif +#ifndef _AMR_AUDIO_SOURCE_HH +#include "AMRAudioSource.hh" +#endif + +class LIVEMEDIA_API AMRAudioRTPSource { +public: + static AMRAudioSource* createNew(UsageEnvironment& env, + Groupsock* RTPgs, + RTPSource*& resultRTPSource, + unsigned char rtpPayloadFormat, + Boolean isWideband = False, + unsigned numChannels = 1, + Boolean isOctetAligned = True, + unsigned interleaving = 0, + // relevant only if "isOctetAligned" + // The maximum # of frame-blocks in a group + // 0 means: no interleaving + Boolean robustSortingOrder = False, + // relevant only if "isOctetAligned" + Boolean CRCsArePresent = False + // relevant only if "isOctetAligned" + ); + // This returns a source to read from, but "resultRTPSource" will + // point to RTP-related state. +}; + +#endif diff --git a/includes/live555/liveMedia/AMRAudioSource.hh b/includes/live555/liveMedia/AMRAudioSource.hh new file mode 100644 index 0000000..05617bc --- /dev/null +++ b/includes/live555/liveMedia/AMRAudioSource.hh @@ -0,0 +1,52 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A source object for AMR audio sources +// C++ header + +#ifndef _AMR_AUDIO_SOURCE_HH +#define _AMR_AUDIO_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API AMRAudioSource: public FramedSource { +public: + Boolean isWideband() const { return fIsWideband; } + unsigned numChannels() const { return fNumChannels; } + + u_int8_t lastFrameHeader() const { return fLastFrameHeader; } + // The frame header for the most recently read frame (RFC 4867, sec. 5.3) + +protected: + AMRAudioSource(UsageEnvironment& env, Boolean isWideband, unsigned numChannels); + // virtual base class + virtual ~AMRAudioSource(); + +private: + // redefined virtual functions: + virtual char const* MIMEtype() const; + virtual Boolean isAMRAudioSource() const; + +protected: + Boolean fIsWideband; + unsigned fNumChannels; + u_int8_t fLastFrameHeader; +}; + +#endif diff --git a/includes/live555/liveMedia/AVIFileSink.hh b/includes/live555/liveMedia/AVIFileSink.hh new file mode 100644 index 0000000..5c0622f --- /dev/null +++ b/includes/live555/liveMedia/AVIFileSink.hh @@ -0,0 +1,115 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A sink that generates an AVI file from a composite media session +// C++ header + +#ifndef _AVI_FILE_SINK_HH +#define _AVI_FILE_SINK_HH + +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif + +class LIVEMEDIA_API AVIFileSink: public Medium { +public: + static AVIFileSink* createNew(UsageEnvironment& env, + MediaSession& inputSession, + char const* outputFileName, + unsigned bufferSize = 20000, + unsigned short movieWidth = 240, + unsigned short movieHeight = 180, + unsigned movieFPS = 15, + Boolean packetLossCompensate = False); + + typedef void (afterPlayingFunc)(void* clientData); + Boolean startPlaying(afterPlayingFunc* afterFunc, + void* afterClientData); + + unsigned numActiveSubsessions() const { return fNumSubsessions; } + +private: + AVIFileSink(UsageEnvironment& env, MediaSession& inputSession, + char const* outputFileName, unsigned bufferSize, + unsigned short movieWidth, unsigned short movieHeight, + unsigned movieFPS, Boolean packetLossCompensate); + // called only by createNew() + virtual ~AVIFileSink(); + + Boolean continuePlaying(); + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + static void onSourceClosure(void* clientData); + void onSourceClosure1(); + static void onRTCPBye(void* clientData); + void addIndexRecord(class AVIIndexRecord* newIndexRecord); + void completeOutputFile(); + +private: + friend class AVISubsessionIOState; + MediaSession& fInputSession; + FILE* fOutFid; + class AVIIndexRecord *fIndexRecordsHead, *fIndexRecordsTail; + unsigned fNumIndexRecords; + unsigned fBufferSize; + Boolean fPacketLossCompensate; + Boolean fAreCurrentlyBeingPlayed; + afterPlayingFunc* fAfterFunc; + void* fAfterClientData; + unsigned fNumSubsessions; + unsigned fNumBytesWritten; + struct timeval fStartTime; + Boolean fHaveCompletedOutputFile; + +private: + ///// Definitions specific to the AVI file format: + + unsigned addWord(unsigned word); // outputs "word" in little-endian order + unsigned addHalfWord(unsigned short halfWord); + unsigned addByte(unsigned char byte) { + putc(byte, fOutFid); + return 1; + } + unsigned addZeroWords(unsigned numWords); + unsigned add4ByteString(char const* str); + void setWord(unsigned filePosn, unsigned size); + + // Define member functions for outputting various types of file header: +#define _header(name) unsigned addFileHeader_##name() + _header(AVI); + _header(hdrl); + _header(avih); + _header(strl); + _header(strh); + _header(strf); + _header(JUNK); +// _header(JUNK); + _header(movi); +private: + unsigned short fMovieWidth, fMovieHeight; + unsigned fMovieFPS; + unsigned fRIFFSizePosition, fRIFFSizeValue; + unsigned fAVIHMaxBytesPerSecondPosition; + unsigned fAVIHFrameCountPosition; + unsigned fMoviSizePosition, fMoviSizeValue; + class AVISubsessionIOState* fCurrentIOState; + unsigned fJunkNumber; +}; + +#endif diff --git a/includes/live555/liveMedia/AudioInputDevice.hh b/includes/live555/liveMedia/AudioInputDevice.hh new file mode 100644 index 0000000..710e63f --- /dev/null +++ b/includes/live555/liveMedia/AudioInputDevice.hh @@ -0,0 +1,71 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// Generic audio input device (such as a microphone, or an input sound card) +// C++ header + +#ifndef _AUDIO_INPUT_DEVICE_HH +#define _AUDIO_INPUT_DEVICE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API AudioPortNames { +public: + AudioPortNames(); + virtual ~AudioPortNames(); + + unsigned numPorts; + char** portName; +}; + +class LIVEMEDIA_API AudioInputDevice: public FramedSource { +public: + unsigned char bitsPerSample() const { return fBitsPerSample; } + unsigned char numChannels() const { return fNumChannels; } + unsigned samplingFrequency() const { return fSamplingFrequency; } + + virtual Boolean setInputPort(int portIndex) = 0; + virtual double getAverageLevel() const = 0; + + static AudioInputDevice* + createNew(UsageEnvironment& env, int inputPortNumber, + unsigned char bitsPerSample, unsigned char numChannels, + unsigned samplingFrequency, unsigned granularityInMS = 20); + static AudioPortNames* getPortNames(); + + static char** allowedDeviceNames; + // If this is set to non-NULL, then it's a NULL-terminated array of strings + // of device names that we are allowed to access. + +protected: + AudioInputDevice(UsageEnvironment& env, + unsigned char bitsPerSample, + unsigned char numChannels, + unsigned samplingFrequency, + unsigned granularityInMS); + // we're an abstract base class + + virtual ~AudioInputDevice(); + +protected: + unsigned char fBitsPerSample, fNumChannels; + unsigned fSamplingFrequency; + unsigned fGranularityInMS; +}; + +#endif diff --git a/includes/live555/liveMedia/AudioRTPSink.hh b/includes/live555/liveMedia/AudioRTPSink.hh new file mode 100644 index 0000000..939e126 --- /dev/null +++ b/includes/live555/liveMedia/AudioRTPSink.hh @@ -0,0 +1,42 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic RTP sink for audio codecs (abstract base class) +// C++ header + +#ifndef _AUDIO_RTP_SINK_HH +#define _AUDIO_RTP_SINK_HH + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#include "MultiFramedRTPSink.hh" +#endif + +class LIVEMEDIA_API AudioRTPSink: public MultiFramedRTPSink { +protected: + AudioRTPSink(UsageEnvironment& env, + Groupsock* rtpgs, unsigned char rtpPayloadType, + unsigned rtpTimestampFrequency, + char const* rtpPayloadFormatName, + unsigned numChannels = 1); + // (we're an abstract base class) + virtual ~AudioRTPSink(); + +private: // redefined virtual functions: + virtual char const* sdpMediaType() const; +}; + +#endif diff --git a/includes/live555/liveMedia/Base64.hh b/includes/live555/liveMedia/Base64.hh new file mode 100644 index 0000000..deaa09d --- /dev/null +++ b/includes/live555/liveMedia/Base64.hh @@ -0,0 +1,43 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Base64 encoding and decoding +// C++ header + +#ifndef _BASE64_HH +#define _BASE64_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +LIVEMEDIA_API unsigned char* base64Decode(char const* in, unsigned& resultSize, + Boolean trimTrailingZeros = True); + // returns a newly allocated array - of size "resultSize" - that + // the caller is responsible for delete[]ing. + +LIVEMEDIA_API unsigned char* base64Decode(char const* in, unsigned inSize, + unsigned& resultSize, + Boolean trimTrailingZeros = True); + // As above, but includes the size of the input string (i.e., the number of bytes to decode) as a parameter. + // This saves an extra call to "strlen()" if we already know the length of the input string. + +LIVEMEDIA_API char* base64Encode(char const* orig, unsigned origLength); + // returns a 0-terminated string that + // the caller is responsible for delete[]ing. + +#endif diff --git a/includes/live555/liveMedia/BasicUDPSink.hh b/includes/live555/liveMedia/BasicUDPSink.hh new file mode 100644 index 0000000..b25de47 --- /dev/null +++ b/includes/live555/liveMedia/BasicUDPSink.hh @@ -0,0 +1,62 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simple UDP sink (i.e., without RTP or other headers added); one frame per packet +// C++ header + +#ifndef _BASIC_UDP_SINK_HH +#define _BASIC_UDP_SINK_HH + +#ifndef _MEDIA_SINK_HH +#include "MediaSink.hh" +#endif +#ifndef _GROUPSOCK_HH +#include +#endif + +class LIVEMEDIA_API BasicUDPSink: public MediaSink { +public: + static BasicUDPSink* createNew(UsageEnvironment& env, Groupsock* gs, + unsigned maxPayloadSize = 1450); +protected: + BasicUDPSink(UsageEnvironment& env, Groupsock* gs, unsigned maxPayloadSize); + // called only by createNew() + virtual ~BasicUDPSink(); + +private: // redefined virtual functions: + virtual Boolean continuePlaying(); + +private: + void continuePlaying1(); + + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, + unsigned durationInMicroseconds); + + static void sendNext(void* firstArg); + +private: + Groupsock* fGS; + unsigned fMaxPayloadSize; + unsigned char* fOutputBuffer; + struct timeval fNextSendTime; +}; + +#endif diff --git a/includes/live555/liveMedia/BasicUDPSource.hh b/includes/live555/liveMedia/BasicUDPSource.hh new file mode 100644 index 0000000..d21cc43 --- /dev/null +++ b/includes/live555/liveMedia/BasicUDPSource.hh @@ -0,0 +1,56 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simple UDP source, where every UDP payload is a complete frame +// C++ header + +#ifndef _BASIC_UDP_SOURCE_HH +#define _BASIC_UDP_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif +#ifndef _GROUPSOCK_HH +#include "Groupsock.hh" +#endif + +class LIVEMEDIA_API BasicUDPSource: public FramedSource { +public: + static BasicUDPSource* createNew(UsageEnvironment& env, Groupsock* inputGS); + + virtual ~BasicUDPSource(); + + Groupsock* gs() const { return fInputGS; } + +private: + BasicUDPSource(UsageEnvironment& env, Groupsock* inputGS); + // called only by createNew() + + static void incomingPacketHandler(BasicUDPSource* source, int mask); + void incomingPacketHandler1(); + +private: // redefined virtual functions: + virtual unsigned maxFrameSize() const; + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + Groupsock* fInputGS; + Boolean fHaveStartedReading; +}; + +#endif diff --git a/includes/live555/liveMedia/BitVector.hh b/includes/live555/liveMedia/BitVector.hh new file mode 100644 index 0000000..dc77e54 --- /dev/null +++ b/includes/live555/liveMedia/BitVector.hh @@ -0,0 +1,67 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Bit Vector data structure +// C++ header + +#ifndef _BIT_VECTOR_HH +#define _BIT_VECTOR_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +class LIVEMEDIA_API BitVector { +public: + BitVector(unsigned char* baseBytePtr, + unsigned baseBitOffset, + unsigned totNumBits); + + void setup(unsigned char* baseBytePtr, + unsigned baseBitOffset, + unsigned totNumBits); + + void putBits(unsigned from, unsigned numBits); // "numBits" <= 32 + void put1Bit(unsigned bit); + + unsigned getBits(unsigned numBits); // "numBits" <= 32 + unsigned get1Bit(); + Boolean get1BitBoolean() { return get1Bit() != 0; } + + void skipBits(unsigned numBits); + + unsigned curBitIndex() const { return fCurBitIndex; } + unsigned totNumBits() const { return fTotNumBits; } + unsigned numBitsRemaining() const { return fTotNumBits - fCurBitIndex; } + + unsigned get_expGolomb(); + // Returns the value of the next bits, assuming that they were encoded using an exponential-Golomb code of order 0 + int get_expGolombSigned(); // signed version of the above + +private: + unsigned char* fBaseBytePtr; + unsigned fBaseBitOffset; + unsigned fTotNumBits; + unsigned fCurBitIndex; +}; + +// A general bit copy operation: +void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset, + unsigned char const* fromBasePtr, unsigned fromBitOffset, + unsigned numBits); + +#endif diff --git a/includes/live555/liveMedia/ByteStreamFileSource.hh b/includes/live555/liveMedia/ByteStreamFileSource.hh new file mode 100644 index 0000000..841a895 --- /dev/null +++ b/includes/live555/liveMedia/ByteStreamFileSource.hh @@ -0,0 +1,82 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A file source that is a plain byte stream (rather than frames) +// C++ header + +#ifndef _BYTE_STREAM_FILE_SOURCE_HH +#define _BYTE_STREAM_FILE_SOURCE_HH + +#ifndef _FRAMED_FILE_SOURCE_HH +#include "FramedFileSource.hh" +#endif + +class LIVEMEDIA_API ByteStreamFileSource: public FramedFileSource { +public: + static ByteStreamFileSource* createNew(UsageEnvironment& env, + char const* fileName, + unsigned preferredFrameSize = 0, + unsigned playTimePerFrame = 0); + // "preferredFrameSize" == 0 means 'no preference' + // "playTimePerFrame" is in microseconds + + static ByteStreamFileSource* createNew(UsageEnvironment& env, + FILE* fid, + unsigned preferredFrameSize = 0, + unsigned playTimePerFrame = 0); + // an alternative version of "createNew()" that's used if you already have + // an open file. + + u_int64_t fileSize() const { return fFileSize; } + // 0 means zero-length, unbounded, or unknown + + void seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream = 0); + // if "numBytesToStream" is >0, then we limit the stream to that number of bytes, before treating it as EOF + void seekToByteRelative(int64_t offset, u_int64_t numBytesToStream = 0); + void seekToEnd(); // to force EOF handling on the next read + +protected: + ByteStreamFileSource(UsageEnvironment& env, + FILE* fid, + unsigned preferredFrameSize, + unsigned playTimePerFrame); + // called only by createNew() + + virtual ~ByteStreamFileSource(); + + static void fileReadableHandler(ByteStreamFileSource* source, int mask); + void doReadFromFile(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +protected: + u_int64_t fFileSize; + +private: + unsigned fPreferredFrameSize; + unsigned fPlayTimePerFrame; + Boolean fFidIsSeekable; + unsigned fLastPlayTime; + Boolean fHaveStartedReading; + Boolean fLimitNumBytesToStream; + u_int64_t fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True +}; + +#endif diff --git a/includes/live555/liveMedia/ByteStreamMemoryBufferSource.hh b/includes/live555/liveMedia/ByteStreamMemoryBufferSource.hh new file mode 100644 index 0000000..4b195d5 --- /dev/null +++ b/includes/live555/liveMedia/ByteStreamMemoryBufferSource.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class for streaming data from a (static) memory buffer, as if it were a file. +// C++ header + +#ifndef _BYTE_STREAM_MEMORY_BUFFER_SOURCE_HH +#define _BYTE_STREAM_MEMORY_BUFFER_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API ByteStreamMemoryBufferSource: public FramedSource { +public: + static ByteStreamMemoryBufferSource* createNew(UsageEnvironment& env, + u_int8_t* buffer, u_int64_t bufferSize, + Boolean deleteBufferOnClose = True, + unsigned preferredFrameSize = 0, + unsigned playTimePerFrame = 0); + // "preferredFrameSize" == 0 means 'no preference' + // "playTimePerFrame" is in microseconds + + u_int64_t bufferSize() const { return fBufferSize; } + + void seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream = 0); + // if "numBytesToStream" is >0, then we limit the stream to that number of bytes, before treating it as EOF + void seekToByteRelative(int64_t offset, u_int64_t numBytesToStream = 0); + +protected: + ByteStreamMemoryBufferSource(UsageEnvironment& env, + u_int8_t* buffer, u_int64_t bufferSize, + Boolean deleteBufferOnClose, + unsigned preferredFrameSize, + unsigned playTimePerFrame); + // called only by createNew() + + virtual ~ByteStreamMemoryBufferSource(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + u_int8_t* fBuffer; + u_int64_t fBufferSize; + u_int64_t fCurIndex; + Boolean fDeleteBufferOnClose; + unsigned fPreferredFrameSize; + unsigned fPlayTimePerFrame; + unsigned fLastPlayTime; + Boolean fLimitNumBytesToStream; + u_int64_t fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True +}; + +#endif diff --git a/includes/live555/liveMedia/ByteStreamMultiFileSource.hh b/includes/live555/liveMedia/ByteStreamMultiFileSource.hh new file mode 100644 index 0000000..7020d43 --- /dev/null +++ b/includes/live555/liveMedia/ByteStreamMultiFileSource.hh @@ -0,0 +1,69 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A source that consists of multiple byte-stream files, read sequentially. +// (The input is an array of file names, with a terminating 'file name' of NULL.) +// C++ header + +#ifndef _BYTE_STREAM_MULTI_FILE_SOURCE_HH +#define _BYTE_STREAM_MULTI_FILE_SOURCE_HH + +#ifndef _BYTE_STREAM_FILE_SOURCE_HH +#include "ByteStreamFileSource.hh" +#endif + +class LIVEMEDIA_API ByteStreamMultiFileSource: public FramedSource { +public: + static ByteStreamMultiFileSource* + createNew(UsageEnvironment& env, char const** fileNameArray, + unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0); + // "fileNameArray" is a pointer to an array of (char const*) file names, with + // A 'file name' of NULL indicating the end of the array + + Boolean haveStartedNewFile() const { return fHaveStartedNewFile; } + // True iff the most recently delivered frame was the first from a newly-opened file + +protected: + ByteStreamMultiFileSource(UsageEnvironment& env, char const** fileNameArray, + unsigned preferredFrameSize, unsigned playTimePerFrame); + // called only by createNew() + + virtual ~ByteStreamMultiFileSource(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void onSourceClosure(void* clientData); + void onSourceClosure1(); + static void afterGettingFrame(void* clientData, + unsigned frameSize, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + unsigned fPreferredFrameSize; + unsigned fPlayTimePerFrame; + unsigned fNumSources; + unsigned fCurrentlyReadSourceNumber; + Boolean fHaveStartedNewFile; + char const** fFileNameArray; + ByteStreamFileSource** fSourceArray; +}; + +#endif diff --git a/includes/live555/liveMedia/DVVideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/DVVideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..bd0014b --- /dev/null +++ b/includes/live555/liveMedia/DVVideoFileServerMediaSubsession.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a DV video file. +// C++ header + +#ifndef _DV_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _DV_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API DVVideoFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static DVVideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + +private: + DVVideoFileServerMediaSubsession(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~DVVideoFileServerMediaSubsession(); + +private: // redefined virtual functions + virtual char const* getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource); + virtual void seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual void setStreamSourceDuration(FramedSource* inputSource, double streamDuration, u_int64_t& numBytes); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource); + virtual float duration() const; + +private: + float fFileDuration; // in seconds +}; + +#endif diff --git a/includes/live555/liveMedia/DVVideoRTPSink.hh b/includes/live555/liveMedia/DVVideoRTPSink.hh new file mode 100644 index 0000000..6f6d0f9 --- /dev/null +++ b/includes/live555/liveMedia/DVVideoRTPSink.hh @@ -0,0 +1,57 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for DV video (RFC 3189) +// (Thanks to Ben Hutchings for prototyping this.) +// C++ header + +#ifndef _DV_VIDEO_RTP_SINK_HH +#define _DV_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif +#ifndef _DV_VIDEO_STREAM_FRAMER_HH +#include "DVVideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API DVVideoRTPSink: public VideoRTPSink { +public: + static DVVideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + char const* auxSDPLineFromFramer(DVVideoStreamFramer* framerSource); + +protected: + DVVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + // called only by createNew() + + virtual ~DVVideoRTPSink(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned computeOverflowForNewFrame(unsigned newFrameSize) const; + virtual char const* auxSDPLine(); + +private: + char* fFmtpSDPLine; +}; + +#endif diff --git a/includes/live555/liveMedia/DVVideoRTPSource.hh b/includes/live555/liveMedia/DVVideoRTPSource.hh new file mode 100644 index 0000000..c1e9670 --- /dev/null +++ b/includes/live555/liveMedia/DVVideoRTPSource.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// DV Video RTP Sources +// C++ header + +#ifndef _DV_VIDEO_RTP_SOURCE_HH +#define _DV_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API DVVideoRTPSource: public MultiFramedRTPSource { +public: + static DVVideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + +protected: + virtual ~DVVideoRTPSource(); + +private: + DVVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/DVVideoStreamFramer.hh b/includes/live555/liveMedia/DVVideoStreamFramer.hh new file mode 100644 index 0000000..380e79a --- /dev/null +++ b/includes/live555/liveMedia/DVVideoStreamFramer.hh @@ -0,0 +1,72 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that parses a DV input stream into DV frames to deliver to the downstream object +// C++ header + +#ifndef _DV_VIDEO_STREAM_FRAMER_HH +#define _DV_VIDEO_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +#define DV_DIF_BLOCK_SIZE 80 +#define DV_NUM_BLOCKS_PER_SEQUENCE 150 +#define DV_SAVED_INITIAL_BLOCKS_SIZE ((DV_NUM_BLOCKS_PER_SEQUENCE+6-1)*DV_DIF_BLOCK_SIZE) + /* enough data to ensure that it contains an intact 6-block header (which occurs at the start of a 150-block sequence) */ + +class LIVEMEDIA_API DVVideoStreamFramer: public FramedFilter { +public: + static DVVideoStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean sourceIsSeekable = False, Boolean leavePresentationTimesUnmodified = False); + // Set "sourceIsSeekable" to True if the input source is a seekable object (e.g. a file), and the server that uses us + // does a seek-to-zero on the source before reading from it. (Our RTSP server implementation does this.) + char const* profileName(); + Boolean getFrameParameters(unsigned& frameSize/*bytes*/, double& frameDuration/*microseconds*/); + +protected: + DVVideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean sourceIsSeekable, Boolean leavePresentationTimesUnmodified); + // called only by createNew(), or by subclass constructors + virtual ~DVVideoStreamFramer(); + +protected: + // redefined virtual functions: + virtual Boolean isDVVideoStreamFramer() const; + virtual void doGetNextFrame(); + +protected: + void getAndDeliverData(); // used to implement "doGetNextFrame()" + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime); + void getProfile(); + +protected: + Boolean fLeavePresentationTimesUnmodified; + void const* fOurProfile; + struct timeval fNextFramePresentationTime; + unsigned char fSavedInitialBlocks[DV_SAVED_INITIAL_BLOCKS_SIZE]; + char fInitialBlocksPresent; + Boolean fSourceIsSeekable; +}; + +#endif diff --git a/includes/live555/liveMedia/DeviceSource.hh b/includes/live555/liveMedia/DeviceSource.hh new file mode 100644 index 0000000..9343b35 --- /dev/null +++ b/includes/live555/liveMedia/DeviceSource.hh @@ -0,0 +1,66 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A template for a MediaSource encapsulating an audio/video input device +// +// NOTE: Sections of this code labeled "%%% TO BE WRITTEN %%%" are incomplete, and needto be written by the programmer +// (depending on the features of the particulardevice). +// C++ header + +#ifndef _DEVICE_SOURCE_HH +#define _DEVICE_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +// The following class can be used to define specific encoder parameters +class LIVEMEDIA_API DeviceParameters { + //%%% TO BE WRITTEN %%% +}; + +class LIVEMEDIA_API DeviceSource: public FramedSource { +public: + static DeviceSource* createNew(UsageEnvironment& env, + DeviceParameters params); + +public: + static EventTriggerId eventTriggerId; + // Note that this is defined here to be a static class variable, because this code is intended to illustrate how to + // encapsulate a *single* device - not a set of devices. + // You can, however, redefine this to be a non-static member variable. + +protected: + DeviceSource(UsageEnvironment& env, DeviceParameters params); + // called only by createNew(), or by subclass constructors + virtual ~DeviceSource(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + //virtual void doStopGettingFrames(); // optional + +private: + static void deliverFrame0(void* clientData); + void deliverFrame(); + +private: + static unsigned referenceCount; // used to count how many instances of this class currently exist + DeviceParameters fParams; +}; + +#endif diff --git a/includes/live555/liveMedia/DigestAuthentication.hh b/includes/live555/liveMedia/DigestAuthentication.hh new file mode 100644 index 0000000..68b7fed --- /dev/null +++ b/includes/live555/liveMedia/DigestAuthentication.hh @@ -0,0 +1,75 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class used for digest authentication. +// C++ header + +#ifndef _DIGEST_AUTHENTICATION_HH +#define _DIGEST_AUTHENTICATION_HH + +#ifndef _BOOLEAN_HH +#include +#endif + +// A class used for digest authentication. +// The "realm", and "nonce" fields are supplied by the server +// (in a "401 Unauthorized" response). +// The "username" and "password" fields are supplied by the client. +class LIVEMEDIA_API Authenticator { +public: + Authenticator(); + Authenticator(char const* username, char const* password, Boolean passwordIsMD5 = False); + // If "passwordIsMD5" is True, then "password" is actually the value computed + // by md5(::) + Authenticator(const Authenticator& orig); + Authenticator& operator=(const Authenticator& rightSide); + Boolean operator<(const Authenticator* rightSide); + virtual ~Authenticator(); + + void reset(); + void setRealmAndNonce(char const* realm, char const* nonce); + void setRealmAndRandomNonce(char const* realm); + // as above, except that the nonce is created randomly. + // (This is used by servers.) + void setUsernameAndPassword(char const* username, char const* password, Boolean passwordIsMD5 = False); + // If "passwordIsMD5" is True, then "password" is actually the value computed + // by md5(::) + + char const* realm() const { return fRealm; } + char const* nonce() const { return fNonce; } + char const* username() const { return fUsername; } + char const* password() const { return fPassword; } + + char const* computeDigestResponse(char const* cmd, char const* url) const; + // The returned string from this function must later be freed by calling: + void reclaimDigestResponse(char const* responseStr) const; + +private: + void resetRealmAndNonce(); + void resetUsernameAndPassword(); + void assignRealmAndNonce(char const* realm, char const* nonce); + void assignUsernameAndPassword(char const* username, char const* password, Boolean passwordIsMD5); + void assign(char const* realm, char const* nonce, + char const* username, char const* password, Boolean passwordIsMD5); + +private: + char* fRealm; char* fNonce; + char* fUsername; char* fPassword; + Boolean fPasswordIsMD5; +}; + +#endif diff --git a/includes/live555/liveMedia/FileServerMediaSubsession.hh b/includes/live555/liveMedia/FileServerMediaSubsession.hh new file mode 100644 index 0000000..8ffecb5 --- /dev/null +++ b/includes/live555/liveMedia/FileServerMediaSubsession.hh @@ -0,0 +1,43 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a file. +// C++ header + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#define _FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif +#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH +#include "OnDemandServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API FileServerMediaSubsession: public OnDemandServerMediaSubsession { +protected: // we're a virtual base class + FileServerMediaSubsession(UsageEnvironment& env, char const* fileName, + Boolean reuseFirstSource); + virtual ~FileServerMediaSubsession(); + +protected: + char const* fFileName; + u_int64_t fFileSize; // if known +}; + +#endif diff --git a/includes/live555/liveMedia/FileSink.hh b/includes/live555/liveMedia/FileSink.hh new file mode 100644 index 0000000..97bdba2 --- /dev/null +++ b/includes/live555/liveMedia/FileSink.hh @@ -0,0 +1,71 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// File Sinks +// C++ header + +#ifndef _FILE_SINK_HH +#define _FILE_SINK_HH + +#ifndef _MEDIA_SINK_HH +#include "MediaSink.hh" +#endif + +class LIVEMEDIA_API FileSink: public MediaSink { +public: + static FileSink* createNew(UsageEnvironment& env, char const* fileName, + unsigned bufferSize = 20000, + Boolean oneFilePerFrame = False); + // "bufferSize" should be at least as large as the largest expected + // input frame. + // "oneFilePerFrame" - if True - specifies that each input frame will + // be written to a separate file (using the presentation time as a + // file name suffix). The default behavior ("oneFilePerFrame" == False) + // is to output all incoming data into a single file. + + virtual void addData(unsigned char const* data, unsigned dataSize, + struct timeval presentationTime); + // (Available in case a client wants to add extra data to the output file) + +protected: + FileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, + char const* perFrameFileNamePrefix); + // called only by createNew() + virtual ~FileSink(); + +protected: // redefined virtual functions: + virtual Boolean continuePlaying(); + +protected: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + virtual void afterGettingFrame(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime); + + FILE* fOutFid; + unsigned char* fBuffer; + unsigned fBufferSize; + char* fPerFrameFileNamePrefix; // used if "oneFilePerFrame" is True + char* fPerFrameFileNameBuffer; // used if "oneFilePerFrame" is True + struct timeval fPrevPresentationTime; + unsigned fSamePresentationTimeCounter; +}; + +#endif diff --git a/includes/live555/liveMedia/FramedFileSource.hh b/includes/live555/liveMedia/FramedFileSource.hh new file mode 100644 index 0000000..5c78ab5 --- /dev/null +++ b/includes/live555/liveMedia/FramedFileSource.hh @@ -0,0 +1,37 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Framed File Sources +// C++ header + +#ifndef _FRAMED_FILE_SOURCE_HH +#define _FRAMED_FILE_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API FramedFileSource: public FramedSource { +protected: + FramedFileSource(UsageEnvironment& env, FILE* fid); // abstract base class + virtual ~FramedFileSource(); + +protected: + FILE* fFid; +}; + +#endif diff --git a/includes/live555/liveMedia/FramedFilter.hh b/includes/live555/liveMedia/FramedFilter.hh new file mode 100644 index 0000000..eda194a --- /dev/null +++ b/includes/live555/liveMedia/FramedFilter.hh @@ -0,0 +1,52 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Framed Filters +// C++ header + +#ifndef _FRAMED_FILTER_HH +#define _FRAMED_FILTER_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API FramedFilter: public FramedSource { +public: + FramedSource* inputSource() const { return fInputSource; } + + void reassignInputSource(FramedSource* newInputSource) { fInputSource = newInputSource; } + + // Call before destruction if you want to prevent the destructor from closing the input source + void detachInputSource(); + +protected: + FramedFilter(UsageEnvironment& env, FramedSource* inputSource); + // abstract base class + virtual ~FramedFilter(); + +protected: + // Redefined virtual functions (with default 'null' implementations): + virtual char const* MIMEtype() const; + virtual void getAttributes() const; + virtual void doStopGettingFrames(); + +protected: + FramedSource* fInputSource; +}; + +#endif diff --git a/includes/live555/liveMedia/FramedSource.hh b/includes/live555/liveMedia/FramedSource.hh new file mode 100644 index 0000000..8c89169 --- /dev/null +++ b/includes/live555/liveMedia/FramedSource.hh @@ -0,0 +1,95 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Framed Sources +// C++ header + +#ifndef _FRAMED_SOURCE_HH +#define _FRAMED_SOURCE_HH + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif +#ifndef _MEDIA_SOURCE_HH +#include "MediaSource.hh" +#endif + +class LIVEMEDIA_API FramedSource: public MediaSource { +public: + static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, + FramedSource*& resultSource); + + typedef void (afterGettingFunc)(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + typedef void (onCloseFunc)(void* clientData); + void getNextFrame(unsigned char* to, unsigned maxSize, + afterGettingFunc* afterGettingFunc, + void* afterGettingClientData, + onCloseFunc* onCloseFunc, + void* onCloseClientData); + + static void handleClosure(void* clientData); + void handleClosure(); + // This should be called (on ourself) if the source is discovered + // to be closed (i.e., no longer readable) + + void stopGettingFrames(); + + virtual unsigned maxFrameSize() const; + // size of the largest possible frame that we may serve, or 0 + // if no such maximum is known (default) + + virtual void doGetNextFrame() = 0; + // called by getNextFrame() + + Boolean isCurrentlyAwaitingData() const {return fIsCurrentlyAwaitingData;} + + static void afterGetting(FramedSource* source); + // doGetNextFrame() should arrange for this to be called after the + // frame has been read (*iff* it is read successfully) + +protected: + FramedSource(UsageEnvironment& env); // abstract base class + virtual ~FramedSource(); + + virtual void doStopGettingFrames(); + +protected: + // The following variables are typically accessed/set by doGetNextFrame() + unsigned char* fTo; // in + unsigned fMaxSize; // in + unsigned fFrameSize; // out + unsigned fNumTruncatedBytes; // out + struct timeval fPresentationTime; // out + unsigned fDurationInMicroseconds; // out + +private: + // redefined virtual functions: + virtual Boolean isFramedSource() const; + +private: + afterGettingFunc* fAfterGettingFunc; + void* fAfterGettingClientData; + onCloseFunc* fOnCloseFunc; + void* fOnCloseClientData; + + Boolean fIsCurrentlyAwaitingData; +}; + +#endif diff --git a/includes/live555/liveMedia/GSMAudioRTPSink.hh b/includes/live555/liveMedia/GSMAudioRTPSink.hh new file mode 100644 index 0000000..0dac23d --- /dev/null +++ b/includes/live555/liveMedia/GSMAudioRTPSink.hh @@ -0,0 +1,44 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for GSM audio +// C++ header + +#ifndef _GSM_AUDIO_RTP_SINK_HH +#define _GSM_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API GSMAudioRTPSink: public AudioRTPSink { +public: + static GSMAudioRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); + +protected: + GSMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs); + // called only by createNew() + + virtual ~GSMAudioRTPSink(); + +private: // redefined virtual functions: + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; +}; + +#endif diff --git a/includes/live555/liveMedia/GenericMediaServer.hh b/includes/live555/liveMedia/GenericMediaServer.hh new file mode 100644 index 0000000..bfd83ff --- /dev/null +++ b/includes/live555/liveMedia/GenericMediaServer.hh @@ -0,0 +1,224 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic media server class, used to implement a RTSP server, and any other server that uses +// "ServerMediaSession" objects to describe media to be served. +// C++ header + +#ifndef _GENERIC_MEDIA_SERVER_HH +#define _GENERIC_MEDIA_SERVER_HH + +#ifndef _MEDIA_HH +#include "Media.hh" +#endif +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif + +#ifndef REQUEST_BUFFER_SIZE +#define REQUEST_BUFFER_SIZE 20000 // for incoming requests +#endif +#ifndef RESPONSE_BUFFER_SIZE +#define RESPONSE_BUFFER_SIZE 20000 +#endif + +// Typedef for a handler function that gets called when "lookupServerMediaSession()" +// (defined below) completes: +typedef void lookupServerMediaSessionCompletionFunc(void* clientData, + ServerMediaSession* sessionLookedUp); + +class LIVEMEDIA_API GenericMediaServer: public Medium { +public: + virtual void addServerMediaSession(ServerMediaSession* serverMediaSession); + + virtual void lookupServerMediaSession(char const* streamName, + lookupServerMediaSessionCompletionFunc* completionFunc, + void* completionClientData, + Boolean isFirstLookupInSession = True); + // Note: This is a virtual function, so can be reimplemented by subclasses. + void lookupServerMediaSession(char const* streamName, + void (GenericMediaServer::*memberFunc)(ServerMediaSession*)); + // Special case of "lookupServerMediaSession()" where the 'completion function' is a + // member function of "GenericMediaServer" (and the 'completion client data' is "this".) + + void removeServerMediaSession(ServerMediaSession* serverMediaSession); + // Removes the "ServerMediaSession" object from our lookup table, so it will no longer be accessible by new clients. + // (However, any *existing* client sessions that use this "ServerMediaSession" object will continue streaming. + // The "ServerMediaSession" object will not get deleted until all of these client sessions have closed.) + // (To both delete the "ServerMediaSession" object *and* close all client sessions that use it, + // call "deleteServerMediaSession(serverMediaSession)" instead.) + virtual void removeServerMediaSession(char const* streamName); + // ditto + + void closeAllClientSessionsForServerMediaSession(ServerMediaSession* serverMediaSession); + // Closes (from the server) all client sessions that are currently using this "ServerMediaSession" object. + // Note, however, that the "ServerMediaSession" object remains accessible by new clients. + virtual void closeAllClientSessionsForServerMediaSession(char const* streamName); + // ditto + + void deleteServerMediaSession(ServerMediaSession* serverMediaSession); + // Equivalent to: + // "closeAllClientSessionsForServerMediaSession(serverMediaSession); removeServerMediaSession(serverMediaSession);" + virtual void deleteServerMediaSession(char const* streamName); + // Equivalent to: + // "closeAllClientSessionsForServerMediaSession(streamName); removeServerMediaSession(streamName); + + unsigned numClientSessions() const { return fClientSessions->numEntries(); } + +protected: + GenericMediaServer(UsageEnvironment& env, int ourSocketIPv4, int ourSocketIPv6, Port ourPort, + unsigned reclamationSeconds); + // If "reclamationSeconds" > 0, then the "ClientSession" state for each client will get + // reclaimed if no activity from the client is detected in at least "reclamationSeconds". + // we're an abstract base class + virtual ~GenericMediaServer(); + void cleanup(); // MUST be called in the destructor of any subclass of us + + static int setUpOurSocket(UsageEnvironment& env, Port& ourPort, int domain); + + static void incomingConnectionHandlerIPv4(void*, int /*mask*/); + static void incomingConnectionHandlerIPv6(void*, int /*mask*/); + void incomingConnectionHandlerIPv4(); + void incomingConnectionHandlerIPv6(); + void incomingConnectionHandlerOnSocket(int serverSocket); + + void setTLSFileNames(char const* certFileName, char const* privKeyFileName); + +public: // should be protected, but some old compilers complain otherwise + // The state of a TCP connection used by a client: + class ClientConnection { + protected: + ClientConnection(GenericMediaServer& ourServer, + int clientSocket, struct sockaddr_storage const& clientAddr, + Boolean useTLS); + virtual ~ClientConnection(); + + UsageEnvironment& envir() { return fOurServer.envir(); } + void closeSockets(); + + static void incomingRequestHandler(void*, int /*mask*/); + void incomingRequestHandler(); + virtual void handleRequestBytes(int newBytesRead) = 0; + void resetRequestBuffer(); + + protected: + friend class GenericMediaServer; + friend class ClientSession; + friend class RTSPServer; // needed to make some broken Windows compilers work; remove this in the future when we end support for Windows + GenericMediaServer& fOurServer; + int fOurSocket; + struct sockaddr_storage fClientAddr; + unsigned char fRequestBuffer[REQUEST_BUFFER_SIZE]; + unsigned char fResponseBuffer[RESPONSE_BUFFER_SIZE]; + unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft; + + // Optional support for TLS: + ServerTLSState fTLS; + ServerTLSState* fInputTLS; // by default, just points to "fTLS", but subclasses may change + ServerTLSState* fOutputTLS; // ditto + }; + + // The state of an individual client session (using one or more sequential TCP connections) handled by a server: + class LIVEMEDIA_API ClientSession { + protected: + ClientSession(GenericMediaServer& ourServer, u_int32_t sessionId); + virtual ~ClientSession(); + + UsageEnvironment& envir() { return fOurServer.envir(); } + void noteLiveness(); + static void noteClientLiveness(ClientSession* clientSession); + static void livenessTimeoutTask(ClientSession* clientSession); + + protected: + friend class GenericMediaServer; + friend class ClientConnection; + GenericMediaServer& fOurServer; + u_int32_t fOurSessionId; + ServerMediaSession* fOurServerMediaSession; + TaskToken fLivenessCheckTask; + }; + +protected: + virtual ClientConnection* createNewClientConnection(int clientSocket, struct sockaddr_storage const& clientAddr) = 0; + virtual ClientSession* createNewClientSession(u_int32_t sessionId) = 0; + + ClientSession* createNewClientSessionWithId(); + // Generates a new (unused) random session id, and calls the "createNewClientSession()" + // virtual function with this session id as parameter. + + // Lookup a "ClientSession" object by sessionId (integer, and string): + ClientSession* lookupClientSession(u_int32_t sessionId); + ClientSession* lookupClientSession(char const* sessionIdStr); + + // An iterator over our "ServerMediaSession" objects: + class ServerMediaSessionIterator { + public: + ServerMediaSessionIterator(GenericMediaServer& server); + virtual ~ServerMediaSessionIterator(); + ServerMediaSession* next(); + private: + HashTable::Iterator* fOurIterator; + }; + + // The basic, synchronous "ServerMediaSession" lookup operation; only for subclasses: + ServerMediaSession* getServerMediaSession(char const* streamName); + +protected: + friend class ClientConnection; + friend class ClientSession; + friend class ServerMediaSessionIterator; + int fServerSocketIPv4, fServerSocketIPv6; + Port fServerPort; + unsigned fReclamationSeconds; + HashTable* fServerMediaSessions; // maps 'stream name' strings to "ServerMediaSession" objects + HashTable* fClientConnections; // the "ClientConnection" objects that we're using + HashTable* fClientSessions; // maps 'session id' strings to "ClientSession" objects + +private: + u_int32_t fPreviousClientSessionId; + + char const* fTLSCertificateFileName; + char const* fTLSPrivateKeyFileName; +}; + +// A data structure used for optional user/password authentication: + +class LIVEMEDIA_API UserAuthenticationDatabase { +public: + UserAuthenticationDatabase(char const* realm = NULL, + Boolean passwordsAreMD5 = False); + // If "passwordsAreMD5" is True, then each password stored into, or removed from, + // the database is actually the value computed + // by md5(::) + virtual ~UserAuthenticationDatabase(); + + virtual void addUserRecord(char const* username, char const* password); + virtual void removeUserRecord(char const* username); + + virtual char const* lookupPassword(char const* username); + // returns NULL if the user name was not present + + char const* realm() { return fRealm; } + Boolean passwordsAreMD5() { return fPasswordsAreMD5; } + +protected: + HashTable* fTable; + char* fRealm; + Boolean fPasswordsAreMD5; +}; + +#endif diff --git a/includes/live555/liveMedia/H261VideoRTPSource.hh b/includes/live555/liveMedia/H261VideoRTPSource.hh new file mode 100644 index 0000000..5dff372 --- /dev/null +++ b/includes/live555/liveMedia/H261VideoRTPSource.hh @@ -0,0 +1,56 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.261 Video RTP Sources +// C++ header + +#ifndef _H261_VIDEO_RTP_SOURCE_HH +#define _H261_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API H261VideoRTPSource: public MultiFramedRTPSource { +public: + static H261VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat = 31, + unsigned rtpTimestampFrequency = 90000); + + u_int32_t lastSpecialHeader() const {return fLastSpecialHeader;} + +protected: + virtual ~H261VideoRTPSource(); + +private: + H261VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + u_int32_t fLastSpecialHeader; +}; + +#endif diff --git a/includes/live555/liveMedia/H263plusVideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/H263plusVideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..3a942f9 --- /dev/null +++ b/includes/live555/liveMedia/H263plusVideoFileServerMediaSubsession.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a H.263 video file. +// C++ header + +#ifndef _H263PLUS_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _H263PLUS_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API H263plusVideoFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static H263plusVideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + +private: + H263plusVideoFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~H263plusVideoFileServerMediaSubsession(); + +private: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); +}; + +#endif diff --git a/includes/live555/liveMedia/H263plusVideoRTPSink.hh b/includes/live555/liveMedia/H263plusVideoRTPSink.hh new file mode 100644 index 0000000..e507949 --- /dev/null +++ b/includes/live555/liveMedia/H263plusVideoRTPSink.hh @@ -0,0 +1,54 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for H.263+ video (RFC 4629) +// C++ header + +#ifndef _H263_PLUS_VIDEO_RTP_SINK_HH +#define _H263_PLUS_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API H263plusVideoRTPSink: public VideoRTPSink { +public: + static H263plusVideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + u_int32_t rtpTimestampFrequency = 90000); + +protected: + H263plusVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + u_int32_t rtpTimestampFrequency); + // called only by createNew() + + virtual ~H263plusVideoRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/H263plusVideoRTPSource.hh b/includes/live555/liveMedia/H263plusVideoRTPSource.hh new file mode 100644 index 0000000..52a0805 --- /dev/null +++ b/includes/live555/liveMedia/H263plusVideoRTPSource.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-2024 Live Networks, Inc. All rights reserved. +// H.263+ Video RTP Sources +// C++ header + +#ifndef _H263_PLUS_VIDEO_RTP_SOURCE_HH +#define _H263_PLUS_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +#define SPECIAL_HEADER_BUFFER_SIZE 1000 + +class LIVEMEDIA_API H263plusVideoRTPSource: public MultiFramedRTPSource { +public: + static H263plusVideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + + // A data structure that stores copies of the special header bytes + // from the most recent frame's RTP packets: + unsigned char fNumSpecialHeaders; + unsigned fSpecialHeaderBytesLength; + unsigned char fSpecialHeaderBytes[SPECIAL_HEADER_BUFFER_SIZE]; + unsigned fPacketSizes[256]; + +protected: + virtual ~H263plusVideoRTPSource(); + +private: + H263plusVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/H263plusVideoStreamFramer.hh b/includes/live555/liveMedia/H263plusVideoStreamFramer.hh new file mode 100644 index 0000000..67efc08 --- /dev/null +++ b/includes/live555/liveMedia/H263plusVideoStreamFramer.hh @@ -0,0 +1,64 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an H263 video elementary stream into frames. +// Author Benhard Feiten + +#ifndef _H263PLUS_VIDEO_STREAM_FRAMER_HH +#define _H263PLUS_VIDEO_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + + +class LIVEMEDIA_API H263plusVideoStreamFramer: public FramedFilter { +public: + + static H263plusVideoStreamFramer* createNew(UsageEnvironment& env, FramedSource* inputSource); + + Boolean& pictureEndMarker() { return fPictureEndMarker; } // a hack for implementing the RTP 'M' bit + +protected: + // Constructor called only by createNew(), or by subclass constructors + H263plusVideoStreamFramer(UsageEnvironment& env, + FramedSource* inputSource, + Boolean createParser = True); + virtual ~H263plusVideoStreamFramer(); + + +public: + static void continueReadProcessing(void* clientData, + unsigned char* ptr, unsigned size, + struct timeval presentationTime); + void continueReadProcessing(); + +private: + virtual void doGetNextFrame(); + virtual Boolean isH263plusVideoStreamFramer() const; + +protected: + double fFrameRate; + unsigned fPictureCount; // hack used to implement doGetNextFrame() ?? + Boolean fPictureEndMarker; + +private: + class H263plusVideoStreamParser* fParser; + struct timeval fPresentationTimeBase; +}; + +#endif diff --git a/includes/live555/liveMedia/H264VideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/H264VideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..874bbfa --- /dev/null +++ b/includes/live555/liveMedia/H264VideoFileServerMediaSubsession.hh @@ -0,0 +1,61 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a H264 Elementary Stream video file. +// C++ header + +#ifndef _H264_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _H264_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API H264VideoFileServerMediaSubsession: public FileServerMediaSubsession { +public: + static H264VideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + + // Used to implement "getAuxSDPLine()": + void checkForAuxSDPLine1(); + void afterPlayingDummy1(); + +protected: + H264VideoFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~H264VideoFileServerMediaSubsession(); + + void setDoneFlag() { fDoneFlag = ~0; } + +protected: // redefined virtual functions + virtual char const* getAuxSDPLine(RTPSink* rtpSink, + FramedSource* inputSource); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + +private: + char* fAuxSDPLine; + char fDoneFlag; // used when setting up "fAuxSDPLine" + RTPSink* fDummyRTPSink; // ditto +}; + +#endif diff --git a/includes/live555/liveMedia/H264VideoFileSink.hh b/includes/live555/liveMedia/H264VideoFileSink.hh new file mode 100644 index 0000000..5e33159 --- /dev/null +++ b/includes/live555/liveMedia/H264VideoFileSink.hh @@ -0,0 +1,47 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.264 Video File Sinks +// C++ header + +#ifndef _H264_VIDEO_FILE_SINK_HH +#define _H264_VIDEO_FILE_SINK_HH + +#ifndef _H264_OR_5_VIDEO_FILE_SINK_HH +#include "H264or5VideoFileSink.hh" +#endif + +class LIVEMEDIA_API H264VideoFileSink: public H264or5VideoFileSink { +public: + static H264VideoFileSink* createNew(UsageEnvironment& env, char const* fileName, + char const* sPropParameterSetsStr = NULL, + // "sPropParameterSetsStr" is an optional 'SDP format' string + // (comma-separated Base64-encoded) representing SPS and/or PPS NAL-units + // to prepend to the output + unsigned bufferSize = 100000, + Boolean oneFilePerFrame = False); + // See "FileSink.hh" for a description of these parameters. + +protected: + H264VideoFileSink(UsageEnvironment& env, FILE* fid, + char const* sPropParameterSetsStr, + unsigned bufferSize, char const* perFrameFileNamePrefix); + // called only by createNew() + virtual ~H264VideoFileSink(); +}; + +#endif diff --git a/includes/live555/liveMedia/H264VideoRTPSink.hh b/includes/live555/liveMedia/H264VideoRTPSink.hh new file mode 100644 index 0000000..77b45a6 --- /dev/null +++ b/includes/live555/liveMedia/H264VideoRTPSink.hh @@ -0,0 +1,59 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for H.264 video (RFC 3984) +// C++ header + +#ifndef _H264_VIDEO_RTP_SINK_HH +#define _H264_VIDEO_RTP_SINK_HH + +#ifndef _H264_OR_5_VIDEO_RTP_SINK_HH +#include "H264or5VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API H264VideoRTPSink: public H264or5VideoRTPSink { +public: + static H264VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + static H264VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int8_t const* sps, unsigned spsSize, u_int8_t const* pps, unsigned ppsSize); + // an optional variant of "createNew()", useful if we know, in advance, + // the stream's SPS and PPS NAL units. + // This avoids us having to 'pre-read' from the input source in order to get these values. + static H264VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + char const* sPropParameterSetsStr); + // an optional variant of "createNew()", useful if we know, in advance, + // the stream's SPS and PPS NAL units. + // This avoids us having to 'pre-read' from the input source in order to get these values. + +protected: + H264VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int8_t const* sps = NULL, unsigned spsSize = 0, + u_int8_t const* pps = NULL, unsigned ppsSize = 0); + // called only by createNew() + virtual ~H264VideoRTPSink(); + +protected: // redefined virtual functions: + virtual char const* auxSDPLine(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); +}; + +#endif diff --git a/includes/live555/liveMedia/H264VideoRTPSource.hh b/includes/live555/liveMedia/H264VideoRTPSource.hh new file mode 100644 index 0000000..9098ed5 --- /dev/null +++ b/includes/live555/liveMedia/H264VideoRTPSource.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.264 Video RTP Sources +// C++ header + +#ifndef _H264_VIDEO_RTP_SOURCE_HH +#define _H264_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API H264VideoRTPSource: public MultiFramedRTPSource { +public: + static H264VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + +protected: + H264VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + + virtual ~H264VideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + friend class H264BufferedPacket; + unsigned char fCurPacketNALUnitType; +}; + +class LIVEMEDIA_API SPropRecord { +public: + ~SPropRecord() { delete[] sPropBytes; } + + unsigned sPropLength; // in bytes + unsigned char* sPropBytes; +}; + +LIVEMEDIA_API SPropRecord* parseSPropParameterSets(char const* sPropParameterSetsStr, + // result parameter: + unsigned& numSPropRecords); + // Returns the binary value of each 'parameter set' specified in a + // "sprop-parameter-sets" string (in the SDP description for a H.264/RTP stream). + // The value is returned as an array (length "numSPropRecords") of "SPropRecord"s. + // This array is dynamically allocated by this routine, and must be delete[]d by the caller. + +#endif diff --git a/includes/live555/liveMedia/H264VideoStreamDiscreteFramer.hh b/includes/live555/liveMedia/H264VideoStreamDiscreteFramer.hh new file mode 100644 index 0000000..97060cb --- /dev/null +++ b/includes/live555/liveMedia/H264VideoStreamDiscreteFramer.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simplified version of "H264VideoStreamFramer" that takes only complete, +// discrete frames (rather than an arbitrary byte stream) as input. +// This avoids the parsing and data copying overhead of the full +// "H264VideoStreamFramer". +// C++ header + +#ifndef _H264_VIDEO_STREAM_DISCRETE_FRAMER_HH +#define _H264_VIDEO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _H264_OR_5_VIDEO_STREAM_DISCRETE_FRAMER_HH +#include "H264or5VideoStreamDiscreteFramer.hh" +#endif + +class LIVEMEDIA_API H264VideoStreamDiscreteFramer: public H264or5VideoStreamDiscreteFramer { +public: + static H264VideoStreamDiscreteFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput = False, Boolean insertAccessUnitDelimiters = False); + +protected: + H264VideoStreamDiscreteFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput, Boolean insertAccessUnitDelimiters); + // called only by createNew() + virtual ~H264VideoStreamDiscreteFramer(); + +private: + // redefined virtual functions: + virtual Boolean isH264VideoStreamFramer() const; +}; + +#endif diff --git a/includes/live555/liveMedia/H264VideoStreamFramer.hh b/includes/live555/liveMedia/H264VideoStreamFramer.hh new file mode 100644 index 0000000..a4eb498 --- /dev/null +++ b/includes/live555/liveMedia/H264VideoStreamFramer.hh @@ -0,0 +1,45 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up a H.264 Video Elementary Stream into NAL units. +// C++ header + +#ifndef _H264_VIDEO_STREAM_FRAMER_HH +#define _H264_VIDEO_STREAM_FRAMER_HH + +#ifndef _H264_OR_5_VIDEO_STREAM_FRAMER_HH +#include "H264or5VideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API H264VideoStreamFramer: public H264or5VideoStreamFramer { +public: + static H264VideoStreamFramer* createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput = False, + Boolean insertAccessUnitDelimiters = False); + +protected: + H264VideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean createParser, + Boolean includeStartCodeInOutput, Boolean insertAccessUnitDelimiters); + // called only by "createNew()" + virtual ~H264VideoStreamFramer(); + + // redefined virtual functions: + virtual Boolean isH264VideoStreamFramer() const; +}; + +#endif diff --git a/includes/live555/liveMedia/H264or5VideoFileSink.hh b/includes/live555/liveMedia/H264or5VideoFileSink.hh new file mode 100644 index 0000000..ab3966f --- /dev/null +++ b/includes/live555/liveMedia/H264or5VideoFileSink.hh @@ -0,0 +1,46 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.264 or H.265 Video File Sinks +// C++ header + +#ifndef _H264_OR_5_VIDEO_FILE_SINK_HH +#define _H264_OR_5_VIDEO_FILE_SINK_HH + +#ifndef _FILE_SINK_HH +#include "FileSink.hh" +#endif + +class LIVEMEDIA_API H264or5VideoFileSink: public FileSink { +protected: + H264or5VideoFileSink(UsageEnvironment& env, FILE* fid, + unsigned bufferSize, char const* perFrameFileNamePrefix, + char const* sPropParameterSetsStr1, + char const* sPropParameterSetsStr2 = NULL, + char const* sPropParameterSetsStr3 = NULL); + // we're an abstract base class + virtual ~H264or5VideoFileSink(); + +protected: // redefined virtual functions: + virtual void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime); + +private: + char const* fSPropParameterSetsStr[3]; + Boolean fHaveWrittenFirstFrame; +}; + +#endif diff --git a/includes/live555/liveMedia/H264or5VideoRTPSink.hh b/includes/live555/liveMedia/H264or5VideoRTPSink.hh new file mode 100644 index 0000000..e9fdf89 --- /dev/null +++ b/includes/live555/liveMedia/H264or5VideoRTPSink.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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for H.264 or H.265 video +// C++ header + +#ifndef _H264_OR_5_VIDEO_RTP_SINK_HH +#define _H264_OR_5_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API H264or5VideoRTPSink: public VideoRTPSink { +protected: + H264or5VideoRTPSink(int hNumber, // 264 or 265 + UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int8_t const* vps = NULL, unsigned vpsSize = 0, + u_int8_t const* sps = NULL, unsigned spsSize = 0, + u_int8_t const* pps = NULL, unsigned ppsSize = 0); + // we're an abstrace base class + virtual ~H264or5VideoRTPSink(); + +private: // redefined virtual functions: + virtual Boolean continuePlaying(); + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + +protected: + int fHNumber; + FramedFilter* fOurFragmenter; + char* fFmtpSDPLine; + u_int8_t* fVPS; unsigned fVPSSize; + u_int8_t* fSPS; unsigned fSPSSize; + u_int8_t* fPPS; unsigned fPPSSize; +}; + +#endif diff --git a/includes/live555/liveMedia/H264or5VideoStreamDiscreteFramer.hh b/includes/live555/liveMedia/H264or5VideoStreamDiscreteFramer.hh new file mode 100644 index 0000000..e417aac --- /dev/null +++ b/includes/live555/liveMedia/H264or5VideoStreamDiscreteFramer.hh @@ -0,0 +1,56 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simplified version of "H264or5VideoStreamFramer" that takes only complete, +// discrete frames (rather than an arbitrary byte stream) as input. +// This avoids the parsing and data copying overhead of the full +// "H264or5VideoStreamFramer". +// C++ header + +#ifndef _H264_OR_5_VIDEO_STREAM_DISCRETE_FRAMER_HH +#define _H264_OR_5_VIDEO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _H264_OR_5_VIDEO_STREAM_FRAMER_HH +#include "H264or5VideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API H264or5VideoStreamDiscreteFramer: public H264or5VideoStreamFramer { +protected: + H264or5VideoStreamDiscreteFramer(int hNumber, UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput, + Boolean insertAccessUnitDelimiters); + // we're an abstract base class + virtual ~H264or5VideoStreamDiscreteFramer(); + +protected: + // redefined virtual functions: + virtual void doGetNextFrame(); + +protected: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + + virtual Boolean nalUnitEndsAccessUnit(u_int8_t nal_unit_type); +}; + +#endif diff --git a/includes/live555/liveMedia/H264or5VideoStreamFramer.hh b/includes/live555/liveMedia/H264or5VideoStreamFramer.hh new file mode 100644 index 0000000..1e249cb --- /dev/null +++ b/includes/live555/liveMedia/H264or5VideoStreamFramer.hh @@ -0,0 +1,92 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up a H.264 or H.265 Video Elementary Stream into NAL units. +// C++ header + +#ifndef _H264_OR_5_VIDEO_STREAM_FRAMER_HH +#define _H264_OR_5_VIDEO_STREAM_FRAMER_HH + +#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH +#include "MPEGVideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API H264or5VideoStreamFramer: public MPEGVideoStreamFramer { +public: + void getVPSandSPSandPPS(u_int8_t*& vps, unsigned& vpsSize, + u_int8_t*& sps, unsigned& spsSize, + u_int8_t*& pps, unsigned& ppsSize) const { + // Returns pointers to copies of the most recently seen VPS (video parameter set) + // SPS (sequence parameter set) and PPS (picture parameter set) NAL units. + // (NULL pointers are returned if the NAL units have not yet been seen.) + vps = fLastSeenVPS; vpsSize = fLastSeenVPSSize; + sps = fLastSeenSPS; spsSize = fLastSeenSPSSize; + pps = fLastSeenPPS; ppsSize = fLastSeenPPSSize; + } + + void setVPSandSPSandPPS(u_int8_t* vps, unsigned vpsSize, + u_int8_t* sps, unsigned spsSize, + u_int8_t* pps, unsigned ppsSize) { + // Assigns copies of the VPS, SPS and PPS NAL units. If this function is not called, + // then these NAL units are assigned only if/when they appear in the input stream. + saveCopyOfVPS(vps, vpsSize); + saveCopyOfSPS(sps, spsSize); + saveCopyOfPPS(pps, ppsSize); + } + +protected: + H264or5VideoStreamFramer(int hNumber, // 264 or 265 + UsageEnvironment& env, FramedSource* inputSource, + Boolean createParser, + Boolean includeStartCodeInOutput, Boolean insertAccessUnitDelimiters); + // We're an abstract base class. + virtual ~H264or5VideoStreamFramer(); + + void saveCopyOfVPS(u_int8_t* from, unsigned size); + void saveCopyOfSPS(u_int8_t* from, unsigned size); + void saveCopyOfPPS(u_int8_t* from, unsigned size); + + void setPresentationTime(); + + Boolean isVPS(u_int8_t nal_unit_type); + Boolean isSPS(u_int8_t nal_unit_type); + Boolean isPPS(u_int8_t nal_unit_type); + Boolean isVCL(u_int8_t nal_unit_type); + +protected: // redefined virtual functions + virtual void doGetNextFrame(); + +protected: + int fHNumber; + Boolean fIncludeStartCodeInOutput, fInsertAccessUnitDelimiters; + u_int8_t* fLastSeenVPS; + unsigned fLastSeenVPSSize; + u_int8_t* fLastSeenSPS; + unsigned fLastSeenSPSSize; + u_int8_t* fLastSeenPPS; + unsigned fLastSeenPPSSize; + struct timeval fNextPresentationTime; // the presentation time to be used for the next NAL unit to be parsed/delivered after this + friend class H264or5VideoStreamParser; // hack +}; + +// A general routine for making a copy of a (H.264 or H.265) NAL unit, +// removing 'emulation' bytes from the copy: +unsigned removeH264or5EmulationBytes(u_int8_t* to, unsigned toMaxSize, + u_int8_t const* from, unsigned fromSize); + // returns the size of the copy; it will be <= min(toMaxSize,fromSize) + +#endif diff --git a/includes/live555/liveMedia/H265VideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/H265VideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..3a3ad11 --- /dev/null +++ b/includes/live555/liveMedia/H265VideoFileServerMediaSubsession.hh @@ -0,0 +1,61 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a H265 Elementary Stream video file. +// C++ header + +#ifndef _H265_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _H265_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API H265VideoFileServerMediaSubsession: public FileServerMediaSubsession { +public: + static H265VideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + + // Used to implement "getAuxSDPLine()": + void checkForAuxSDPLine1(); + void afterPlayingDummy1(); + +protected: + H265VideoFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~H265VideoFileServerMediaSubsession(); + + void setDoneFlag() { fDoneFlag = ~0; } + +protected: // redefined virtual functions + virtual char const* getAuxSDPLine(RTPSink* rtpSink, + FramedSource* inputSource); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + +private: + char* fAuxSDPLine; + char fDoneFlag; // used when setting up "fAuxSDPLine" + RTPSink* fDummyRTPSink; // ditto +}; + +#endif diff --git a/includes/live555/liveMedia/H265VideoFileSink.hh b/includes/live555/liveMedia/H265VideoFileSink.hh new file mode 100644 index 0000000..d065c09 --- /dev/null +++ b/includes/live555/liveMedia/H265VideoFileSink.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.265 Video File Sinks +// C++ header + +#ifndef _H265_VIDEO_FILE_SINK_HH +#define _H265_VIDEO_FILE_SINK_HH + +#ifndef _H264_OR_5_VIDEO_FILE_SINK_HH +#include "H264or5VideoFileSink.hh" +#endif + +class LIVEMEDIA_API H265VideoFileSink: public H264or5VideoFileSink { +public: + static H265VideoFileSink* createNew(UsageEnvironment& env, char const* fileName, + char const* sPropVPSStr = NULL, + char const* sPropSPSStr = NULL, + char const* sPropPPSStr = NULL, + // The "sProp*Str" parameters are optional 'SDP format' strings + // (comma-separated Base64-encoded) representing VPS, SPS, and/or PPS NAL-units + // to prepend to the output + unsigned bufferSize = 100000, + Boolean oneFilePerFrame = False); + // See "FileSink.hh" for a description of these parameters. + +protected: + H265VideoFileSink(UsageEnvironment& env, FILE* fid, + char const* sPropVPSStr, + char const* sPropSPSStr, + char const* sPropPPSStr, + unsigned bufferSize, char const* perFrameFileNamePrefix); + // called only by createNew() + virtual ~H265VideoFileSink(); +}; + +#endif diff --git a/includes/live555/liveMedia/H265VideoRTPSink.hh b/includes/live555/liveMedia/H265VideoRTPSink.hh new file mode 100644 index 0000000..4cc1c0b --- /dev/null +++ b/includes/live555/liveMedia/H265VideoRTPSink.hh @@ -0,0 +1,62 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for H.265 video +// C++ header + +#ifndef _H265_VIDEO_RTP_SINK_HH +#define _H265_VIDEO_RTP_SINK_HH + +#ifndef _H264_OR_5_VIDEO_RTP_SINK_HH +#include "H264or5VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API H265VideoRTPSink: public H264or5VideoRTPSink { +public: + static H265VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + static H265VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int8_t const* vps, unsigned vpsSize, + u_int8_t const* sps, unsigned spsSize, + u_int8_t const* pps, unsigned ppsSize); + // an optional variant of "createNew()", useful if we know, in advance, + // the stream's VPS, SPS and PPS NAL units. + // This avoids us having to 'pre-read' from the input source in order to get these values. + static H265VideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + char const* sPropVPSStr, char const* sPropSPSStr, char const* sPropPPSStr); + // an optional variant of "createNew()", useful if we know, in advance, + // the stream's VPS, SPS and PPS NAL units. + // This avoids us having to 'pre-read' from the input source in order to get these values. + +protected: + H265VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int8_t const* vps = NULL, unsigned vpsSize = 0, + u_int8_t const* sps = NULL, unsigned spsSize = 0, + u_int8_t const* pps = NULL, unsigned ppsSize = 0); + // called only by createNew() + virtual ~H265VideoRTPSink(); + +protected: // redefined virtual functions: + virtual char const* auxSDPLine(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); +}; + +#endif diff --git a/includes/live555/liveMedia/H265VideoRTPSource.hh b/includes/live555/liveMedia/H265VideoRTPSource.hh new file mode 100644 index 0000000..e0c478e --- /dev/null +++ b/includes/live555/liveMedia/H265VideoRTPSource.hh @@ -0,0 +1,67 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// H.265 Video RTP Sources +// C++ header + +#ifndef _H265_VIDEO_RTP_SOURCE_HH +#define _H265_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API H265VideoRTPSource: public MultiFramedRTPSource { +public: + static H265VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + Boolean expectDONFields = False, + unsigned rtpTimestampFrequency = 90000); + // "expectDONFields" is True iff we expect incoming H.265/RTP packets to contain + // DONL and DOND fields. I.e., if "tx-mode == "MST" or sprop-depack-buf-nalus > 0". + + u_int64_t currentNALUnitAbsDon() const { return fCurrentNALUnitAbsDon; } + // the 'absolute decoding order number (AbsDon)' for the most-recently delivered NAL unit + +protected: + H265VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + Boolean expectDONFields, + unsigned rtpTimestampFrequency); + // called only by createNew() + + virtual ~H265VideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + void computeAbsDonFromDON(u_int16_t DON); + +private: + friend class H265BufferedPacket; + Boolean fExpectDONFields; + unsigned char fCurPacketNALUnitType; + u_int16_t fPreviousNALUnitDON; + u_int64_t fCurrentNALUnitAbsDon; +}; + +#endif diff --git a/includes/live555/liveMedia/H265VideoStreamDiscreteFramer.hh b/includes/live555/liveMedia/H265VideoStreamDiscreteFramer.hh new file mode 100644 index 0000000..758c193 --- /dev/null +++ b/includes/live555/liveMedia/H265VideoStreamDiscreteFramer.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simplified version of "H265VideoStreamFramer" that takes only complete, +// discrete frames (rather than an arbitrary byte stream) as input. +// This avoids the parsing and data copying overhead of the full +// "H265VideoStreamFramer". +// C++ header + +#ifndef _H265_VIDEO_STREAM_DISCRETE_FRAMER_HH +#define _H265_VIDEO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _H264_OR_5_VIDEO_STREAM_DISCRETE_FRAMER_HH +#include "H264or5VideoStreamDiscreteFramer.hh" +#endif + +class LIVEMEDIA_API H265VideoStreamDiscreteFramer: public H264or5VideoStreamDiscreteFramer { +public: + static H265VideoStreamDiscreteFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput = False, Boolean insertAccessUnitDelimiters = False); + +protected: + H265VideoStreamDiscreteFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput, Boolean insertAccessUnitDelimiters); + // called only by createNew() + virtual ~H265VideoStreamDiscreteFramer(); + +private: + // redefined virtual functions: + virtual Boolean isH265VideoStreamFramer() const; +}; + +#endif diff --git a/includes/live555/liveMedia/H265VideoStreamFramer.hh b/includes/live555/liveMedia/H265VideoStreamFramer.hh new file mode 100644 index 0000000..c8ba3d3 --- /dev/null +++ b/includes/live555/liveMedia/H265VideoStreamFramer.hh @@ -0,0 +1,45 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up a H.265 Video Elementary Stream into NAL units. +// C++ header + +#ifndef _H265_VIDEO_STREAM_FRAMER_HH +#define _H265_VIDEO_STREAM_FRAMER_HH + +#ifndef _H264_OR_5_VIDEO_STREAM_FRAMER_HH +#include "H264or5VideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API H265VideoStreamFramer: public H264or5VideoStreamFramer { +public: + static H265VideoStreamFramer* createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean includeStartCodeInOutput = False, + Boolean insertAccessUnitDelimiters = False); + +protected: + H265VideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean createParser, + Boolean includeStartCodeInOutput, Boolean insertAccessUnitDelimiters); + // called only by "createNew()" + virtual ~H265VideoStreamFramer(); + + // redefined virtual functions: + virtual Boolean isH265VideoStreamFramer() const; +}; + +#endif diff --git a/includes/live555/liveMedia/HLSSegmenter.hh b/includes/live555/liveMedia/HLSSegmenter.hh new file mode 100644 index 0000000..d6d2be6 --- /dev/null +++ b/includes/live555/liveMedia/HLSSegmenter.hh @@ -0,0 +1,76 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A media sink that takes - as input - a MPEG Transport Stream, and outputs a series +// of MPEG Transport Stream files, each representing a segment of the input stream, +// suitable for HLS (Apple's "HTTP Live Streaming"). +// C++ header + +#ifndef _HLS_SEGMENTER_HH +#define _HLS_SEGMENTER_HH + +#ifndef _MEDIA_SINK_HH +#include "MediaSink.hh" +#endif + +class LIVEMEDIA_API HLSSegmenter: public MediaSink { +public: + typedef void (onEndOfSegmentFunc)(void* clientData, + char const* segmentFileName, double segmentDuration); + static HLSSegmenter* createNew(UsageEnvironment& env, + unsigned segmentationDuration, char const* fileNamePrefix, + onEndOfSegmentFunc* onEndOfSegmentFunc = NULL, + void* onEndOfSegmentClientData = NULL); + +private: + HLSSegmenter(UsageEnvironment& env, unsigned segmentationDuration, char const* fileNamePrefix, + onEndOfSegmentFunc* onEndOfSegmentFunc, void* onEndOfSegmentClientData); + // called only by createNew() + virtual ~HLSSegmenter(); + + static void ourEndOfSegmentHandler(void* clientData, double segmentDuration); + void ourEndOfSegmentHandler(double segmentDuration); + + Boolean openNextOutputSegment(); + + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + virtual void afterGettingFrame(unsigned frameSize, + unsigned numTruncatedBytes); + + static void ourOnSourceClosure(void* clientData); + void ourOnSourceClosure(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + virtual Boolean continuePlaying(); + +private: + unsigned fSegmentationDuration; + char const* fFileNamePrefix; + onEndOfSegmentFunc* fOnEndOfSegmentFunc; + void* fOnEndOfSegmentClientData; + Boolean fHaveConfiguredUpstreamSource; + unsigned fCurrentSegmentCounter; + char* fOutputSegmentFileName; + FILE* fOutFid; + unsigned char* fOutputFileBuffer; +}; + +#endif diff --git a/includes/live555/liveMedia/HMAC_SHA1.hh b/includes/live555/liveMedia/HMAC_SHA1.hh new file mode 100644 index 0000000..b0762e1 --- /dev/null +++ b/includes/live555/liveMedia/HMAC_SHA1.hh @@ -0,0 +1,34 @@ +/********** +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-2024, Live Networks, Inc. All rights reserved +// +// A function for computing the HMAC_SHA1 digest +// Definition + +#ifndef _HMAC_SHA1_HH +#define _HMAC_SHA1_HH + +#ifndef NO_OPENSSL +#ifndef _HMAC_HASH_HH +#include "HMAC_hash.hh" +#endif + +#define SHA1_DIGEST_LEN 20 + +HMAC_hash HMAC_SHA1; +#endif +#endif diff --git a/includes/live555/liveMedia/HMAC_hash.hh b/includes/live555/liveMedia/HMAC_hash.hh new file mode 100644 index 0000000..2e9dc88 --- /dev/null +++ b/includes/live555/liveMedia/HMAC_hash.hh @@ -0,0 +1,37 @@ +/********** +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-2024, Live Networks, Inc. All rights reserved +// +// Generic HMA_HASH functions +// Definition + +#ifndef _HMAC_HASH_HH +#define _HMAC_HASH_HH + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif + +// All HMAC hash functions have the following signature: +typedef void HMAC_hash(u_int8_t const* key, unsigned keyLength, + u_int8_t const* text, unsigned textLength, + u_int8_t* resultDigest); + // "resultDigest" must point to an array of sufficient size to hold the digest + +#define HMAC_BLOCK_SIZE 64 + +#endif diff --git a/includes/live555/liveMedia/InputFile.hh b/includes/live555/liveMedia/InputFile.hh new file mode 100644 index 0000000..454d27d --- /dev/null +++ b/includes/live555/liveMedia/InputFile.hh @@ -0,0 +1,67 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Common routines for opening/closing named input files +// C++ header + +#ifndef _INPUT_FILE_HH +#define _INPUT_FILE_HH + +#include +#include + +#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_WCE)) +#ifndef _WIN32_WCE +// Include header files that might be needed by Windows (in code that uses this header file): +#include +#include +#endif + +#define READ_FROM_FILES_SYNCHRONOUSLY 1 + // Because Windows is a silly toy operating system that doesn't (reliably) treat + // open files as being readable sockets (which can be handled within the default + // "BasicTaskScheduler" event loop, using "select()"), we implement file reading + // in Windows using synchronous, rather than asynchronous, I/O. This can severely + // limit the scalability of servers using this code that run on Windows. + // If this is a problem for you, then either use a better operating system, + // or else write your own Windows-specific event loop ("TaskScheduler" subclass) + // that can handle readable data in Windows open files as an event. +#endif + +#ifndef _WIN32_WCE +#include +#endif + +FILE* OpenInputFile(UsageEnvironment& env, char const* fileName); + +void CloseInputFile(FILE* fid); + +#undef GetFileSize // because some platforms already define this as a macro +u_int64_t GetFileSize(char const* fileName, FILE* fid); + // 0 means zero-length, unbounded, or unknown + +int64_t SeekFile64(FILE *fid, int64_t offset, int whence); + // A platform-independent routine for seeking within (possibly) large files + +int64_t TellFile64(FILE *fid); + // A platform-independent routine for reporting the position within + // (possibly) large files + +Boolean FileIsSeekable(FILE *fid); + // Tests whether "fid" is seekable, by trying to seek within it. + +#endif diff --git a/includes/live555/liveMedia/JPEG2000VideoRTPSink.hh b/includes/live555/liveMedia/JPEG2000VideoRTPSink.hh new file mode 100644 index 0000000..c06c568 --- /dev/null +++ b/includes/live555/liveMedia/JPEG2000VideoRTPSink.hh @@ -0,0 +1,46 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. + + +#ifndef _JPEG2000_VIDEO_RTP_SINK_HH +#define _JPEG2000_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API JPEG2000VideoRTPSink: public VideoRTPSink { +public: + static JPEG2000VideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); + +protected: + JPEG2000VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs); + // called only by createNew() + + virtual ~JPEG2000VideoRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/JPEG2000VideoRTPSource.hh b/includes/live555/liveMedia/JPEG2000VideoRTPSource.hh new file mode 100644 index 0000000..a2c4312 --- /dev/null +++ b/includes/live555/liveMedia/JPEG2000VideoRTPSource.hh @@ -0,0 +1,53 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. + +#ifndef _JPEG2000_VIDEO_RTP_SOURCE_HH +#define _JPEG2000_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API JPEG2000VideoRTPSource: public MultiFramedRTPSource { +public: + static JPEG2000VideoRTPSource* createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* sampling); + +protected: + virtual ~JPEG2000VideoRTPSource(); + +protected: + JPEG2000VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* sampling); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + char* fSampling; +}; + +#endif diff --git a/includes/live555/liveMedia/JPEGVideoRTPSink.hh b/includes/live555/liveMedia/JPEGVideoRTPSink.hh new file mode 100644 index 0000000..acc0917 --- /dev/null +++ b/includes/live555/liveMedia/JPEGVideoRTPSink.hh @@ -0,0 +1,52 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for JPEG video (RFC 2435) +// C++ header + +#ifndef _JPEG_VIDEO_RTP_SINK_HH +#define _JPEG_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API JPEGVideoRTPSink: public VideoRTPSink { +public: + static JPEGVideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); + +protected: + JPEGVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs); + // called only by createNew() + + virtual ~JPEGVideoRTPSink(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/JPEGVideoRTPSource.hh b/includes/live555/liveMedia/JPEGVideoRTPSource.hh new file mode 100644 index 0000000..bf68b7c --- /dev/null +++ b/includes/live555/liveMedia/JPEGVideoRTPSource.hh @@ -0,0 +1,59 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// JPEG Video (RFC 2435) RTP Sources +// C++ header + +#ifndef _JPEG_VIDEO_RTP_SOURCE_HH +#define _JPEG_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +#define MAX_JPEG_HEADER_SIZE 1024 + +class LIVEMEDIA_API JPEGVideoRTPSource: public MultiFramedRTPSource { +public: + static JPEGVideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat = 26, + unsigned rtpPayloadFrequency = 90000, + unsigned defaultWidth = 0, unsigned defaultHeight = 0); + +protected: + virtual ~JPEGVideoRTPSource(); + +private: + JPEGVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + unsigned defaultWidth, unsigned defaultHeight); + // called only by createNew() + + // Image dimensions from the SDP description, if any + unsigned fDefaultWidth, fDefaultHeight; + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/JPEGVideoSource.hh b/includes/live555/liveMedia/JPEGVideoSource.hh new file mode 100644 index 0000000..5c8ec75 --- /dev/null +++ b/includes/live555/liveMedia/JPEGVideoSource.hh @@ -0,0 +1,55 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// JPEG video sources +// C++ header + +#ifndef _JPEG_VIDEO_SOURCE_HH +#define _JPEG_VIDEO_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API JPEGVideoSource: public FramedSource { +public: + virtual u_int8_t type() = 0; + virtual u_int8_t qFactor() = 0; + virtual u_int8_t width() = 0; // # pixels/8 (or 0 for 2048 pixels) + virtual u_int8_t height() = 0; // # pixels/8 (or 0 for 2048 pixels) + + virtual u_int8_t const* quantizationTables(u_int8_t& precision, + u_int16_t& length); + // If "qFactor()" returns a value >= 128, then this function is called + // to tell us the quantization tables that are being used. + // (The default implementation of this function just returns NULL.) + // "precision" and "length" are as defined in RFC 2435, section 3.1.8. + + virtual u_int16_t restartInterval(); + // If restart intervals are being used (i.e., 64 <= type() <= 127), then this function must be + // redefined - by a subclass - to return a non-zero value. + +protected: + JPEGVideoSource(UsageEnvironment& env); // abstract base class + virtual ~JPEGVideoSource(); + +private: + // redefined virtual functions: + virtual Boolean isJPEGVideoSource() const; +}; + +#endif diff --git a/includes/live555/liveMedia/Locale.hh b/includes/live555/liveMedia/Locale.hh new file mode 100644 index 0000000..6d78922 --- /dev/null +++ b/includes/live555/liveMedia/Locale.hh @@ -0,0 +1,75 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Support for temporarily setting the locale (e.g., to "C" or "POSIX") for (e.g.) parsing or printing +// floating-point numbers in protocol headers, or calling toupper()/tolower() on human-input strings. +// C++ header + +#ifndef _LOCALE_HH +#define _LOCALE_HH + +// If you're on a system that (for whatever reason) doesn't have either the "setlocale()" or the "newlocale()" function, then +// add "-DLOCALE_NOT_USED" to your "config.*" file. + +// If you're on a system that (for whatever reason) has "setlocale()" but not "newlocale()", then +// add "-DNEWLOCALE_NOT_USED" to your "config.*" file. +// (Note that -DLOCALE_NOT_USED implies -DNEWLOCALE_NOT_USED; you do not need both.) +// Also, for Windows systems, we define "NEWLOCALE_NOT_USED" by default, because at least some Windows systems +// (or their development environments) don't have "newlocale()". If, however, your Windows system *does* have "newlocale()", +// then you can override this by defining "NEWLOCALE_USED" before #including this file. + +// Finally, some old development environments need a header file "xlocale.h" to use "newlocale()". +// Should you need this header file, add "-DNEED_XLOCALE_H" to your "config.*" file. + +#ifdef NEWLOCALE_USED +#undef LOCALE_NOT_USED +#undef NEWLOCALE_NOT_USED +#else +#if defined(__WIN32__) || defined(_WIN32) +#define NEWLOCALE_NOT_USED 1 +#endif +#endif + +#ifndef LOCALE_NOT_USED +#include +#ifndef NEWLOCALE_NOT_USED +#ifdef NEED_XLOCALE_H +#include +#endif +#endif +#endif + + +enum LocaleCategory { All, Numeric }; // define and implement more categories later, as needed + +class Locale { +public: + Locale(char const* newLocale, LocaleCategory category = All); + virtual ~Locale(); + +private: +#ifndef LOCALE_NOT_USED +#ifndef NEWLOCALE_NOT_USED + locale_t fLocale, fPrevLocale; +#else + int fCategoryNum; + char* fPrevLocale; +#endif +#endif +}; + +#endif diff --git a/includes/live555/liveMedia/MIKEY.hh b/includes/live555/liveMedia/MIKEY.hh new file mode 100644 index 0000000..cbf9434 --- /dev/null +++ b/includes/live555/liveMedia/MIKEY.hh @@ -0,0 +1,75 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A data structure that implements a MIKEY message (RFC 3830) +// C++ header + +#ifndef _MIKEY_HH +#define _MIKEY_HH + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +class LIVEMEDIA_API MIKEYState { +public: + MIKEYState(Boolean useEncryption = True); // initialize with default parameters + virtual ~MIKEYState(); + + static MIKEYState* createNew(u_int8_t const* messageToParse, unsigned messageSize); + // (Attempts to) parse a binary MIKEY message, returning a new "MIKEYState" if successful + // (or NULL if unsuccessful). + + u_int8_t* generateMessage(unsigned& messageSize) const; + // Returns a binary message representing the current MIKEY state, of size "messageSize" bytes. + // This array is dynamically allocated by this routine, and must be delete[]d by the caller. + + // Accessors for the encryption/authentication parameters: + Boolean encryptSRTP() const { return fEncryptSRTP; } + Boolean encryptSRTCP() const { return fEncryptSRTCP; } + u_int8_t const* keyData() const { return fKeyData; } + u_int32_t MKI() const { return fMKI; } + Boolean useAuthentication() const { return fUseAuthentication; } + +private: + MIKEYState(u_int8_t const* messageToParse, unsigned messageSize, Boolean& parsedOK); + // called only by "createNew()" + + void addNewPayload(class MIKEYPayload* newPayload); + Boolean parseHDRPayload(u_int8_t const*& ptr, u_int8_t const* endPtr, u_int8_t& nextPayloadType); + Boolean parseNonHDRPayload(u_int8_t const*& ptr, u_int8_t const* endPtr, u_int8_t& nextPayloadType); + +private: + // Encryption/authentication parameters, either set by default + // (if the first (parameterless) constructor is used), or set by parsing an input message + // (if the second constructor is used): + Boolean fEncryptSRTP; + Boolean fEncryptSRTCP; + u_int8_t fKeyData[16+14]; // encryption key + salt + u_int32_t fMKI; // used only if encryption is used. (We assume a MKI length of 4.) + Boolean fUseAuthentication; + + // Our internal binary representation of the MIKEY payloads: + class MIKEYPayload* fHeaderPayload; + class MIKEYPayload* fTailPayload; + unsigned fTotalPayloadByteCount; +}; + +#endif diff --git a/includes/live555/liveMedia/MP3ADU.hh b/includes/live555/liveMedia/MP3ADU.hh new file mode 100644 index 0000000..5ee81da --- /dev/null +++ b/includes/live555/liveMedia/MP3ADU.hh @@ -0,0 +1,94 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// 'ADU' MP3 streams (for improved loss-tolerance) +// C++ header + +#ifndef _MP3_ADU_HH +#define _MP3_ADU_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API ADUFromMP3Source: public FramedFilter { +public: + static ADUFromMP3Source* createNew(UsageEnvironment& env, + FramedSource* inputSource, + Boolean includeADUdescriptors = True); + + void resetInput(); + // This is called whenever there's a discontinuity in the input MP3 source + // (e.g., due to seeking within the source). It causes any still-unprocessed + // MP3 frame data within our queue to be discarded, so that it does not + // erroneously get used by backpointers from the new MP3 frames. + + Boolean setScaleFactor(int scale); + +protected: + ADUFromMP3Source(UsageEnvironment& env, + FramedSource* inputSource, + Boolean includeADUdescriptors); + // called only by createNew() + virtual ~ADUFromMP3Source(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + virtual char const* MIMEtype() const; + +private: + Boolean doGetNextFrame1(); + +private: + Boolean fAreEnqueueingMP3Frame; + class SegmentQueue* fSegments; + Boolean fIncludeADUdescriptors; + unsigned fTotalDataSizeBeforePreviousRead; + int fScale; + unsigned fFrameCounter; +}; + +class LIVEMEDIA_API MP3FromADUSource: public FramedFilter { +public: + static MP3FromADUSource* createNew(UsageEnvironment& env, + FramedSource* inputSource, + Boolean includeADUdescriptors = True); + +protected: + MP3FromADUSource(UsageEnvironment& env, + FramedSource* inputSource, + Boolean includeADUdescriptors); + // called only by createNew() + virtual ~MP3FromADUSource(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + virtual char const* MIMEtype() const; + +private: + Boolean needToGetAnADU(); + void insertDummyADUsIfNecessary(); + Boolean generateFrameFromHeadADU(); + +private: + Boolean fAreEnqueueingADU; + class SegmentQueue* fSegments; +}; + +#endif diff --git a/includes/live555/liveMedia/MP3ADURTPSink.hh b/includes/live555/liveMedia/MP3ADURTPSink.hh new file mode 100644 index 0000000..1345596 --- /dev/null +++ b/includes/live555/liveMedia/MP3ADURTPSink.hh @@ -0,0 +1,55 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for 'ADUized' MP3 frames ("mpa-robust") +// C++ header + +#ifndef _MP3_ADU_RTP_SINK_HH +#define _MP3_ADU_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API MP3ADURTPSink: public AudioRTPSink { +public: + static MP3ADURTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char RTPPayloadType); + +protected: + virtual ~MP3ADURTPSink(); + +private: + MP3ADURTPSink(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char RTPPayloadType); + // called only by createNew() + + +private: + // Redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned specialHeaderSize() const; + +private: + unsigned fCurADUSize; // used when fragmenting over multiple RTP packets +}; + +#endif diff --git a/includes/live555/liveMedia/MP3ADURTPSource.hh b/includes/live555/liveMedia/MP3ADURTPSource.hh new file mode 100644 index 0000000..b8187f0 --- /dev/null +++ b/includes/live555/liveMedia/MP3ADURTPSource.hh @@ -0,0 +1,49 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP source for 'ADUized' MP3 frames ("mpa-robust") +// C++ header + +#ifndef _MP3_ADU_SOURCE_HH +#define _MP3_ADU_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MP3ADURTPSource: public MultiFramedRTPSource { +public: + static MP3ADURTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + +protected: + virtual ~MP3ADURTPSource(); + +private: + MP3ADURTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MP3ADUTranscoder.hh b/includes/live555/liveMedia/MP3ADUTranscoder.hh new file mode 100644 index 0000000..ca7859b --- /dev/null +++ b/includes/live555/liveMedia/MP3ADUTranscoder.hh @@ -0,0 +1,64 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Transcoder for ADUized MP3 frames +// C++ header + +#ifndef _MP3_ADU_TRANSCODER_HH +#define _MP3_ADU_TRANSCODER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API MP3ADUTranscoder: public FramedFilter { +public: + static MP3ADUTranscoder* createNew(UsageEnvironment& env, + unsigned outBitrate /* in kbps */, + FramedSource* inputSource); + + unsigned outBitrate() const { return fOutBitrate; } +protected: + MP3ADUTranscoder(UsageEnvironment& env, + unsigned outBitrate /* in kbps */, + FramedSource* inputSource); + // called only by createNew() + virtual ~MP3ADUTranscoder(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void getAttributes() const; + +private: + static void afterGettingFrame(void* clientData, + unsigned numBytesRead, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned numBytesRead, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + unsigned fOutBitrate; // in kbps + unsigned fAvailableBytesForBackpointer; + + unsigned char* fOrigADU; + // used to store incoming ADU prior to transcoding +}; + +#endif diff --git a/includes/live555/liveMedia/MP3ADUinterleaving.hh b/includes/live555/liveMedia/MP3ADUinterleaving.hh new file mode 100644 index 0000000..12482cd --- /dev/null +++ b/includes/live555/liveMedia/MP3ADUinterleaving.hh @@ -0,0 +1,129 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Interleaving of MP3 ADUs +// C++ header + +#ifndef _MP3_ADU_INTERLEAVING_HH +#define _MP3_ADU_INTERLEAVING_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +// A data structure used to represent an interleaving +#define MAX_CYCLE_SIZE 256 +class LIVEMEDIA_API Interleaving { +public: + Interleaving(unsigned cycleSize, unsigned char const* cycleArray); + virtual ~Interleaving(); + + unsigned cycleSize() const {return fCycleSize;} + unsigned char lookupInverseCycle(unsigned char index) const { + return fInverseCycle[index]; + } + +private: + unsigned fCycleSize; + unsigned char fInverseCycle[MAX_CYCLE_SIZE]; +}; + +// This class is used only as a base for the following two: + +class LIVEMEDIA_API MP3ADUinterleaverBase: public FramedFilter { +protected: + MP3ADUinterleaverBase(UsageEnvironment& env, + FramedSource* inputSource); + // abstract base class + virtual ~MP3ADUinterleaverBase(); + + static FramedSource* getInputSource(UsageEnvironment& env, + char const* inputSourceName); + static void afterGettingFrame(void* clientData, + unsigned numBytesRead, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + virtual void afterGettingFrame(unsigned numBytesRead, + struct timeval presentationTime, + unsigned durationInMicroseconds) = 0; +}; + +// This class is used to convert an ADU sequence from non-interleaved +// to interleaved form: + +class LIVEMEDIA_API MP3ADUinterleaver: public MP3ADUinterleaverBase { +public: + static MP3ADUinterleaver* createNew(UsageEnvironment& env, + Interleaving const& interleaving, + FramedSource* inputSource); + +protected: + MP3ADUinterleaver(UsageEnvironment& env, + Interleaving const& interleaving, + FramedSource* inputSource); + // called only by createNew() + virtual ~MP3ADUinterleaver(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void afterGettingFrame(unsigned numBytesRead, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + void releaseOutgoingFrame(); + +private: + Interleaving const fInterleaving; + class InterleavingFrames* fFrames; + unsigned char fPositionOfNextIncomingFrame; + unsigned fII, fICC; +}; + +// This class is used to convert an ADU sequence from interleaved +// to non-interleaved form: + +class LIVEMEDIA_API MP3ADUdeinterleaver: public MP3ADUinterleaverBase { +public: + static MP3ADUdeinterleaver* createNew(UsageEnvironment& env, + FramedSource* inputSource); + +protected: + MP3ADUdeinterleaver(UsageEnvironment& env, + FramedSource* inputSource); + // called only by createNew() + virtual ~MP3ADUdeinterleaver(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void afterGettingFrame(unsigned numBytesRead, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + void releaseOutgoingFrame(); + +private: + class DeinterleavingFrames* fFrames; + unsigned fIIlastSeen, fICClastSeen; +}; + +#endif + diff --git a/includes/live555/liveMedia/MP3AudioFileServerMediaSubsession.hh b/includes/live555/liveMedia/MP3AudioFileServerMediaSubsession.hh new file mode 100644 index 0000000..cd8c6a0 --- /dev/null +++ b/includes/live555/liveMedia/MP3AudioFileServerMediaSubsession.hh @@ -0,0 +1,73 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an MP3 audio file. +// (Actually, any MPEG-1 or MPEG-2 audio file should work.) +// C++ header + +#ifndef _MP3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _MP3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif +#ifndef _MP3_ADU_INTERLEAVING_HH +#include "MP3ADUinterleaving.hh" +#endif +#ifndef _MP3_ADU_HH +#include "MP3ADU.hh" +#endif + +class LIVEMEDIA_API MP3AudioFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static MP3AudioFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, + Boolean generateADUs, Interleaving* interleaving); + // Note: "interleaving" is used only if "generateADUs" is True, + // (and a value of NULL means 'no interleaving') + +protected: + MP3AudioFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource, + Boolean generateADUs, + Interleaving* interleaving); + // called only by createNew(); + virtual ~MP3AudioFileServerMediaSubsession(); + + FramedSource* createNewStreamSourceCommon(FramedSource* baseMP3Source, unsigned mp3NumBytes, unsigned& estBitrate); + void getBaseStreams(FramedSource* frontStream, + FramedSource*& sourceMP3Stream, ADUFromMP3Source*& aduStream/*if any*/); + +protected: // redefined virtual functions + virtual void seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual void setStreamSourceScale(FramedSource* inputSource, float scale); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + virtual void testScaleFactor(float& scale); + virtual float duration() const; + +protected: + Boolean fGenerateADUs; + Interleaving* fInterleaving; + float fFileDuration; +}; + +#endif diff --git a/includes/live555/liveMedia/MP3FileSource.hh b/includes/live555/liveMedia/MP3FileSource.hh new file mode 100644 index 0000000..976bc39 --- /dev/null +++ b/includes/live555/liveMedia/MP3FileSource.hh @@ -0,0 +1,71 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MP3 File Sources +// C++ header + +#ifndef _MP3_FILE_SOURCE_HH +#define _MP3_FILE_SOURCE_HH + +#ifndef _FRAMED_FILE_SOURCE_HH +#include "FramedFileSource.hh" +#endif + +class MP3StreamState; // forward + +class LIVEMEDIA_API MP3FileSource: public FramedFileSource { +public: + static MP3FileSource* createNew(UsageEnvironment& env, char const* fileName); + + float filePlayTime() const; + unsigned fileSize() const; + void setPresentationTimeScale(unsigned scale); + void seekWithinFile(double seekNPT, double streamDuration); + // if "streamDuration" is >0.0, then we limit the stream to that duration, before treating it as EOF + +protected: + MP3FileSource(UsageEnvironment& env, FILE* fid); + // called only by createNew() + + virtual ~MP3FileSource(); + +protected: + void assignStream(FILE* fid, unsigned filesize); + Boolean initializeStream(); + + MP3StreamState* streamState() {return fStreamState;} + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual char const* MIMEtype() const; + virtual void getAttributes() const; + +private: + static void fileReadableHandler(MP3FileSource* source, int mask); + +private: + MP3StreamState* fStreamState; + Boolean fFidIsSeekable; + Boolean fHaveStartedReading; + unsigned fHaveBeenInitialized; + struct timeval fFirstFramePresentationTime; // set on stream init + Boolean fLimitNumBytesToStream; + unsigned fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True +}; + +#endif diff --git a/includes/live555/liveMedia/MP3Transcoder.hh b/includes/live555/liveMedia/MP3Transcoder.hh new file mode 100644 index 0000000..de42cc3 --- /dev/null +++ b/includes/live555/liveMedia/MP3Transcoder.hh @@ -0,0 +1,44 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MP3 Transcoder +// C++ header + +#ifndef _MP3_TRANSCODER_HH +#define _MP3_TRANSCODER_HH + +#ifndef _MP3_ADU_HH +#include "MP3ADU.hh" +#endif +#ifndef _MP3_ADU_TRANSCODER_HH +#include "MP3ADUTranscoder.hh" +#endif + +class LIVEMEDIA_API MP3Transcoder: public MP3FromADUSource { +public: + static MP3Transcoder* createNew(UsageEnvironment& env, + unsigned outBitrate /* in kbps */, + FramedSource* inputSource); + +protected: + MP3Transcoder(UsageEnvironment& env, + MP3ADUTranscoder* aduTranscoder); + // called only by createNew() + virtual ~MP3Transcoder(); +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2AudioRTPSink.hh b/includes/live555/liveMedia/MPEG1or2AudioRTPSink.hh new file mode 100644 index 0000000..4d291e3 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2AudioRTPSink.hh @@ -0,0 +1,48 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for MPEG audio (RFC 2250) +// C++ header + +#ifndef _MPEG_1OR2_AUDIO_RTP_SINK_HH +#define _MPEG_1OR2_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API MPEG1or2AudioRTPSink: public AudioRTPSink { +public: + static MPEG1or2AudioRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs); + +protected: + MPEG1or2AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs); + // called only by createNew() + + virtual ~MPEG1or2AudioRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2AudioRTPSource.hh b/includes/live555/liveMedia/MPEG1or2AudioRTPSource.hh new file mode 100644 index 0000000..e9b1e83 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2AudioRTPSource.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MPEG-1 or MPEG-2 Audio RTP Sources +// C++ header + +#ifndef _MPEG_1OR2_AUDIO_RTP_SOURCE_HH +#define _MPEG_1OR2_AUDIO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MPEG1or2AudioRTPSource: public MultiFramedRTPSource { +public: + static MPEG1or2AudioRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat = 14, + unsigned rtpTimestampFrequency = 90000); + +protected: + virtual ~MPEG1or2AudioRTPSource(); + +private: + MPEG1or2AudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2AudioStreamFramer.hh b/includes/live555/liveMedia/MPEG1or2AudioStreamFramer.hh new file mode 100644 index 0000000..1acd253 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2AudioStreamFramer.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an MPEG (1,2) audio elementary stream into frames +// C++ header + +#ifndef _MPEG_1OR2_AUDIO_STREAM_FRAMER_HH +#define _MPEG_1OR2_AUDIO_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API MPEG1or2AudioStreamFramer: public FramedFilter { +public: + static MPEG1or2AudioStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean syncWithInputSource = False); + // If "syncWithInputSource" is True, the stream's presentation time + // will be reset to that of the input source, whenever new data + // is read from it. + + void flushInput(); // called if there is a discontinuity (seeking) in the input + +private: + MPEG1or2AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, + Boolean syncWithInputSource); + // called only by createNew() + virtual ~MPEG1or2AudioStreamFramer(); + + static void continueReadProcessing(void* clientData, + unsigned char* ptr, unsigned size, + struct timeval presentationTime); + void continueReadProcessing(); + + void resetPresentationTime(struct timeval newPresentationTime); + // useful if we're being synced with a separate (e.g., video) stream + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + void reset(); + struct timeval currentFramePlayTime() const; + +private: + Boolean fSyncWithInputSource; + struct timeval fNextFramePresentationTime; + +private: // parsing state + class MPEG1or2AudioStreamParser* fParser; + friend class MPEG1or2AudioStreamParser; // hack +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2Demux.hh b/includes/live555/liveMedia/MPEG1or2Demux.hh new file mode 100644 index 0000000..5ec4cf5 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2Demux.hh @@ -0,0 +1,158 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Demultiplexer for a MPEG 1 or 2 Program Stream +// C++ header + +#ifndef _MPEG_1OR2_DEMUX_HH +#define _MPEG_1OR2_DEMUX_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class MPEG1or2DemuxedElementaryStream; // forward + +typedef void MPEG1or2DemuxOnDeletionFunc(void* objectToNotify, class MPEG1or2Demux* demuxBeingDeleted); + +class LIVEMEDIA_API MPEG1or2Demux: public Medium { +public: + static MPEG1or2Demux* createNew(UsageEnvironment& env, + FramedSource* inputSource, + 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. + + MPEG1or2DemuxedElementaryStream* newElementaryStream(u_int8_t streamIdTag); + + // Specialized versions of the above for audio and video: + MPEG1or2DemuxedElementaryStream* newAudioStream(); + MPEG1or2DemuxedElementaryStream* newVideoStream(); + + // A hack for getting raw, undemuxed PES packets from the Program Stream: + MPEG1or2DemuxedElementaryStream* newRawPESStream(); + + void getNextFrame(u_int8_t streamIdTag, + unsigned char* to, unsigned maxSize, + FramedSource::afterGettingFunc* afterGettingFunc, + void* afterGettingClientData, + FramedSource::onCloseFunc* onCloseFunc, + void* onCloseClientData); + // similar to FramedSource::getNextFrame(), except that it also + // takes a stream id tag as parameter. + + void stopGettingFrames(u_int8_t streamIdTag); + // similar to FramedSource::stopGettingFrames(), except that it also + // takes a stream id tag as parameter. + + static void handleClosure(void* clientData); + // This should be called (on ourself) if the source is discovered + // to be closed (i.e., no longer readable) + + FramedSource* inputSource() const { return fInputSource; } + + class LIVEMEDIA_API SCR { + public: + SCR(); + + u_int8_t highBit; + u_int32_t remainingBits; + u_int16_t extension; + + Boolean isValid; + }; + SCR& lastSeenSCR() { return fLastSeenSCR; } + + unsigned char mpegVersion() const { return fMPEGversion; } + + void flushInput(); // should be called before any 'seek' on the underlying source + +private: + MPEG1or2Demux(UsageEnvironment& env, + FramedSource* inputSource, Boolean reclaimWhenLastESDies, + MPEG1or2DemuxOnDeletionFunc* onDeletionFunc, void* objectToNotify); + // called only by createNew() + virtual ~MPEG1or2Demux(); + + void registerReadInterest(u_int8_t streamIdTag, + unsigned char* to, unsigned maxSize, + FramedSource::afterGettingFunc* afterGettingFunc, + void* afterGettingClientData, + FramedSource::onCloseFunc* onCloseFunc, + void* onCloseClientData); + + Boolean useSavedData(u_int8_t streamIdTag, + unsigned char* to, unsigned maxSize, + FramedSource::afterGettingFunc* afterGettingFunc, + void* afterGettingClientData); + + static void continueReadProcessing(void* clientData, + unsigned char* ptr, unsigned size, + struct timeval presentationTime); + void continueReadProcessing(); + +private: + friend class MPEG1or2DemuxedElementaryStream; + void noteElementaryStreamDeletion(MPEG1or2DemuxedElementaryStream* es); + +private: + FramedSource* fInputSource; + SCR fLastSeenSCR; + unsigned char fMPEGversion; + + unsigned char fNextAudioStreamNumber; + unsigned char fNextVideoStreamNumber; + Boolean fReclaimWhenLastESDies; + unsigned fNumOutstandingESs; + + // A descriptor for each possible stream id tag: + typedef struct OutputDescriptor { + // input parameters + unsigned char* to; unsigned maxSize; + FramedSource::afterGettingFunc* fAfterGettingFunc; + void* afterGettingClientData; + FramedSource::onCloseFunc* fOnCloseFunc; + void* onCloseClientData; + + // output parameters + unsigned frameSize; struct timeval presentationTime; + class SavedData; // forward + SavedData* savedDataHead; + SavedData* savedDataTail; + unsigned savedDataTotalSize; + + // status parameters + Boolean isPotentiallyReadable; + Boolean isCurrentlyActive; + Boolean isCurrentlyAwaitingData; + } OutputDescriptor_t; + OutputDescriptor_t fOutput[256]; + + unsigned fNumPendingReads; + Boolean fHaveUndeliveredData; + + MPEG1or2DemuxOnDeletionFunc* fOnDeletionFunc; + void* fOnDeletionObjectToNotify; + +private: // parsing state + class MPEGProgramStreamParser* fParser; + friend class MPEGProgramStreamParser; // hack +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2DemuxedElementaryStream.hh b/includes/live555/liveMedia/MPEG1or2DemuxedElementaryStream.hh new file mode 100644 index 0000000..4e40dc2 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2DemuxedElementaryStream.hh @@ -0,0 +1,69 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A MPEG 1 or 2 Elementary Stream, demultiplexed from a Program Stream +// C++ header + +#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH +#define _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH + +#ifndef _MPEG_1OR2_DEMUX_HH +#include "MPEG1or2Demux.hh" +#endif + +class LIVEMEDIA_API MPEG1or2DemuxedElementaryStream: public FramedSource { +public: + MPEG1or2Demux::SCR lastSeenSCR() const { return fLastSeenSCR; } + + unsigned char mpegVersion() const { return fMPEGversion; } + + MPEG1or2Demux& sourceDemux() const { return fOurSourceDemux; } + +private: // We are created only by a MPEG1or2Demux (a friend) + MPEG1or2DemuxedElementaryStream(UsageEnvironment& env, + u_int8_t streamIdTag, + MPEG1or2Demux& sourceDemux); + virtual ~MPEG1or2DemuxedElementaryStream(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + virtual char const* MIMEtype() const; + virtual unsigned maxFrameSize() const; + +private: + static void afterGettingFrame(void* clientData, + unsigned frameSize, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + + void afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + u_int8_t fOurStreamIdTag; + MPEG1or2Demux& fOurSourceDemux; + char const* fMIMEtype; + MPEG1or2Demux::SCR fLastSeenSCR; + unsigned char fMPEGversion; + + friend class MPEG1or2Demux; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2DemuxedServerMediaSubsession.hh b/includes/live555/liveMedia/MPEG1or2DemuxedServerMediaSubsession.hh new file mode 100644 index 0000000..8cb0cb7 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2DemuxedServerMediaSubsession.hh @@ -0,0 +1,63 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a MPEG-1 or 2 demuxer. +// C++ header + +#ifndef _MPEG_1OR2_DEMUXED_SERVER_MEDIA_SUBSESSION_HH +#define _MPEG_1OR2_DEMUXED_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH +#include "OnDemandServerMediaSubsession.hh" +#endif +#ifndef _MPEG_1OR2_FILE_SERVER_DEMUX_HH +#include "MPEG1or2FileServerDemux.hh" +#endif + +class LIVEMEDIA_API MPEG1or2DemuxedServerMediaSubsession: public OnDemandServerMediaSubsession{ +public: + static MPEG1or2DemuxedServerMediaSubsession* + createNew(MPEG1or2FileServerDemux& demux, u_int8_t streamIdTag, + Boolean reuseFirstSource, + Boolean iFramesOnly = False, double vshPeriod = 5.0); + // The last two parameters are relevant for video streams only + +private: + MPEG1or2DemuxedServerMediaSubsession(MPEG1or2FileServerDemux& demux, + u_int8_t streamIdTag, Boolean reuseFirstSource, + Boolean iFramesOnly, double vshPeriod); + // called only by createNew(); + virtual ~MPEG1or2DemuxedServerMediaSubsession(); + +private: // redefined virtual functions + virtual void seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + virtual float duration() const; + +private: + MPEG1or2FileServerDemux& fOurDemux; + u_int8_t fStreamIdTag; + Boolean fIFramesOnly; // for video streams + double fVSHPeriod; // for video streams +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2FileServerDemux.hh b/includes/live555/liveMedia/MPEG1or2FileServerDemux.hh new file mode 100644 index 0000000..7f0ab36 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2FileServerDemux.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A server demultiplexer for a MPEG 1 or 2 Program Stream +// C++ header + +#ifndef _MPEG_1OR2_FILE_SERVER_DEMUX_HH +#define _MPEG_1OR2_FILE_SERVER_DEMUX_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif +#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH +#include "MPEG1or2DemuxedElementaryStream.hh" +#endif + +class LIVEMEDIA_API MPEG1or2FileServerDemux: public Medium { +public: + static MPEG1or2FileServerDemux* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + + ServerMediaSubsession* newAudioServerMediaSubsession(); // MPEG-1 or 2 audio + ServerMediaSubsession* newVideoServerMediaSubsession(Boolean iFramesOnly = False, + double vshPeriod = 5.0 + /* how often (in seconds) to inject a Video_Sequence_Header, + if one doesn't already appear in the stream */); + ServerMediaSubsession* newAC3AudioServerMediaSubsession(); // AC-3 audio (from VOB) + + unsigned fileSize() const { return fFileSize; } + float fileDuration() const { return fFileDuration; } + +private: + MPEG1or2FileServerDemux(UsageEnvironment& env, char const* fileName, + Boolean reuseFirstSource); + // called only by createNew(); + virtual ~MPEG1or2FileServerDemux(); + +private: + friend class MPEG1or2DemuxedServerMediaSubsession; + 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; + float fFileDuration; + Boolean fReuseFirstSource; + MPEG1or2Demux* fSession0Demux; + MPEG1or2Demux* fLastCreatedDemux; + unsigned fLastClientSessionId; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2VideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/MPEG1or2VideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..95bbe6b --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2VideoFileServerMediaSubsession.hh @@ -0,0 +1,59 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a MPEG-1 or 2 Elementary Stream video file. +// C++ header + +#ifndef _MPEG_1OR2_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _MPEG_1OR2_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API MPEG1or2VideoFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static MPEG1or2VideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, + Boolean iFramesOnly = False, + double vshPeriod = 5.0 + /* how often (in seconds) to inject a Video_Sequence_Header, + if one doesn't already appear in the stream */); + +private: + MPEG1or2VideoFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, + Boolean reuseFirstSource, + Boolean iFramesOnly, + double vshPeriod); + // called only by createNew(); + virtual ~MPEG1or2VideoFileServerMediaSubsession(); + +private: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + +private: + Boolean fIFramesOnly; + double fVSHPeriod; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2VideoRTPSink.hh b/includes/live555/liveMedia/MPEG1or2VideoRTPSink.hh new file mode 100644 index 0000000..d812e1a --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2VideoRTPSink.hh @@ -0,0 +1,69 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for MPEG video (RFC 2250) +// C++ header + +#ifndef _MPEG_1OR2_VIDEO_RTP_SINK_HH +#define _MPEG_1OR2_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API MPEG1or2VideoRTPSink: public VideoRTPSink { +public: + static MPEG1or2VideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); + +protected: + MPEG1or2VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs); + // called only by createNew() + + virtual ~MPEG1or2VideoRTPSink(); + +private: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean allowFragmentationAfterStart() const; + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; + +private: + // MPEG video-specific state, used to decide how to fill out the + // video-specific header, and when to include multiple 'frames' in a + // single outgoing RTP packet. Eventually we should somehow get this + // state from the source (MPEG1or2VideoStreamFramer) instead, as the source + // already has this info itself. + struct { + unsigned temporal_reference; + unsigned char picture_coding_type; + unsigned char vector_code_bits; // FBV,BFC,FFV,FFC from RFC 2250, sec. 3.4 + } fPictureState; + Boolean fPreviousFrameWasSlice; + // used to implement frameCanAppearAfterPacketStart() + Boolean fSequenceHeaderPresent; + Boolean fPacketBeginsSlice, fPacketEndsSlice; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2VideoRTPSource.hh b/includes/live555/liveMedia/MPEG1or2VideoRTPSource.hh new file mode 100644 index 0000000..a656974 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2VideoRTPSource.hh @@ -0,0 +1,53 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MPEG-1 or MPEG-2 Video RTP Sources +// C++ header + +#ifndef _MPEG_1OR2_VIDEO_RTP_SOURCE_HH +#define _MPEG_1OR2_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MPEG1or2VideoRTPSource: public MultiFramedRTPSource { +public: + static MPEG1or2VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat = 32, + unsigned rtpPayloadFrequency = 90000); + +protected: + virtual ~MPEG1or2VideoRTPSource(); + +private: + MPEG1or2VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual Boolean packetIsUsableInJitterCalculation(unsigned char* packet, + unsigned packetSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2VideoStreamDiscreteFramer.hh b/includes/live555/liveMedia/MPEG1or2VideoStreamDiscreteFramer.hh new file mode 100644 index 0000000..d5b917d --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2VideoStreamDiscreteFramer.hh @@ -0,0 +1,76 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simplified version of "MPEG1or2VideoStreamFramer" that takes only +// complete, discrete frames (rather than an arbitrary byte stream) as input. +// This avoids the parsing and data copying overhead of the full +// "MPEG1or2VideoStreamFramer". +// C++ header + +#ifndef _MPEG1or2_VIDEO_STREAM_DISCRETE_FRAMER_HH +#define _MPEG1or2_VIDEO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _MPEG1or2_VIDEO_STREAM_FRAMER_HH +#include "MPEG1or2VideoStreamFramer.hh" +#endif + +#define VSH_MAX_SIZE 1000 + +class LIVEMEDIA_API MPEG1or2VideoStreamDiscreteFramer: public MPEG1or2VideoStreamFramer { +public: + static MPEG1or2VideoStreamDiscreteFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean iFramesOnly = False, // see MPEG1or2VideoStreamFramer.hh + double vshPeriod = 5.0, // see MPEG1or2VideoStreamFramer.hh + Boolean leavePresentationTimesUnmodified = False); + +protected: + MPEG1or2VideoStreamDiscreteFramer(UsageEnvironment& env, + FramedSource* inputSource, + Boolean iFramesOnly, double vshPeriod, Boolean leavePresentationTimesUnmodified); + // called only by createNew() + virtual ~MPEG1or2VideoStreamDiscreteFramer(); + +protected: + // redefined virtual functions: + virtual void doGetNextFrame(); + +protected: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +protected: + Boolean fLeavePresentationTimesUnmodified; + struct timeval fLastNonBFramePresentationTime; + unsigned fLastNonBFrameTemporal_reference; + + // A saved copy of the most recently seen 'video_sequence_header', + // in case we need to insert it into the stream periodically: + unsigned char fSavedVSHBuffer[VSH_MAX_SIZE]; + unsigned fSavedVSHSize; + double fSavedVSHTimestamp; + Boolean fIFramesOnly; + double fVSHPeriod; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG1or2VideoStreamFramer.hh b/includes/live555/liveMedia/MPEG1or2VideoStreamFramer.hh new file mode 100644 index 0000000..2656e20 --- /dev/null +++ b/includes/live555/liveMedia/MPEG1or2VideoStreamFramer.hh @@ -0,0 +1,56 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an MPEG 1 or 2 video elementary stream into +// frames for: Video_Sequence_Header, GOP_Header, Picture_Header +// C++ header + +#ifndef _MPEG_1OR2_VIDEO_STREAM_FRAMER_HH +#define _MPEG_1OR2_VIDEO_STREAM_FRAMER_HH + +#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH +#include "MPEGVideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API MPEG1or2VideoStreamFramer: public MPEGVideoStreamFramer { +public: + static MPEG1or2VideoStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, + Boolean iFramesOnly = False, + double vshPeriod = 5.0 + /* how often (in seconds) to inject a Video_Sequence_Header, + if one doesn't already appear in the stream */); + +protected: + MPEG1or2VideoStreamFramer(UsageEnvironment& env, + FramedSource* inputSource, + Boolean iFramesOnly, double vshPeriod, + Boolean createParser = True); + // called only by createNew(), or by subclass constructors + virtual ~MPEG1or2VideoStreamFramer(); + +private: + // redefined virtual functions: + virtual Boolean isMPEG1or2VideoStreamFramer() const; + +private: + double getCurrentPTS() const; + + friend class MPEG1or2VideoStreamParser; // hack +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2IndexFromTransportStream.hh b/includes/live555/liveMedia/MPEG2IndexFromTransportStream.hh new file mode 100644 index 0000000..187f208 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2IndexFromTransportStream.hh @@ -0,0 +1,95 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that produces a sequence of I-frame indices from a MPEG-2 Transport Stream +// C++ header + +#ifndef _MPEG2_IFRAME_INDEX_FROM_TRANSPORT_STREAM_HH +#define _MPEG2_IFRAME_INDEX_FROM_TRANSPORT_STREAM_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +#ifndef TRANSPORT_PACKET_SIZE +#define TRANSPORT_PACKET_SIZE 188 +#endif + +#ifndef MAX_PES_PACKET_SIZE +#define MAX_PES_PACKET_SIZE 65536 +#endif + +class IndexRecord; // forward + +class LIVEMEDIA_API MPEG2IFrameIndexFromTransportStream: public FramedFilter { +public: + static MPEG2IFrameIndexFromTransportStream* + createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + MPEG2IFrameIndexFromTransportStream(UsageEnvironment& env, + FramedSource* inputSource); + // called only by createNew() + virtual ~MPEG2IFrameIndexFromTransportStream(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + + static void handleInputClosure(void* clientData); + void handleInputClosure1(); + + void analyzePAT(unsigned char* pkt, unsigned size); + void analyzePMT(unsigned char* pkt, unsigned size); + + Boolean deliverIndexRecord(); + Boolean parseFrame(); + Boolean parseToNextCode(unsigned char& nextCode); + void compactParseBuffer(); + void addToTail(IndexRecord* newIndexRecord); + +private: + Boolean fIsH264; // True iff the video is H.264 (encapsulated in a Transport Stream) + Boolean fIsH265; // True iff the video is H.265 (encapsulated in a Transport Stream) + unsigned long fInputTransportPacketCounter; + unsigned fClosureNumber; + u_int8_t fLastContinuityCounter; + float fFirstPCR, fLastPCR; + Boolean fHaveSeenFirstPCR; + u_int16_t fPMT_PID, fVideo_PID; + // Note: We assume: 1 program per Transport Stream; 1 video stream per program + unsigned char fInputBuffer[TRANSPORT_PACKET_SIZE]; + unsigned char* fParseBuffer; + unsigned fParseBufferSize; + unsigned fParseBufferFrameStart; + unsigned fParseBufferParseEnd; + unsigned fParseBufferDataEnd; + IndexRecord* fHeadIndexRecord; + IndexRecord* fTailIndexRecord; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportFileServerMediaSubsession.hh b/includes/live555/liveMedia/MPEG2TransportFileServerMediaSubsession.hh new file mode 100644 index 0000000..c68a78d --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportFileServerMediaSubsession.hh @@ -0,0 +1,131 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a MPEG-2 Transport Stream file. +// C++ header + +#ifndef _MPEG2_TRANSPORT_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _MPEG2_TRANSPORT_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif +#ifndef _MPEG2_TRANSPORT_STREAM_FRAMER_HH +#include "MPEG2TransportStreamFramer.hh" +#endif +#ifndef _BYTE_STREAM_FILE_SOURCE_HH +#include "ByteStreamFileSource.hh" +#endif +#ifndef _MPEG2_TRANSPORT_STREAM_TRICK_MODE_FILTER_HH +#include "MPEG2TransportStreamTrickModeFilter.hh" +#endif +#ifndef _MPEG2_TRANSPORT_STREAM_FROM_ES_SOURCE_HH +#include "MPEG2TransportStreamFromESSource.hh" +#endif + +class ClientTrickPlayState; // forward + +class LIVEMEDIA_API MPEG2TransportFileServerMediaSubsession: public FileServerMediaSubsession { +public: + static MPEG2TransportFileServerMediaSubsession* + createNew(UsageEnvironment& env, + char const* dataFileName, char const* indexFileName, + Boolean reuseFirstSource); + +protected: + MPEG2TransportFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, + MPEG2TransportStreamIndexFile* indexFile, + Boolean reuseFirstSource); + // called only by createNew(); + virtual ~MPEG2TransportFileServerMediaSubsession(); + + virtual ClientTrickPlayState* newClientTrickPlayState(); + +private: // redefined virtual functions + // Note that because - to implement 'trick play' operations - we're operating on + // more than just the input source, we reimplement some functions that are + // already implemented in "OnDemandServerMediaSubsession", rather than + // reimplementing "seekStreamSource()" and "setStreamSourceScale()": + virtual void startStream(unsigned clientSessionId, void* streamToken, + TaskFunc* rtcpRRHandler, + void* rtcpRRHandlerClientData, + unsigned short& rtpSeqNum, + unsigned& rtpTimestamp, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData); + virtual void pauseStream(unsigned clientSessionId, void* streamToken); + virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale); + virtual void deleteStream(unsigned clientSessionId, void*& streamToken); + + // The virtual functions that are usually implemented by "ServerMediaSubsession"s: + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + + virtual void testScaleFactor(float& scale); + virtual float duration() const; + +private: + ClientTrickPlayState* lookupClient(unsigned clientSessionId); + +private: + MPEG2TransportStreamIndexFile* fIndexFile; + float fDuration; + HashTable* fClientSessionHashTable; // indexed by client session id +}; + + +// This class encapsulates the 'trick play' state for each current client (for +// a given "MPEG2TransportFileServerMediaSubsession" - i.e., Transport Stream file). +// It is used only within the implementation of "MPEG2TransportFileServerMediaSubsession", but is included here, +// in case subclasses of "MPEG2TransportFileServerMediaSubsession" want to use it. + +class LIVEMEDIA_API ClientTrickPlayState { +public: + ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile); + + // Functions to bring "fNPT", "fTSRecordNum" and "fIxRecordNum" in sync: + unsigned long updateStateFromNPT(double npt, double seekDuration); + void updateStateOnScaleChange(); + void updateStateOnPlayChange(Boolean reverseToPreviousVSH); + + void handleStreamDeletion(); + void setSource(MPEG2TransportStreamFramer* framer); + + void setNextScale(float nextScale) { fNextScale = nextScale; } + Boolean areChangingScale() const { return fNextScale != fScale; } + +protected: + void updateTSRecordNum(); + void reseekOriginalTransportStreamSource(); + +protected: + MPEG2TransportStreamIndexFile* fIndexFile; + ByteStreamFileSource* fOriginalTransportStreamSource; + MPEG2TransportStreamTrickModeFilter* fTrickModeFilter; + MPEG2TransportStreamFromESSource* fTrickPlaySource; + MPEG2TransportStreamFramer* fFramer; + float fScale, fNextScale, fNPT; + unsigned long fTSRecordNum, fIxRecordNum; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamAccumulator.hh b/includes/live555/liveMedia/MPEG2TransportStreamAccumulator.hh new file mode 100644 index 0000000..659055b --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamAccumulator.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-2024 Live Networks, Inc. All rights reserved. +// Collects a stream of incoming MPEG Transport Stream packets into +// a chunk sufficiently large to send in a single outgoing (RTP or UDP) packet. +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_ACCUMULATOR_HH +#define _MPEG2_TRANSPORT_STREAM_ACCUMULATOR_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportStreamAccumulator: public FramedFilter { +public: + static MPEG2TransportStreamAccumulator* createNew(UsageEnvironment& env, + FramedSource* inputSource, + unsigned maxPacketSize = 1456); + +protected: + MPEG2TransportStreamAccumulator(UsageEnvironment& env, + FramedSource* inputSource, unsigned maxPacketSize); + // called only by createNew() + virtual ~MPEG2TransportStreamAccumulator(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + unsigned const fDesiredPacketSize; + unsigned fNumBytesGathered; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamDemux.hh b/includes/live555/liveMedia/MPEG2TransportStreamDemux.hh new file mode 100644 index 0000000..dabc10f --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamDemux.hh @@ -0,0 +1,50 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Demultiplexer for a MPEG Transport Stream +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_DEMUX_HH +#define _MPEG2_TRANSPORT_STREAM_DEMUX_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportStreamDemux: public Medium { +public: + static MPEG2TransportStreamDemux* createNew(UsageEnvironment& env, + FramedSource* inputSource, + FramedSource::onCloseFunc* onCloseFunc, + void* onCloseClientData); + +private: + MPEG2TransportStreamDemux(UsageEnvironment& env, FramedSource* inputSource, + FramedSource::onCloseFunc* onCloseFunc, void* onCloseClientData); + // called only by createNew() + virtual ~MPEG2TransportStreamDemux(); + + static void handleEndOfFile(void* clientData); + void handleEndOfFile(); + +private: + class MPEG2TransportStreamParser* fParser; + FramedSource::onCloseFunc* fOnCloseFunc; + void* fOnCloseClientData; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamFramer.hh b/includes/live555/liveMedia/MPEG2TransportStreamFramer.hh new file mode 100644 index 0000000..81913b6 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamFramer.hh @@ -0,0 +1,78 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that passes through (unchanged) chunks that contain an integral number +// of MPEG-2 Transport Stream packets, but returning (in "fDurationInMicroseconds") +// an updated estimate of the time gap between chunks. +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_FRAMER_HH +#define _MPEG2_TRANSPORT_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportStreamFramer: public FramedFilter { +public: + static MPEG2TransportStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource); + + u_int64_t tsPacketCount() const { return fTSPacketCount; } + + void changeInputSource(FramedSource* newInputSource) { fInputSource = newInputSource; } + + void clearPIDStatusTable(); + void setNumTSPacketsToStream(unsigned long numTSRecordsToStream); + void setPCRLimit(float pcrLimit); + +protected: + MPEG2TransportStreamFramer(UsageEnvironment& env, FramedSource* inputSource); + // called only by createNew() + virtual ~MPEG2TransportStreamFramer(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + struct timeval presentationTime); + + Boolean updateTSPacketDurationEstimate(unsigned char* pkt, double timeNow); + +private: + u_int64_t fTSPacketCount; + double fTSPacketDurationEstimate; + HashTable* fPIDStatusTable; + u_int64_t fTSPCRCount; + Boolean fLimitNumTSPacketsToStream; + unsigned long fNumTSPacketsToStream; // used iff "fLimitNumTSPacketsToStream" is True + Boolean fLimitTSPacketsToStreamByPCR; + float fPCRLimit; // used iff "fLimitTSPacketsToStreamByPCR" is True +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamFromESSource.hh b/includes/live555/liveMedia/MPEG2TransportStreamFromESSource.hh new file mode 100644 index 0000000..66a9f23 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamFromESSource.hh @@ -0,0 +1,66 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter for converting one or more MPEG Elementary Streams +// to a MPEG-2 Transport Stream +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_FROM_ES_SOURCE_HH +#define _MPEG2_TRANSPORT_STREAM_FROM_ES_SOURCE_HH + +#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH +#include "MPEG2TransportStreamMultiplexor.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportStreamFromESSource: public MPEG2TransportStreamMultiplexor { +public: + static MPEG2TransportStreamFromESSource* createNew(UsageEnvironment& env); + + void addNewVideoSource(FramedSource* inputSource, int mpegVersion, int16_t PID = -1); + // Note: For MPEG-4 video, set "mpegVersion" to 4; for H.264 video, set "mpegVersion" to 5; + // for H.265 video, set "mpegVersion" to 6 + void addNewAudioSource(FramedSource* inputSource, int mpegVersion, int16_t PID = -1); + // Note: For Opus audio, set "mpegVersion" to 3 + + // Note: In these functions, if "PID" is not -1, then it (currently, just the low 8 bits) + // is used as the stream's PID. Otherwise (if "PID" is -1) the 'stream_id' is used as + // the PID. + + static unsigned maxInputESFrameSize; + +protected: + MPEG2TransportStreamFromESSource(UsageEnvironment& env); + // called only by createNew() + virtual ~MPEG2TransportStreamFromESSource(); + + void addNewInputSource(FramedSource* inputSource, + u_int8_t streamId, int mpegVersion, int16_t PID = -1); + // used to implement addNew*Source() above + +private: + // Redefined virtual functions: + virtual void doStopGettingFrames(); + virtual void awaitNewBuffer(unsigned char* oldBuffer); + +private: + friend class InputESSourceRecord; + class InputESSourceRecord* fInputSources; + unsigned fVideoSourceCounter, fAudioSourceCounter; + Boolean fAwaitingBackgroundDelivery; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamFromPESSource.hh b/includes/live555/liveMedia/MPEG2TransportStreamFromPESSource.hh new file mode 100644 index 0000000..2063815 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamFromPESSource.hh @@ -0,0 +1,62 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter for converting a stream of MPEG PES packets to a MPEG-2 Transport Stream +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_FROM_PES_SOURCE_HH +#define _MPEG2_TRANSPORT_STREAM_FROM_PES_SOURCE_HH + +#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH +#include "MPEG2TransportStreamMultiplexor.hh" +#endif +#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH +#include "MPEG1or2DemuxedElementaryStream.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportStreamFromPESSource: public MPEG2TransportStreamMultiplexor { +public: + static MPEG2TransportStreamFromPESSource* + createNew(UsageEnvironment& env, MPEG1or2DemuxedElementaryStream* inputSource); + +protected: + MPEG2TransportStreamFromPESSource(UsageEnvironment& env, + MPEG1or2DemuxedElementaryStream* inputSource); + // called only by createNew() + virtual ~MPEG2TransportStreamFromPESSource(); + +private: + // Redefined virtual functions: + virtual void doStopGettingFrames(); + virtual void awaitNewBuffer(unsigned char* oldBuffer); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + MPEG1or2DemuxedElementaryStream* fInputSource; + unsigned char* fInputBuffer; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamIndexFile.hh b/includes/live555/liveMedia/MPEG2TransportStreamIndexFile.hh new file mode 100644 index 0000000..c5e9640 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamIndexFile.hh @@ -0,0 +1,96 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class that encapsulates MPEG-2 Transport Stream 'index files'/ +// These index files are used to implement 'trick play' operations +// (seek-by-time, fast forward, reverse play) on Transport Stream files. +// +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_INDEX_FILE_HH +#define _MPEG2_TRANSPORT_STREAM_INDEX_FILE_HH + +#ifndef _MEDIA_HH +#include "Media.hh" +#endif + +#define INDEX_RECORD_SIZE 11 + +class LIVEMEDIA_API MPEG2TransportStreamIndexFile: public Medium { +public: + static MPEG2TransportStreamIndexFile* createNew(UsageEnvironment& env, + char const* indexFileName); + + virtual ~MPEG2TransportStreamIndexFile(); + + // Functions that map between a playing time and a Transport packet number + // in the original Transport Stream file: + + void lookupTSPacketNumFromNPT(float& npt, unsigned long& tsPacketNumber, + unsigned long& indexRecordNumber); + // Looks up the Transport Stream Packet number corresponding to "npt". + // (This may modify "npt" to a more exact value.) + // (We also return the index record number that we looked up.) + + void lookupPCRFromTSPacketNum(unsigned long& tsPacketNumber, Boolean reverseToPreviousCleanPoint, + float& pcr, unsigned long& indexRecordNumber); + // Looks up the PCR timestamp for the transport packet "tsPacketNumber". + // (Adjust "tsPacketNumber" only if "reverseToPreviousCleanPoint" is True.) + // (We also return the index record number that we looked up.) + + // Miscellaneous functions used to implement 'trick play': + Boolean readIndexRecordValues(unsigned long indexRecordNum, + unsigned long& transportPacketNum, u_int8_t& offset, + u_int8_t& size, float& pcr, u_int8_t& recordType); + float getPlayingDuration(); + void stopReading() { closeFid(); } + + int mpegVersion(); + // returns the best guess for the version of MPEG being used for data within the underlying Transport Stream file. + // (1,2,4, or 5 (representing H.264). 0 means 'don't know' (usually because the index file is empty)) + +private: + MPEG2TransportStreamIndexFile(UsageEnvironment& env, char const* indexFileName); + + Boolean openFid(); + Boolean seekToIndexRecord(unsigned long indexRecordNumber); + Boolean readIndexRecord(unsigned long indexRecordNum); // into "fBuf" + Boolean readOneIndexRecord(unsigned long indexRecordNum); // closes "fFid" at end + void closeFid(); + + u_int8_t recordTypeFromBuf() { return fBuf[0]; } + u_int8_t offsetFromBuf() { return fBuf[1]; } + u_int8_t sizeFromBuf() { return fBuf[2]; } + float pcrFromBuf(); // after "fBuf" has been read + unsigned long tsPacketNumFromBuf(); + void setMPEGVersionFromRecordType(u_int8_t recordType); + + Boolean rewindToCleanPoint(unsigned long&ixFound); + // used to implement "lookupTSPacketNumber()" + +private: + char* fFileName; + FILE* fFid; // used internally when reading from the file + int fMPEGVersion; + unsigned long fCurrentIndexRecordNum; // within "fFid" + float fCachedPCR; + unsigned long fCachedTSPacketNumber, fCachedIndexRecordNumber; + unsigned long fNumIndexRecords; + unsigned char fBuf[INDEX_RECORD_SIZE]; // used for reading index records from file +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamMultiplexor.hh b/includes/live555/liveMedia/MPEG2TransportStreamMultiplexor.hh new file mode 100644 index 0000000..d086fa8 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamMultiplexor.hh @@ -0,0 +1,120 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class for generating MPEG-2 Transport Stream from one or more input +// Elementary Stream data sources +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH +#define _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif +#ifndef _MPEG_1OR2_DEMUX_HH +#include "MPEG1or2Demux.hh" // for SCR +#endif + +#define PID_TABLE_SIZE 0x2000 // 2^13 + +class LIVEMEDIA_API MPEG2TransportStreamMultiplexor: public FramedSource { +public: + typedef void (onEndOfSegmentFunc)(void* clientData, double segmentDuration); + void setTimedSegmentation(unsigned segmentationDuration, + onEndOfSegmentFunc* onEndOfSegmentFunc = NULL, + void* onEndOfSegmentClientData = NULL); + // Specifies that PAT and PMT packets should be output every "segmentationDuration" seconds. + // (If "segmentationDuration" is 0 (the default value), then PAT and PMT packets are output + // at a preset frequency.) + // The optional function "onEndOfSegmentFunc" is called after each segment is output. + double currentSegmentDuration() const { return fCurrentSegmentDuration; } + // Valid only if "setTimedSegmentation()" was previously called with "segmentationDuration" > 0 + + Boolean canDeliverNewFrameImmediately() const { return fInputBufferBytesUsed < fInputBufferSize; } + // Can be used by a downstream reader to test whether the next call to "doGetNextFrame()" + // will deliver data immediately). + +protected: + MPEG2TransportStreamMultiplexor(UsageEnvironment& env); + virtual ~MPEG2TransportStreamMultiplexor(); + + virtual void awaitNewBuffer(unsigned char* oldBuffer) = 0; + // implemented by subclasses + + void handleNewBuffer(unsigned char* buffer, unsigned bufferSize, + int mpegVersion, MPEG1or2Demux::SCR scr, int16_t PID = -1); + // called by "awaitNewBuffer()" + // Note: For MPEG-4 video, set "mpegVersion" to 4; for H.264 video, set "mpegVersion" to 5; + // for H.265 video, set "mpegVersion" to 6. + // For Opus audio, set "mpegVersion" to 3. + // The buffer is assumed to be a PES packet, with a proper PES header. + // If "PID" is not -1, then it (currently, only the low 8 bits) is used as the stream's PID, + // otherwise the "stream_id" in the PES header is reused to be the stream's PID. + +private: + // Redefined virtual functions: + virtual Boolean isMPEG2TransportStreamMultiplexor() const; + virtual void doGetNextFrame(); + +private: + void deliverDataToClient(u_int16_t pid, unsigned char* buffer, unsigned bufferSize, + unsigned& startPositionInBuffer); + + void deliverPATPacket(); + void deliverPMTPacket(Boolean hasChanged); + + void setProgramStreamMap(unsigned frameSize); + +protected: + Boolean fHaveVideoStreams; + +private: + unsigned fOutgoingPacketCounter; + unsigned fProgramMapVersion; + u_int8_t fPreviousInputProgramMapVersion, fCurrentInputProgramMapVersion; + // These two fields are used if we see "program_stream_map"s in the input. + struct { + unsigned counter; + u_int8_t streamType; // for use in Program Maps + } fPIDState[PID_TABLE_SIZE]; + u_int16_t fPCR_PID, fCurrentPID; // only the low 13 bits are used + MPEG1or2Demux::SCR fPCR; + unsigned char* fInputBuffer; + unsigned fInputBufferSize, fInputBufferBytesUsed; + Boolean fIsFirstAdaptationField; + unsigned fSegmentationDuration; + // if nonzero, this is the number of seconds between successive 'segments'. Each 'segment' + // begins with a PAT, followed by a PMT. + // if zero (the default value), then the frequency of PATs and PMTs depends on the constants + // PAT_PERIOD_IF_UNTIMED and PMT_PERIOD_IF_UNTIMED, defined in the .cpp file. + Boolean segmentationIsTimed() const { return fSegmentationDuration > 0; } + u_int8_t fSegmentationIndication; + // used only if fSegmentationDuration > 0: + // 1 if a segment has just ended and the next packet is to be a PAT + // 2 if a segment has just ended and the following PAT has been sent; a PMT is next + // 0 otherwise + double fCurrentSegmentDuration, fPreviousPTS; // used only if fSegmentationDuration > 0 + onEndOfSegmentFunc* fOnEndOfSegmentFunc; // used only if fSegmentationDuration > 0 + void* fOnEndOfSegmentClientData; // ditto +}; + + +// The CRC calculation function that Transport Streams use. We make this function public +// here in case it's useful elsewhere: +u_int32_t calculateCRC(u_int8_t const* data, unsigned dataLength, u_int32_t initialValue = 0xFFFFFFFF); + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportStreamTrickModeFilter.hh b/includes/live555/liveMedia/MPEG2TransportStreamTrickModeFilter.hh new file mode 100644 index 0000000..95aa5ea --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportStreamTrickModeFilter.hh @@ -0,0 +1,99 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved.// A filter that converts a MPEG Transport Stream file - with corresponding index file +// - to a corresponding Video Elementary Stream. It also uses a "scale" parameter +// to implement 'trick mode' (fast forward or reverse play, using I-frames) on +// the video stream. +// C++ header + +#ifndef _MPEG2_TRANSPORT_STREAM_TRICK_MODE_FILTER_HH +#define _MPEG2_TRANSPORT_STREAM_TRICK_MODE_FILTER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +#ifndef _MPEG2_TRANSPORT_STREAM_INDEX_FILE_HH +#include "MPEG2TransportStreamIndexFile.hh" +#endif + +#ifndef TRANSPORT_PACKET_SIZE +#define TRANSPORT_PACKET_SIZE 188 +#endif + +class LIVEMEDIA_API MPEG2TransportStreamTrickModeFilter: public FramedFilter { +public: + static MPEG2TransportStreamTrickModeFilter* + createNew(UsageEnvironment& env, FramedSource* inputSource, + MPEG2TransportStreamIndexFile* indexFile, int scale); + + Boolean seekTo(unsigned long tsPacketNumber, unsigned long indexRecordNumber); + + unsigned long nextIndexRecordNum() const { return fNextIndexRecordNum; } + + void forgetInputSource() { fInputSource = NULL; } + // this lets us delete this without also deleting the input Transport Stream + +protected: + MPEG2TransportStreamTrickModeFilter(UsageEnvironment& env, FramedSource* inputSource, + MPEG2TransportStreamIndexFile* indexFile, int scale); + // called only by createNew() + virtual ~MPEG2TransportStreamTrickModeFilter(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + void attemptDeliveryToClient(); + void seekToTransportPacket(unsigned long tsPacketNum); + void readTransportPacket(unsigned long tsPacketNum); // asynchronously + + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize); + + static void onSourceClosure(void* clientData); + void onSourceClosure1(); + +private: + Boolean fHaveStarted; + MPEG2TransportStreamIndexFile* fIndexFile; + int fScale; // absolute value + int fDirection; // 1 => forward; -1 => reverse + enum { + SKIPPING_FRAME, + DELIVERING_SAVED_FRAME, + SAVING_AND_DELIVERING_FRAME + } fState; + unsigned fFrameCount; + unsigned long fNextIndexRecordNum; // next to be read from the index file + unsigned long fNextTSPacketNum; // next to be read from the transport stream file + unsigned char fInputBuffer[TRANSPORT_PACKET_SIZE]; + unsigned long fCurrentTSPacketNum; // corresponding to data currently in the buffer + unsigned long fDesiredTSPacketNum; + u_int8_t fDesiredDataOffset, fDesiredDataSize; + float fDesiredDataPCR, fFirstPCR; + unsigned long fSavedFrameIndexRecordStart; + unsigned long fSavedSequentialIndexRecordNum; + Boolean fUseSavedFrameNextTime; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG2TransportUDPServerMediaSubsession.hh b/includes/live555/liveMedia/MPEG2TransportUDPServerMediaSubsession.hh new file mode 100644 index 0000000..a967133 --- /dev/null +++ b/includes/live555/liveMedia/MPEG2TransportUDPServerMediaSubsession.hh @@ -0,0 +1,55 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an incoming UDP (or RTP/UDP) MPEG-2 Transport Stream +// C++ header + +#ifndef _MPEG2_TRANSPORT_UDP_SERVER_MEDIA_SUBSESSION_HH +#define _MPEG2_TRANSPORT_UDP_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH +#include "OnDemandServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API MPEG2TransportUDPServerMediaSubsession: public OnDemandServerMediaSubsession { +public: + static MPEG2TransportUDPServerMediaSubsession* + createNew(UsageEnvironment& env, + char const* inputAddressStr, // An IP multicast address, or use "0.0.0.0" or NULL for unicast input + Port const& inputPort, + Boolean inputStreamIsRawUDP = False); // otherwise (default) the input stream is RTP/UDP +protected: + MPEG2TransportUDPServerMediaSubsession(UsageEnvironment& env, + char const* inputAddressStr, Port const& inputPort, Boolean inputStreamIsRawUDP); + // called only by createNew(); + virtual ~MPEG2TransportUDPServerMediaSubsession(); + +protected: // redefined virtual functions + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); +protected: + char const* fInputAddressStr; + Port fInputPort; + Groupsock* fInputGroupsock; + Boolean fInputStreamIsRawUDP; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4ESVideoRTPSink.hh b/includes/live555/liveMedia/MPEG4ESVideoRTPSink.hh new file mode 100644 index 0000000..6bbbf39 --- /dev/null +++ b/includes/live555/liveMedia/MPEG4ESVideoRTPSink.hh @@ -0,0 +1,72 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for MPEG-4 Elementary Stream video (RFC 3016) +// C++ header + +#ifndef _MPEG4ES_VIDEO_RTP_SINK_HH +#define _MPEG4ES_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API MPEG4ESVideoRTPSink: public VideoRTPSink { +public: + static MPEG4ESVideoRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs, unsigned char rtpPayloadFormat, + u_int32_t rtpTimestampFrequency = 90000); + static MPEG4ESVideoRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs, unsigned char rtpPayloadFormat, u_int32_t rtpTimestampFrequency, + u_int8_t profileAndLevelIndication, char const* configStr); + // an optional variant of "createNew()", useful if we know, in advance, the stream's 'configuration' info. + + +protected: + MPEG4ESVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, u_int32_t rtpTimestampFrequency, + u_int8_t profileAndLevelIndication = 0, char const* configStr = NULL); + // called only by createNew() + + virtual ~MPEG4ESVideoRTPSink(); + +protected: // redefined virtual functions: + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean allowFragmentationAfterStart() const; + virtual Boolean + frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + + virtual char const* auxSDPLine(); + +protected: + Boolean fVOPIsPresent; + +private: + u_int8_t fProfileAndLevelIndication; + unsigned char* fConfigBytes; + unsigned fNumConfigBytes; + + char* fFmtpSDPLine; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4ESVideoRTPSource.hh b/includes/live555/liveMedia/MPEG4ESVideoRTPSource.hh new file mode 100644 index 0000000..4df9a81 --- /dev/null +++ b/includes/live555/liveMedia/MPEG4ESVideoRTPSource.hh @@ -0,0 +1,51 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MP4V-ES video RTP stream sources +// C++ header + +#ifndef _MPEG4_ES_VIDEO_RTP_SOURCE_HH +#define _MPEG4_ES_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MPEG4ESVideoRTPSource: public MultiFramedRTPSource { +public: + static MPEG4ESVideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + +protected: + virtual ~MPEG4ESVideoRTPSource(); + +private: + MPEG4ESVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4GenericRTPSink.hh b/includes/live555/liveMedia/MPEG4GenericRTPSink.hh new file mode 100644 index 0000000..82c821b --- /dev/null +++ b/includes/live555/liveMedia/MPEG4GenericRTPSink.hh @@ -0,0 +1,70 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sinks +// C++ header + +#ifndef _MPEG4_GENERIC_RTP_SINK_HH +#define _MPEG4_GENERIC_RTP_SINK_HH + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#include "MultiFramedRTPSink.hh" +#endif + +class LIVEMEDIA_API MPEG4GenericRTPSink: public MultiFramedRTPSink { +public: + static MPEG4GenericRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, + char const* sdpMediaTypeString, char const* mpeg4Mode, + char const* configString, + unsigned numChannels = 1); + +protected: + MPEG4GenericRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, + u_int32_t rtpTimestampFrequency, + char const* sdpMediaTypeString, + char const* mpeg4Mode, char const* configString, + unsigned numChannels); + // called only by createNew() + + virtual ~MPEG4GenericRTPSink(); + +private: // redefined virtual functions: + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual unsigned specialHeaderSize() const; + + virtual char const* sdpMediaType() const; + + virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line + +private: + char const* fSDPMediaTypeString; + char const* fMPEG4Mode; + char const* fConfigString; + char* fFmtpSDPLine; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4GenericRTPSource.hh b/includes/live555/liveMedia/MPEG4GenericRTPSource.hh new file mode 100644 index 0000000..06b48c5 --- /dev/null +++ b/includes/live555/liveMedia/MPEG4GenericRTPSource.hh @@ -0,0 +1,78 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sources +// C++ header + +#ifndef _MPEG4_GENERIC_RTP_SOURCE_HH +#define _MPEG4_GENERIC_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MPEG4GenericRTPSource: public MultiFramedRTPSource { +public: + static MPEG4GenericRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* mediumName, + char const* mode, unsigned sizeLength, unsigned indexLength, + unsigned indexDeltaLength + // add other parameters later + ); + // mediumName is "audio", "video", or "application" + // it *cannot* be NULL + +protected: + MPEG4GenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* mediumName, + char const* mode, + unsigned sizeLength, unsigned indexLength, + unsigned indexDeltaLength + ); + // called only by createNew(), or by subclass constructors + virtual ~MPEG4GenericRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + char* fMIMEType; + + char* fMode; + unsigned fSizeLength, fIndexLength, fIndexDeltaLength; + unsigned fNumAUHeaders; // in the most recently read packet + unsigned fNextAUHeader; // index of the next AU Header to read + struct AUHeader* fAUHeaders; + + friend class MPEG4GenericBufferedPacket; +}; + + + +// A function that looks up the sampling frequency from an +// "AudioSpecificConfig" string. (0 means 'unknown') +unsigned samplingFrequencyFromAudioSpecificConfig(char const* configStr); + +#endif diff --git a/includes/live555/liveMedia/MPEG4LATMAudioRTPSink.hh b/includes/live555/liveMedia/MPEG4LATMAudioRTPSink.hh new file mode 100644 index 0000000..06c476b --- /dev/null +++ b/includes/live555/liveMedia/MPEG4LATMAudioRTPSink.hh @@ -0,0 +1,69 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for MPEG-4 audio, using LATM multiplexing (RFC 3016) +// (Note that the initial 'size' field is assumed to be present at the start of +// each frame.) +// C++ header + +#ifndef _MPEG4_LATM_AUDIO_RTP_SINK_HH +#define _MPEG4_LATM_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API MPEG4LATMAudioRTPSink: public AudioRTPSink { +public: + static MPEG4LATMAudioRTPSink* createNew(UsageEnvironment& env, + Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + u_int32_t rtpTimestampFrequency, + char const* streamMuxConfigString, + unsigned numChannels, + Boolean allowMultipleFramesPerPacket = False); + +protected: + MPEG4LATMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + u_int32_t rtpTimestampFrequency, + char const* streamMuxConfigString, + unsigned numChannels, + Boolean allowMultipleFramesPerPacket); + // called only by createNew() + + virtual ~MPEG4LATMAudioRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean + frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + + virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line + +private: + char const* fStreamMuxConfigString; + char* fFmtpSDPLine; + Boolean fAllowMultipleFramesPerPacket; +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4LATMAudioRTPSource.hh b/includes/live555/liveMedia/MPEG4LATMAudioRTPSource.hh new file mode 100644 index 0000000..560c31d --- /dev/null +++ b/includes/live555/liveMedia/MPEG4LATMAudioRTPSource.hh @@ -0,0 +1,101 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// MPEG-4 audio, using LATM multiplexing +// C++ header + +#ifndef _MPEG4_LATM_AUDIO_RTP_SOURCE_HH +#define _MPEG4_LATM_AUDIO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API MPEG4LATMAudioRTPSource: public MultiFramedRTPSource { +public: + static MPEG4LATMAudioRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + + // By default, the LATM data length field is included at the beginning of each + // returned frame. To omit this field, call the following: + void omitLATMDataLengthField(); + + Boolean returnedFrameIncludesLATMDataLengthField() const { return fIncludeLATMDataLengthField; } + +protected: + virtual ~MPEG4LATMAudioRTPSource(); + +private: + MPEG4LATMAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + Boolean fIncludeLATMDataLengthField; +}; + + +// A utility for parsing a "StreamMuxConfig" string +LIVEMEDIA_API Boolean +parseStreamMuxConfigStr(char const* configStr, + // result parameters: + Boolean& audioMuxVersion, + Boolean& allStreamsSameTimeFraming, + unsigned char& numSubFrames, + unsigned char& numProgram, + unsigned char& numLayer, + unsigned char*& audioSpecificConfig, + unsigned& audioSpecificConfigSize); + // Parses "configStr" as a sequence of hexadecimal digits, representing + // a "StreamMuxConfig" (as defined in ISO.IEC 14496-3, table 1.21). + // Returns, in "audioSpecificConfig", a binary representation of + // the enclosed "AudioSpecificConfig" structure (of size + // "audioSpecificConfigSize" bytes). The memory for this is allocated + // dynamically by this function; the caller is responsible for + // freeing it. Other values, that precede "AudioSpecificConfig", + // are returned in the other parameters. + // Returns True iff the parsing succeeds. + // IMPORTANT NOTE: The implementation of this function currently assumes + // that everything after the first "numLayer" field is an + // "AudioSpecificConfig". Therefore, it will not work properly if + // "audioMuxVersion" != 0, "numProgram" > 0, or "numLayer" > 0. + // Also, any 'other data' or CRC info will be included at + // the end of "audioSpecificConfig". + +LIVEMEDIA_API unsigned char* parseStreamMuxConfigStr(char const* configStr, + // result parameter: + unsigned& audioSpecificConfigSize); + // A variant of the above that returns just the "AudioSpecificConfig" data + // (or NULL) if the parsing failed, without bothering with the other + // result parameters. + +LIVEMEDIA_API unsigned char* parseGeneralConfigStr(char const* configStr, + // result parameter: + unsigned& configSize); + // A routine that parses an arbitrary config string, returning + // the result in binary form. + +#endif diff --git a/includes/live555/liveMedia/MPEG4VideoFileServerMediaSubsession.hh b/includes/live555/liveMedia/MPEG4VideoFileServerMediaSubsession.hh new file mode 100644 index 0000000..2457993 --- /dev/null +++ b/includes/live555/liveMedia/MPEG4VideoFileServerMediaSubsession.hh @@ -0,0 +1,61 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from a MPEG-4 video file. +// C++ header + +#ifndef _MPEG4_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _MPEG4_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API MPEG4VideoFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static MPEG4VideoFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); + + // Used to implement "getAuxSDPLine()": + void checkForAuxSDPLine1(); + void afterPlayingDummy1(); + +protected: + MPEG4VideoFileServerMediaSubsession(UsageEnvironment& env, + char const* fileName, Boolean reuseFirstSource); + // called only by createNew(); + virtual ~MPEG4VideoFileServerMediaSubsession(); + + void setDoneFlag() { fDoneFlag = ~0; } + +protected: // redefined virtual functions + virtual char const* getAuxSDPLine(RTPSink* rtpSink, + FramedSource* inputSource); + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + +private: + char* fAuxSDPLine; + char fDoneFlag; // used when setting up "fAuxSDPLine" + RTPSink* fDummyRTPSink; // ditto +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4VideoStreamDiscreteFramer.hh b/includes/live555/liveMedia/MPEG4VideoStreamDiscreteFramer.hh new file mode 100644 index 0000000..6b390ab --- /dev/null +++ b/includes/live555/liveMedia/MPEG4VideoStreamDiscreteFramer.hh @@ -0,0 +1,73 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simplified version of "MPEG4VideoStreamFramer" that takes only complete, +// discrete frames (rather than an arbitrary byte stream) as input. +// This avoids the parsing and data copying overhead of the full +// "MPEG4VideoStreamFramer". +// C++ header + +#ifndef _MPEG4_VIDEO_STREAM_DISCRETE_FRAMER_HH +#define _MPEG4_VIDEO_STREAM_DISCRETE_FRAMER_HH + +#ifndef _MPEG4_VIDEO_STREAM_FRAMER_HH +#include "MPEG4VideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API MPEG4VideoStreamDiscreteFramer: public MPEG4VideoStreamFramer { +public: + static MPEG4VideoStreamDiscreteFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource, Boolean leavePresentationTimesUnmodified = False); + +protected: + MPEG4VideoStreamDiscreteFramer(UsageEnvironment& env, + FramedSource* inputSource, Boolean leavePresentationTimesUnmodified); + // called only by createNew() + virtual ~MPEG4VideoStreamDiscreteFramer(); + +protected: + // redefined virtual functions: + virtual void doGetNextFrame(); + +protected: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + + Boolean getNextFrameBit(u_int8_t& result); + Boolean getNextFrameBits(unsigned numBits, u_int32_t& result); + // Which are used by: + void analyzeVOLHeader(); + +protected: + Boolean fLeavePresentationTimesUnmodified; + u_int32_t vop_time_increment_resolution; + unsigned fNumVTIRBits; + // # of bits needed to count to "vop_time_increment_resolution" + struct timeval fLastNonBFramePresentationTime; + unsigned fLastNonBFrameVop_time_increment; + +private: + unsigned fNumBitsSeenSoFar; // used by the getNextFrameBit*() routines +}; + +#endif diff --git a/includes/live555/liveMedia/MPEG4VideoStreamFramer.hh b/includes/live555/liveMedia/MPEG4VideoStreamFramer.hh new file mode 100644 index 0000000..6faac6f --- /dev/null +++ b/includes/live555/liveMedia/MPEG4VideoStreamFramer.hh @@ -0,0 +1,75 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an MPEG-4 video elementary stream into +// frames for: +// - Visual Object Sequence (VS) Header + Visual Object (VO) Header +// + Video Object Layer (VOL) Header +// - Group of VOP (GOV) Header +// - VOP frame +// C++ header + +#ifndef _MPEG4_VIDEO_STREAM_FRAMER_HH +#define _MPEG4_VIDEO_STREAM_FRAMER_HH + +#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH +#include "MPEGVideoStreamFramer.hh" +#endif + +class LIVEMEDIA_API MPEG4VideoStreamFramer: public MPEGVideoStreamFramer { +public: + static MPEG4VideoStreamFramer* + createNew(UsageEnvironment& env, FramedSource* inputSource); + + u_int8_t profile_and_level_indication() const { + return fProfileAndLevelIndication; + } + + unsigned char* getConfigBytes(unsigned& numBytes) const; + + void setConfigInfo(u_int8_t profileAndLevelIndication, char const* configStr); + // Assigns the "profile_and_level_indication" number, and the 'config' bytes. + // If this function is not called, then this data is only assigned later, when it appears in the input stream. + +protected: + MPEG4VideoStreamFramer(UsageEnvironment& env, + FramedSource* inputSource, + Boolean createParser = True); + // called only by createNew(), or by subclass constructors + virtual ~MPEG4VideoStreamFramer(); + + void startNewConfig(); + void appendToNewConfig(unsigned char* newConfigBytes, + unsigned numNewBytes); + void completeNewConfig(); + +private: + // redefined virtual functions: + virtual Boolean isMPEG4VideoStreamFramer() const; + +protected: + u_int8_t fProfileAndLevelIndication; + unsigned char* fConfigBytes; + unsigned fNumConfigBytes; + +private: + unsigned char* fNewConfigBytes; + unsigned fNumNewConfigBytes; + friend class MPEG4VideoStreamParser; // hack +}; + +#endif diff --git a/includes/live555/liveMedia/MPEGVideoStreamFramer.hh b/includes/live555/liveMedia/MPEGVideoStreamFramer.hh new file mode 100644 index 0000000..5187e00 --- /dev/null +++ b/includes/live555/liveMedia/MPEGVideoStreamFramer.hh @@ -0,0 +1,85 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A filter that breaks up an MPEG video elementary stream into +// headers and frames +// C++ header + +#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH +#define _MPEG_VIDEO_STREAM_FRAMER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class LIVEMEDIA_API TimeCode { +public: + TimeCode(); + virtual ~TimeCode(); + + int operator==(TimeCode const& arg2) const; + unsigned days, hours, minutes, seconds, pictures; +}; + +class LIVEMEDIA_API MPEGVideoStreamFramer: public FramedFilter { +public: + Boolean& pictureEndMarker() { return fPictureEndMarker; } + // a hack for implementing the RTP 'M' bit + + void flushInput(); // called if there is a discontinuity (seeking) in the input + +protected: + MPEGVideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource); + // we're an abstract base class + virtual ~MPEGVideoStreamFramer(); + + void computePresentationTime(unsigned numAdditionalPictures); + // sets "fPresentationTime" + void setTimeCode(unsigned hours, unsigned minutes, unsigned seconds, + unsigned pictures, unsigned picturesSinceLastGOP); + +protected: // redefined virtual functions + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + void reset(); + + static void continueReadProcessing(void* clientData, + unsigned char* ptr, unsigned size, + struct timeval presentationTime); + void continueReadProcessing(); + +protected: + double fFrameRate; // Note: For MPEG-4, this is really a 'tick rate' + unsigned fPictureCount; // hack used to implement doGetNextFrame() + Boolean fPictureEndMarker; + struct timeval fPresentationTimeBase; + + // parsing state + class MPEGVideoStreamParser* fParser; + friend class MPEGVideoStreamParser; // hack + +private: + TimeCode fCurGOPTimeCode, fPrevGOPTimeCode; + unsigned fPicturesAdjustment; + double fPictureTimeBase; + unsigned fTcSecsBase; + Boolean fHaveSeenFirstTimeCode; +}; + +#endif diff --git a/includes/live555/liveMedia/MatroskaFile.hh b/includes/live555/liveMedia/MatroskaFile.hh new file mode 100644 index 0000000..4773fc3 --- /dev/null +++ b/includes/live555/liveMedia/MatroskaFile.hh @@ -0,0 +1,218 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class that encapsulates a Matroska file. +// C++ header + +#ifndef _MATROSKA_FILE_HH +#define _MATROSKA_FILE_HH + +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif +#ifndef _FILE_SINK_HH +#include "FileSink.hh" +#endif +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif + +class MatroskaTrack; // forward +class MatroskaDemux; // forward + +typedef void MatroskaDemuxOnDeletionFunc(void* objectToNotify, MatroskaDemux* demuxBeingDeleted); + +class LIVEMEDIA_API MatroskaFile: public Medium { +public: + typedef void (onCreationFunc)(MatroskaFile* newFile, void* clientData); + static void createNew(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData, + char const* preferredLanguage = "eng"); + // Note: Unlike most "createNew()" functions, this one doesn't return a new object immediately. Instead, because this class + // requires file reading (to parse the Matroska 'Track' headers) before a new object can be initialized, the creation of a new + // object is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as a parameter to "createNew()". + + MatroskaTrack* lookup(unsigned trackNumber) const; + + 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 + float segmentDuration() { return fSegmentDuration; } // in units of "timecodeScale()" + float fileDuration(); // in seconds + + char const* fileName() const { return fFileName; } + + unsigned chosenVideoTrackNumber() { return fChosenVideoTrackNumber; } + unsigned chosenAudioTrackNumber() { return fChosenAudioTrackNumber; } + unsigned chosenSubtitleTrackNumber() { return fChosenSubtitleTrackNumber; } + + FramedSource* + createSourceForStreaming(FramedSource* baseSource, unsigned trackNumber, + unsigned& estBitrate, unsigned& numFiltersInFrontOfTrack); + // Takes a data source (which must be a demultiplexed track from this file) and returns + // a (possibly modified) data source that can be used for streaming. + + char const* trackMIMEType(unsigned trackNumber) const; + // in the form "/", or NULL if no such track exists + + RTPSink* createRTPSinkForTrackNumber(unsigned trackNumber, Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic); + // Creates a "RTPSink" object that would be appropriate for streaming the specified track, + // or NULL if no appropriate "RTPSink" exists + + FileSink* createFileSinkForTrackNumber(unsigned trackNumber, char const* fileName); + // Creates a "FileSink" object that would be appropriate for recording the contents of + // the specified track, or NULL if no appropriate "FileSink" exists. + +private: + MatroskaFile(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData, + char const* preferredLanguage); + // called only by createNew() + virtual ~MatroskaFile(); + + static void handleEndOfTrackHeaderParsing(void* clientData); + void handleEndOfTrackHeaderParsing(); + + void addTrack(MatroskaTrack* newTrack, unsigned trackNumber); + void addCuePoint(double cueTime, u_int64_t clusterOffsetInFile, unsigned blockNumWithinCluster); + Boolean lookupCuePoint(double& cueTime, u_int64_t& resultClusterOffsetInFile, unsigned& resultBlockNumWithinCluster); + void printCuePoints(FILE* fid); + + void removeDemux(MatroskaDemux* demux); + + void getH264ConfigData(MatroskaTrack const* track, + u_int8_t*& sps, unsigned& spsSize, + u_int8_t*& pps, unsigned& ppsSize); + // "sps","pps" are dynamically allocated by this function, and must be delete[]d afterwards + void getH265ConfigData(MatroskaTrack const* track, + u_int8_t*& vps, unsigned& vpsSize, + u_int8_t*& sps, unsigned& spsSize, + u_int8_t*& pps, unsigned& ppsSize); + // "vps","sps","pps" are dynamically allocated by this function, and must be delete[]d afterwards + + void getVorbisOrTheoraConfigData(MatroskaTrack const* track, + u_int8_t*& identificationHeader, unsigned& identificationHeaderSize, + u_int8_t*& commentHeader, unsigned& commentHeaderSize, + u_int8_t*& setupHeader, unsigned& setupHeaderSize); + // "identificationHeader", "commentHeader", "setupHeader" are dynamically allocated by this function, and must be delete[]d afterwards + +private: + friend class MatroskaFileParser; + friend class MatroskaDemux; + char const* fFileName; + onCreationFunc* fOnCreation; + void* fOnCreationClientData; + char const* fPreferredLanguage; + + unsigned fTimecodeScale; // in nanoseconds + float fSegmentDuration; // in units of "fTimecodeScale" + u_int64_t fSegmentDataOffset, fClusterOffset, fCuesOffset; + + class MatroskaTrackTable* fTrackTable; + HashTable* fDemuxesTable; + class CuePoint* fCuePoints; + unsigned fChosenVideoTrackNumber, fChosenAudioTrackNumber, fChosenSubtitleTrackNumber; + class MatroskaFileParser* fParserForInitialization; +}; + +// We define our own track type codes as bits (powers of 2), so we can use the set of track types as a bitmap, representing a set: +// (Note that MATROSKA_TRACK_TYPE_OTHER must be last, and have the largest value.) +#define MATROSKA_TRACK_TYPE_VIDEO 0x01 +#define MATROSKA_TRACK_TYPE_AUDIO 0x02 +#define MATROSKA_TRACK_TYPE_SUBTITLE 0x04 +#define MATROSKA_TRACK_TYPE_OTHER 0x08 + +class LIVEMEDIA_API MatroskaTrack { +public: + MatroskaTrack(); + virtual ~MatroskaTrack(); + + // track parameters + unsigned trackNumber; + u_int8_t trackType; + Boolean isEnabled, isDefault, isForced; + unsigned defaultDuration; + char* name; + char* language; + char* codecID; + unsigned samplingFrequency; + unsigned numChannels; + char const* mimeType; + unsigned codecPrivateSize; + u_int8_t* codecPrivate; + Boolean codecPrivateUsesH264FormatForH265; // a hack specifically for H.265 video tracks + Boolean codecIsOpus; // a hack for Opus audio + unsigned headerStrippedBytesSize; + u_int8_t* headerStrippedBytes; + char const* colorSampling; + char const* colorimetry; + unsigned pixelWidth; + unsigned pixelHeight; + unsigned bitDepth; + unsigned subframeSizeSize; // 0 means: frames do not have subframes (the default behavior) + Boolean haveSubframes() const { return subframeSizeSize > 0; } +}; + +class LIVEMEDIA_API MatroskaDemux: public Medium { +public: + FramedSource* newDemuxedTrack(); + FramedSource* newDemuxedTrack(unsigned& resultTrackNumber); + // Returns a new stream ("FramedSource" subclass) that represents the next preferred media + // track (video, audio, subtitle - in that order) from the file. (Preferred media tracks + // are based on the file's language preference.) + // This function returns NULL when no more media tracks exist. + + FramedSource* newDemuxedTrackByTrackNumber(unsigned trackNumber); + // As above, but creates a new stream for a specific track number within the Matroska file. + // (You should not call this function more than once with the same track number.) + + // Note: We assume that: + // - Every track created by "newDemuxedTrack()" is later read + // - All calls to "newDemuxedTrack()" are made before any track is read + +protected: + friend class MatroskaFile; + friend class MatroskaFileParser; + class MatroskaDemuxedTrack* lookupDemuxedTrack(unsigned trackNumber); + + MatroskaDemux(MatroskaFile& ourFile); // we're created only by a "MatroskaFile" (a friend) + virtual ~MatroskaDemux(); + +private: + friend class MatroskaDemuxedTrack; + void removeTrack(unsigned trackNumber); + void continueReading(); // called by a demuxed track to tell us that it has a pending read ("doGetNextFrame()") + void seekToTime(double& seekNPT); + void pause(); + + static void handleEndOfFile(void* clientData); + void handleEndOfFile(); + + void resetState(); + +private: + MatroskaFile& fOurFile; + class MatroskaFileParser* fOurParser; + HashTable* fDemuxedTracksTable; + + // Used to implement "newServerMediaSubsession()": + u_int8_t fNextTrackTypeToCheck; +}; + +#endif diff --git a/includes/live555/liveMedia/MatroskaFileServerDemux.hh b/includes/live555/liveMedia/MatroskaFileServerDemux.hh new file mode 100644 index 0000000..ceb626b --- /dev/null +++ b/includes/live555/liveMedia/MatroskaFileServerDemux.hh @@ -0,0 +1,88 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A server demultiplexor for a Matroska file +// C++ header + +#ifndef _MATROSKA_FILE_SERVER_DEMUX_HH +#define _MATROSKA_FILE_SERVER_DEMUX_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif + +#ifndef _MATROSKA_FILE_HH +#include "MatroskaFile.hh" +#endif + +class LIVEMEDIA_API MatroskaFileServerDemux: public Medium { +public: + typedef void (onCreationFunc)(MatroskaFileServerDemux* newDemux, void* clientData); + static void createNew(UsageEnvironment& env, char const* fileName, + onCreationFunc* onCreation, void* onCreationClientData, + char const* preferredLanguage = "eng"); + // Note: Unlike most "createNew()" functions, this one doesn't return a new object immediately. Instead, because this class + // requires file reading (to parse the Matroska 'Track' headers) before a new object can be initialized, the creation of a new + // object is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as a parameter to "createNew()". + + ServerMediaSubsession* newServerMediaSubsession(); + ServerMediaSubsession* newServerMediaSubsession(unsigned& resultTrackNumber); + // Returns a new "ServerMediaSubsession" object that represents the next preferred media track + // (video, audio, subtitle - in that order) from the file. (Preferred media tracks are based on the file's language preference.) + // This function returns NULL when no more media tracks exist. + + ServerMediaSubsession* newServerMediaSubsessionByTrackNumber(unsigned trackNumber); + // As above, but creates a new "ServerMediaSubsession" object for a specific track number within the Matroska file. + // (You should not call this function more than once with the same track number.) + + // The following public: member functions are called only by the "ServerMediaSubsession" objects: + + MatroskaFile* ourMatroskaFile() { return fOurMatroskaFile; } + char const* fileName() const { return fFileName; } + float fileDuration() const { return fOurMatroskaFile->fileDuration(); } + + FramedSource* newDemuxedTrack(unsigned clientSessionId, unsigned trackNumber); + // Used by the "ServerMediaSubsession" objects to implement their "createNewStreamSource()" virtual function. + +private: + MatroskaFileServerDemux(UsageEnvironment& env, char const* fileName, + onCreationFunc* onCreation, void* onCreationClientData, + char const* preferredLanguage); + // called only by createNew() + virtual ~MatroskaFileServerDemux(); + + 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; + void* fOnCreationClientData; + MatroskaFile* fOurMatroskaFile; + + // Used to implement "newServerMediaSubsession()": + u_int8_t fNextTrackTypeToCheck; + + // Used to set up demuxing, to implement "newDemuxedTrack()": + unsigned fLastClientSessionId; + MatroskaDemux* fLastCreatedDemux; +}; + +#endif diff --git a/includes/live555/liveMedia/Media.hh b/includes/live555/liveMedia/Media.hh new file mode 100644 index 0000000..5c691c2 --- /dev/null +++ b/includes/live555/liveMedia/Media.hh @@ -0,0 +1,137 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Medium +// C++ header + +#ifndef _MEDIA_HH +#define _MEDIA_HH + +#ifndef _LIVEMEDIA_VERSION_HH +#include "liveMedia_version.hh" +#endif + +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif + +#ifndef _USAGE_ENVIRONMENT_HH +#include "UsageEnvironment.hh" +#endif + +// Lots of files end up needing the following, so just #include them here: +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif +#include + +// The following makes the Borland compiler happy: +#ifdef __BORLANDC__ +#define _strnicmp strnicmp +#define fabsf(x) fabs(x) +#endif + +#define mediumNameMaxLen 30 + +class LIVEMEDIA_API Medium { +public: + static Boolean lookupByName(UsageEnvironment& env, + char const* mediumName, + Medium*& resultMedium); + static void close(UsageEnvironment& env, char const* mediumName); + static void close(Medium* medium); // alternative close() method using ptrs + // (has no effect if medium == NULL) + + UsageEnvironment& envir() const {return fEnviron;} + + char const* name() const {return fMediumName;} + + // Test for specific types of media: + virtual Boolean isSource() const; + virtual Boolean isSink() const; + virtual Boolean isRTCPInstance() const; + virtual Boolean isRTSPClient() const; + virtual Boolean isRTSPServer() const; + virtual Boolean isMediaSession() const; + virtual Boolean isServerMediaSession() const; + +protected: + friend class MediaLookupTable; + Medium(UsageEnvironment& env); // abstract base class + virtual ~Medium(); // instances are deleted using close() only + + TaskToken& nextTask() { + return fNextTask; + } + +private: + UsageEnvironment& fEnviron; + char fMediumName[mediumNameMaxLen]; + TaskToken fNextTask; +}; + + +// A data structure for looking up a Medium by its string name. +// (It is used only to implement "Medium", but we make it visible here, in case developers want to use it to iterate over +// the whole set of "Medium" objects that we've created.) +class LIVEMEDIA_API MediaLookupTable { +public: + static MediaLookupTable* ourMedia(UsageEnvironment& env); + HashTable const& getTable() { return *fTable; } + +protected: + MediaLookupTable(UsageEnvironment& env); + virtual ~MediaLookupTable(); + +private: + friend class Medium; + + Medium* lookup(char const* name) const; + // Returns NULL if none already exists + + void addNew(Medium* medium, char* mediumName); + void remove(char const* name); + + void generateNewName(char* mediumName, unsigned maxLen); + +private: + UsageEnvironment& fEnv; + HashTable* fTable; + unsigned fNameGenerator; +}; + + +// The structure pointed to by the "liveMediaPriv" UsageEnvironment field: +class _Tables { +public: + static _Tables* getOurTables(UsageEnvironment& env, Boolean createIfNotPresent = True); + // returns a pointer to a "_Tables" structure (creating it if necessary) + void reclaimIfPossible(); + // used to delete ourselves when we're no longer used + + MediaLookupTable* mediaTable; + void* socketTable; + +protected: + _Tables(UsageEnvironment& env); + virtual ~_Tables(); + +private: + UsageEnvironment& fEnv; +}; + +#endif diff --git a/includes/live555/liveMedia/MediaSession.hh b/includes/live555/liveMedia/MediaSession.hh new file mode 100644 index 0000000..1276424 --- /dev/null +++ b/includes/live555/liveMedia/MediaSession.hh @@ -0,0 +1,370 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A data structure that represents a session that consists of +// potentially multiple (audio and/or video) sub-sessions +// (This data structure is used for media *receivers* - i.e., clients. +// For media streamers, use "ServerMediaSession" instead.) +// C++ header + +/* NOTE: To support receiving your own custom RTP payload format, you must first define a new + subclass of "MultiFramedRTPSource" (or "BasicUDPSource") that implements it. + Then define your own subclass of "MediaSession" and "MediaSubsession", as follows: + - In your subclass of "MediaSession" (named, for example, "myMediaSession"): + - Define and implement your own static member function + static myMediaSession* createNew(UsageEnvironment& env, char const* sdpDescription); + and call this - instead of "MediaSession::createNew()" - in your application, + when you create a new "MediaSession" object. + - Reimplement the "createNewMediaSubsession()" virtual function, as follows: + MediaSubsession* myMediaSession::createNewMediaSubsession() { return new myMediaSubsession(*this); } + - In your subclass of "MediaSubsession" (named, for example, "myMediaSubsession"): + - Reimplement the "createSourceObjects()" virtual function, perhaps similar to this: + Boolean myMediaSubsession::createSourceObjects(int useSpecialRTPoffset) { + if (strcmp(fCodecName, "X-MY-RTP-PAYLOAD-FORMAT") == 0) { + // This subsession uses our custom RTP payload format: + fReadSource = fRTPSource = myRTPPayloadFormatRTPSource::createNew( ); + return True; + } else { + // This subsession uses some other RTP payload format - perhaps one that we already implement: + return ::createSourceObjects(useSpecialRTPoffset); + } + } +*/ + +#ifndef _MEDIA_SESSION_HH +#define _MEDIA_SESSION_HH + +#ifndef _RTCP_HH +#include "RTCP.hh" +#endif +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif +#ifndef _SRTP_CRYPTOGRAPHIC_CONTEXT_HH +#include "SRTPCryptographicContext.hh" +#endif + +class MediaSubsession; // forward + +class LIVEMEDIA_API MediaSession: public Medium { +public: + static MediaSession* createNew(UsageEnvironment& env, + char const* sdpDescription); + + static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, + MediaSession*& resultSession); + + Boolean hasSubsessions() const { return fSubsessionsHead != NULL; } + + char* connectionEndpointName() const { return fConnectionEndpointName; } + int connectionEndpointNameAddressFamily() const { return fConnectionEndpointNameAddressFamily; } + char const* CNAME() const { return fCNAME; } + struct sockaddr_storage const& sourceFilterAddr() const { return fSourceFilterAddr; } + float& scale() { return fScale; } + float& speed() { return fSpeed; } + char* mediaSessionType() const { return fMediaSessionType; } + char* sessionName() const { return fSessionName; } + char* sessionDescription() const { return fSessionDescription; } + char const* controlPath() const { return fControlPath; } + + double& playStartTime() { return fMaxPlayStartTime; } + double& playEndTime() { return fMaxPlayEndTime; } + char* absStartTime() const; + char* absEndTime() const; + // Used only to set the local fields: + char*& _absStartTime() { return fAbsStartTime; } + char*& _absEndTime() { return fAbsEndTime; } + + Boolean initiateByMediaType(char const* mimeType, + MediaSubsession*& resultSubsession, + int useSpecialRTPoffset = -1); + // Initiates the first subsession with the specified MIME type + // Returns the resulting subsession, or 'multi source' (not both) + + MIKEYState* getMIKEYState() const { return fMIKEYState; } + SRTPCryptographicContext* getCrypto() const { return fCrypto; } + +protected: // redefined virtual functions + virtual Boolean isMediaSession() const; + +protected: + MediaSession(UsageEnvironment& env); + // called only by createNew(); + virtual ~MediaSession(); + + virtual MediaSubsession* createNewMediaSubsession(); + + Boolean initializeWithSDP(char const* sdpDescription); + Boolean parseSDPLine(char const* input, char const*& nextLine); + Boolean parseSDPLine_s(char const* sdpLine); + Boolean parseSDPLine_i(char const* sdpLine); + Boolean parseSDPLine_c(char const* sdpLine); + Boolean parseSDPAttribute_type(char const* sdpLine); + Boolean parseSDPAttribute_control(char const* sdpLine); + Boolean parseSDPAttribute_range(char const* sdpLine); + Boolean parseSDPAttribute_source_filter(char const* sdpLine); + Boolean parseSDPAttribute_key_mgmt(char const* sdpLine); + + static char* lookupPayloadFormat(unsigned char rtpPayloadType, + unsigned& rtpTimestampFrequency, + unsigned& numChannels); + static unsigned guessRTPTimestampFrequency(char const* mediumName, + char const* codecName); + +protected: + friend class MediaSubsessionIterator; + char* fCNAME; // used for RTCP + + // Linkage fields: + MediaSubsession* fSubsessionsHead; + MediaSubsession* fSubsessionsTail; + + // Fields set from a SDP description: + char* fConnectionEndpointName; + int fConnectionEndpointNameAddressFamily; + double fMaxPlayStartTime; + double fMaxPlayEndTime; + char* fAbsStartTime; + char* fAbsEndTime; + struct sockaddr_storage fSourceFilterAddr; // used for SSM + float fScale; // set from a RTSP "Scale:" header + float fSpeed; + char* fMediaSessionType; // holds a=type value + char* fSessionName; // holds s= value + char* fSessionDescription; // holds i= value + char* fControlPath; // holds optional a=control: string + + // Optional key management and crypto state: + MIKEYState* fMIKEYState; + SRTPCryptographicContext* fCrypto; +}; + + +class LIVEMEDIA_API MediaSubsessionIterator { +public: + MediaSubsessionIterator(MediaSession const& session); + virtual ~MediaSubsessionIterator(); + + MediaSubsession* next(); // NULL if none + void reset(); + +private: + MediaSession const& fOurSession; + MediaSubsession* fNextPtr; +}; + + +class LIVEMEDIA_API MediaSubsession { +public: + MediaSession& parentSession() { return fParent; } + MediaSession const& parentSession() const { return fParent; } + + unsigned short clientPortNum() const { return fClientPortNum; } + unsigned char rtpPayloadFormat() const { return fRTPPayloadFormat; } + char const* savedSDPLines() const { return fSavedSDPLines; } + char const* mediumName() const { return fMediumName; } + char const* codecName() const { return fCodecName; } + char const* protocolName() const { return fProtocolName; } + char const* controlPath() const { return fControlPath; } + + Boolean isSSM() const { return !addressIsNull(fSourceFilterAddr); } + + unsigned short videoWidth() const { return fVideoWidth; } + unsigned short videoHeight() const { return fVideoHeight; } + unsigned videoFPS() const { return fVideoFPS; } + unsigned numChannels() const { return fNumChannels; } + float& scale() { return fScale; } + float& speed() { return fSpeed; } + + RTPSource* rtpSource() { return fRTPSource; } + RTCPInstance* rtcpInstance() { return fRTCPInstance; } + unsigned rtpTimestampFrequency() const { return fRTPTimestampFrequency; } + Boolean rtcpIsMuxed() const { return fMultiplexRTCPWithRTP; } + FramedSource* readSource() { return fReadSource; } + // This is the source that client sinks read from. It is usually + // (but not necessarily) the same as "rtpSource()" + void addFilter(FramedFilter* filter); + // Changes "readSource()" to "filter" (which must have just been created with "readSource()" as its input) + + double playStartTime() const; + double playEndTime() const; + char* absStartTime() const; + char* absEndTime() const; + // Used only to set the local fields: + double& _playStartTime() { return fPlayStartTime; } + double& _playEndTime() { return fPlayEndTime; } + char*& _absStartTime() { return fAbsStartTime; } + char*& _absEndTime() { return fAbsEndTime; } + + Boolean initiate(int useSpecialRTPoffset = -1); + // Creates a "RTPSource" for this subsession. (Has no effect if it's + // already been created.) Returns True iff this succeeds. + void deInitiate(); // Destroys any previously created RTPSource + Boolean setClientPortNum(unsigned short portNum); + // Sets the preferred client port number that any "RTPSource" for + // this subsession would use. (By default, the client port number + // is gotten from the original SDP description, or - if the SDP + // description does not specfy a client port number - an ephemeral + // (even) port number is chosen.) This routine must *not* be + // called after initiate(). + void receiveRawMP3ADUs() { fReceiveRawMP3ADUs = True; } // optional hack for audio/MPA-ROBUST; must not be called after initiate() + void receiveRawJPEGFrames() { fReceiveRawJPEGFrames = True; } // optional hack for video/JPEG; must not be called after initiate() + char*& connectionEndpointName() { return fConnectionEndpointName; } + char const* connectionEndpointName() const { + return fConnectionEndpointName; + } + int connectionEndpointNameAddressFamily() const { + return fConnectionEndpointNameAddressFamily == AF_UNSPEC + ? parentSession().connectionEndpointNameAddressFamily() + : fConnectionEndpointNameAddressFamily; + } + + // 'Bandwidth' parameter, set in the "b=" SDP line: + unsigned bandwidth() const { return fBandwidth; } + + // General SDP attribute accessor functions: + char const* attrVal_str(char const* attrName) const; + // returns "" if attribute doesn't exist (and has no default value), or is not a string + char const* attrVal_strToLower(char const* attrName) const; + // returns "" if attribute doesn't exist (and has no default value), or is not a string + unsigned attrVal_int(char const* attrName) const; + // also returns 0 if attribute doesn't exist (and has no default value) + unsigned attrVal_unsigned(char const* attrName) const { return (unsigned)attrVal_int(attrName); } + Boolean attrVal_bool(char const* attrName) const { return attrVal_int(attrName) != 0; } + + // Old, now-deprecated SDP attribute accessor functions, kept here for backwards-compatibility: + char const* fmtp_config() const; + char const* fmtp_configuration() const { return fmtp_config(); } + char const* fmtp_spropparametersets() const { return attrVal_str("sprop-parameter-sets"); } + char const* fmtp_spropvps() const { return attrVal_str("sprop-vps"); } + char const* fmtp_spropsps() const { return attrVal_str("sprop-sps"); } + char const* fmtp_sproppps() const { return attrVal_str("sprop-pps"); } + + void getConnectionEndpointAddress(struct sockaddr_storage& addr) const; + // Converts "fConnectionEndpointName" to an address (or 0 if unknown) + void setDestinations(struct sockaddr_storage const& defaultDestAddress); + // Uses "fConnectionEndpointName" and "serverPortNum" to set + // the destination address and port of the RTP and RTCP objects. + // This is typically called by RTSP clients after doing "SETUP". + + char const* sessionId() const { return fSessionId; } + void setSessionId(char const* sessionId); + + // Public fields that external callers can use to keep state. + // (They are responsible for all storage management on these fields) + unsigned short serverPortNum; // in host byte order (used by RTSP) + unsigned char rtpChannelId, rtcpChannelId; // used by RTSP (for RTP/TCP) + MediaSink* sink; // callers can use this to keep track of who's playing us + void* miscPtr; // callers can use this for whatever they want + + // Parameters set from a RTSP "RTP-Info:" header: + struct { + u_int16_t seqNum; + u_int32_t timestamp; + Boolean infoIsNew; // not part of the RTSP header; instead, set whenever this struct is filled in + } rtpInfo; + + double getNormalPlayTime(struct timeval const& presentationTime); + // Computes the stream's "Normal Play Time" (NPT) from the given "presentationTime". + // (For the definition of "Normal Play Time", see RFC 2326, section 3.6.) + // This function is useful only if the "rtpInfo" structure was previously filled in + // (e.g., by a "RTP-Info:" header in a RTSP response). + // Also, for this function to work properly, the RTP stream's presentation times must (eventually) be + // synchronized via RTCP. + // (Note: If this function returns a negative number, then the result should be ignored by the caller.) + + MIKEYState* getMIKEYState() const { return fMIKEYState != NULL ? fMIKEYState : fParent.getMIKEYState(); } + SRTPCryptographicContext* getCrypto() const { return fCrypto != NULL ? fCrypto : fParent.getCrypto(); } + +protected: + friend class MediaSession; + friend class MediaSubsessionIterator; + MediaSubsession(MediaSession& parent); + virtual ~MediaSubsession(); + + UsageEnvironment& env() { return fParent.envir(); } + void setNext(MediaSubsession* next) { fNext = next; } + + void setAttribute(char const* name, char const* value = NULL, Boolean valueIsHexadecimal = False); + + Boolean parseSDPLine_c(char const* sdpLine); + Boolean parseSDPLine_b(char const* sdpLine); + Boolean parseSDPAttribute_rtpmap(char const* sdpLine); + Boolean parseSDPAttribute_rtcpmux(char const* sdpLine); + Boolean parseSDPAttribute_control(char const* sdpLine); + Boolean parseSDPAttribute_range(char const* sdpLine); + Boolean parseSDPAttribute_fmtp(char const* sdpLine); + Boolean parseSDPAttribute_source_filter(char const* sdpLine); + Boolean parseSDPAttribute_x_dimensions(char const* sdpLine); + Boolean parseSDPAttribute_framerate(char const* sdpLine); + Boolean parseSDPAttribute_key_mgmt(char const* sdpLine); + + virtual Boolean createSourceObjects(int useSpecialRTPoffset); + // create "fRTPSource" and "fReadSource" member objects, after we've been initialized via SDP + +protected: + // Linkage fields: + MediaSession& fParent; + MediaSubsession* fNext; + + // Fields set from a SDP description: + char* fConnectionEndpointName; // may also be set by RTSP SETUP response + int fConnectionEndpointNameAddressFamily; + unsigned short fClientPortNum; // in host byte order + // This field is also set by initiate() + unsigned char fRTPPayloadFormat; + char* fSavedSDPLines; + char* fMediumName; + char* fCodecName; + char* fProtocolName; + unsigned fRTPTimestampFrequency; + Boolean fMultiplexRTCPWithRTP; + char* fControlPath; // holds optional a=control: string + + // Optional key management and crypto state: + MIKEYState* fMIKEYState; + SRTPCryptographicContext* fCrypto; + + struct sockaddr_storage fSourceFilterAddr; // used for SSM + unsigned fBandwidth; // in kilobits-per-second, from b= line + + double fPlayStartTime; + double fPlayEndTime; + char* fAbsStartTime; + char* fAbsEndTime; + unsigned short fVideoWidth, fVideoHeight; + // screen dimensions (set by an optional a=x-dimensions: , line) + unsigned fVideoFPS; + // frame rate (set by an optional "a=framerate: " or "a=x-framerate: " line) + unsigned fNumChannels; + // optionally set by "a=rtpmap:" lines for audio sessions. Default: 1 + float fScale; // set from a RTSP "Scale:" header + float fSpeed; + double fNPT_PTS_Offset; // set by "getNormalPlayTime()"; add this to a PTS to get NPT + HashTable* fAttributeTable; // for "a=fmtp:" attributes. (Later an array by payload type #####) + + // Fields set or used by initiate(): + Groupsock* fRTPSocket; Groupsock* fRTCPSocket; // works even for unicast + RTPSource* fRTPSource; RTCPInstance* fRTCPInstance; + FramedSource* fReadSource; + Boolean fReceiveRawMP3ADUs, fReceiveRawJPEGFrames; + + // Other fields: + char* fSessionId; // used by RTSP +}; + +#endif diff --git a/includes/live555/liveMedia/MediaSink.hh b/includes/live555/liveMedia/MediaSink.hh new file mode 100644 index 0000000..350200d --- /dev/null +++ b/includes/live555/liveMedia/MediaSink.hh @@ -0,0 +1,135 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Media Sinks +// C++ header + +#ifndef _MEDIA_SINK_HH +#define _MEDIA_SINK_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class LIVEMEDIA_API MediaSink: public Medium { +public: + static Boolean lookupByName(UsageEnvironment& env, char const* sinkName, + MediaSink*& resultSink); + + typedef void (afterPlayingFunc)(void* clientData); + Boolean startPlaying(MediaSource& source, + afterPlayingFunc* afterFunc, + void* afterClientData); + virtual void stopPlaying(); + + // Test for specific types of sink: + virtual Boolean isRTPSink() const; + + FramedSource* source() const {return fSource;} + +protected: + MediaSink(UsageEnvironment& env); // abstract base class + virtual ~MediaSink(); + + virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); + // called by startPlaying() + virtual Boolean continuePlaying() = 0; + // called by startPlaying() + + static void onSourceClosure(void* clientData); // can be used in "getNextFrame()" calls + void onSourceClosure(); + // should be called (on ourselves) by continuePlaying() when it + // discovers that the source we're playing from has closed. + + FramedSource* fSource; + +private: + // redefined virtual functions: + virtual Boolean isSink() const; + +private: + // The following fields are used when we're being played: + afterPlayingFunc* fAfterFunc; + void* fAfterClientData; +}; + +// A data structure that a sink may use for an output packet: +class LIVEMEDIA_API OutPacketBuffer { +public: + OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize, + unsigned maxBufferSize = 0); + // if "maxBufferSize" is >0, use it - instead of "maxSize" to compute the buffer size + ~OutPacketBuffer(); + + static unsigned maxSize; + static void increaseMaxSizeTo(unsigned newMaxSize) { if (newMaxSize > OutPacketBuffer::maxSize) OutPacketBuffer::maxSize = newMaxSize; } + + unsigned char* curPtr() const {return &fBuf[fPacketStart + fCurOffset];} + unsigned totalBytesAvailable() const { + return fLimit - (fPacketStart + fCurOffset); + } + unsigned totalBufferSize() const { return fLimit; } + unsigned char* packet() const {return &fBuf[fPacketStart];} + unsigned curPacketSize() const {return fCurOffset;} + + void increment(unsigned numBytes) {fCurOffset += numBytes;} + + void enqueue(unsigned char const* from, unsigned numBytes); + void enqueueWord(u_int32_t word); + void insert(unsigned char const* from, unsigned numBytes, unsigned toPosition); + void insertWord(u_int32_t word, unsigned toPosition); + void extract(unsigned char* to, unsigned numBytes, unsigned fromPosition); + u_int32_t extractWord(unsigned fromPosition); + + void skipBytes(unsigned numBytes); + + Boolean isPreferredSize() const {return fCurOffset >= fPreferred;} + Boolean wouldOverflow(unsigned numBytes) const { + return (fCurOffset+numBytes) > fMax; + } + unsigned numOverflowBytes(unsigned numBytes) const { + return (fCurOffset+numBytes) - fMax; + } + Boolean isTooBigForAPacket(unsigned numBytes) const { + return numBytes > fMax; + } + + void setOverflowData(unsigned overflowDataOffset, + unsigned overflowDataSize, + struct timeval const& presentationTime, + unsigned durationInMicroseconds); + unsigned overflowDataSize() const {return fOverflowDataSize;} + struct timeval overflowPresentationTime() const {return fOverflowPresentationTime;} + unsigned overflowDurationInMicroseconds() const {return fOverflowDurationInMicroseconds;} + Boolean haveOverflowData() const {return fOverflowDataSize > 0;} + void useOverflowData(); + + void adjustPacketStart(unsigned numBytes); + void resetPacketStart(); + void resetOffset() { fCurOffset = 0; } + void resetOverflowData() { fOverflowDataOffset = fOverflowDataSize = 0; } + +private: + unsigned fPacketStart, fCurOffset, fPreferred, fMax, fLimit; + unsigned char* fBuf; + + unsigned fOverflowDataOffset, fOverflowDataSize; + struct timeval fOverflowPresentationTime; + unsigned fOverflowDurationInMicroseconds; +}; + +#endif diff --git a/includes/live555/liveMedia/MediaSource.hh b/includes/live555/liveMedia/MediaSource.hh new file mode 100644 index 0000000..a1915c4 --- /dev/null +++ b/includes/live555/liveMedia/MediaSource.hh @@ -0,0 +1,59 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Media Sources +// C++ header + +#ifndef _MEDIA_SOURCE_HH +#define _MEDIA_SOURCE_HH + +#ifndef _MEDIA_HH +#include "Media.hh" +#endif + +class LIVEMEDIA_API MediaSource: public Medium { +public: + static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, + MediaSource*& resultSource); + virtual void getAttributes() const; + // attributes are returned in "env's" 'result message' + + // The MIME type of this source: + virtual char const* MIMEtype() const; + + // Test for specific types of source: + virtual Boolean isFramedSource() const; + virtual Boolean isRTPSource() const; + virtual Boolean isMPEG1or2VideoStreamFramer() const; + virtual Boolean isMPEG4VideoStreamFramer() const; + virtual Boolean isH264VideoStreamFramer() const; + virtual Boolean isH265VideoStreamFramer() const; + virtual Boolean isDVVideoStreamFramer() const; + virtual Boolean isJPEGVideoSource() const; + virtual Boolean isAMRAudioSource() const; + virtual Boolean isMPEG2TransportStreamMultiplexor() const; + +protected: + MediaSource(UsageEnvironment& env); // abstract base class + virtual ~MediaSource(); + +private: + // redefined virtual functions: + virtual Boolean isSource() const; +}; + +#endif diff --git a/includes/live555/liveMedia/MediaTranscodingTable.hh b/includes/live555/liveMedia/MediaTranscodingTable.hh new file mode 100644 index 0000000..1f005b0 --- /dev/null +++ b/includes/live555/liveMedia/MediaTranscodingTable.hh @@ -0,0 +1,66 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class that implements a database that can be accessed to create +// "FramedFilter" (subclass) objects that transcode one codec into another. +// The implementation of this class just returns NULL for each codec lookup; +// To actually implement transcoding, you would subclass it. +// C++ header + +#ifndef _MEDIA_TRANSCODING_TABLE_HH +#define _MEDIA_TRANSCODING_TABLE_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif + +class LIVEMEDIA_API MediaTranscodingTable: public Medium { +public: + virtual FramedFilter* + lookupTranscoder(MediaSubsession& /*inputCodecDescription*/, // in + char*& outputCodecName/* out; must be delete[]d later */) { + // Default implementation: Return NULL (indicating: no transcoding). + // You would reimplement this virtual function in a subclass to return a new 'transcoding' + // "FramedFilter" (subclass) object for each ("mediumName","codecName") that you wish to + // transcode (or return NULL for no transcoding). + // (Note that "inputCodecDescription" must have a non-NULL "readSource()"; this is used + // as the input to the new "FramedFilter" (subclass) object.) + outputCodecName = NULL; + return NULL; + } + + virtual Boolean weWillTranscode(char const* /*mediumName*/, char const* /*codecName*/) { + // Default implementation: Return False. + // You would reimplement this in a subclass - returning True for each + // / for which you'll do transcoding. + // Note: Unlike "lookupTranscoder()", this function does not actually create any 'transcoding' + // filter objects. (It may be called before "MediaSubsession::initiate()".) + return False; + } + +protected: // we are to be subclassed only + MediaTranscodingTable(UsageEnvironment& env) + : Medium(env) { + } + virtual ~MediaTranscodingTable() { + } +}; + +#endif diff --git a/includes/live555/liveMedia/MultiFramedRTPSink.hh b/includes/live555/liveMedia/MultiFramedRTPSink.hh new file mode 100644 index 0000000..535f353 --- /dev/null +++ b/includes/live555/liveMedia/MultiFramedRTPSink.hh @@ -0,0 +1,140 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for a common kind of payload format: Those which pack multiple, +// complete codec frames (as many as possible) into each RTP packet. +// C++ header + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#define _MULTI_FRAMED_RTP_SINK_HH + +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif + +class LIVEMEDIA_API MultiFramedRTPSink: public RTPSink { +public: + void setPacketSizes(unsigned preferredPacketSize, unsigned maxPacketSize); + + typedef void (onSendErrorFunc)(void* clientData); + void setOnSendErrorFunc(onSendErrorFunc* onSendErrorFunc, void* onSendErrorFuncData) { + // Can be used to set a callback function to be called if there's an error sending RTP packets on our socket. + fOnSendErrorFunc = onSendErrorFunc; + fOnSendErrorData = onSendErrorFuncData; + } + +protected: + MultiFramedRTPSink(UsageEnvironment& env, + Groupsock* rtpgs, unsigned char rtpPayloadType, + unsigned rtpTimestampFrequency, + char const* rtpPayloadFormatName, + unsigned numChannels = 1); + // we're a virtual base class + + virtual ~MultiFramedRTPSink(); + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + // perform any processing specific to the particular payload format + virtual Boolean allowFragmentationAfterStart() const; + // whether a frame can be fragmented if other frame(s) appear earlier + // in the packet (by default: False) + virtual Boolean allowOtherFramesAfterLastFragment() const; + // whether other frames can be packed into a packet following the + // final fragment of a previous, fragmented frame (by default: False) + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + // whether this frame can appear in position >1 in a pkt (default: True) + virtual unsigned specialHeaderSize() const; + // returns the size of any special header used (following the RTP header) (default: 0) + virtual unsigned frameSpecificHeaderSize() const; + // returns the size of any frame-specific header used (before each frame + // within the packet) (default: 0) + virtual unsigned computeOverflowForNewFrame(unsigned newFrameSize) const; + // returns the number of overflow bytes that would be produced by adding a new + // frame of size "newFrameSize" to the current RTP packet. + // (By default, this just calls "numOverflowBytes()", but subclasses can redefine + // this to (e.g.) impose a granularity upon RTP payload fragments.) + + // Functions that might be called by doSpecialFrameHandling(), or other subclass virtual functions: + Boolean isFirstPacket() const { return fIsFirstPacket; } + Boolean isFirstFrameInPacket() const { return fNumFramesUsedSoFar == 0; } + unsigned curFragmentationOffset() const { return fCurFragmentationOffset; } + void setMarkerBit(); + void setTimestamp(struct timeval framePresentationTime); + void setSpecialHeaderWord(unsigned word, /* 32 bits, in host order */ + unsigned wordPosition = 0); + void setSpecialHeaderBytes(unsigned char const* bytes, unsigned numBytes, + unsigned bytePosition = 0); + void setFrameSpecificHeaderWord(unsigned word, /* 32 bits, in host order */ + unsigned wordPosition = 0); + void setFrameSpecificHeaderBytes(unsigned char const* bytes, unsigned numBytes, + unsigned bytePosition = 0); + void setFramePadding(unsigned numPaddingBytes); + unsigned numFramesUsedSoFar() const { return fNumFramesUsedSoFar; } + unsigned ourMaxPacketSize() const { return fOurMaxPacketSize; } + +public: // redefined virtual functions: + virtual void stopPlaying(); + +protected: // redefined virtual functions: + virtual Boolean continuePlaying(); + +private: + void buildAndSendPacket(Boolean isFirstPacket); + void packFrame(); + void sendPacketIfNecessary(); + static void sendNext(void* firstArg); + friend void sendNext(void*); + + static void afterGettingFrame(void* clientData, + unsigned numBytesRead, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned numBytesRead, unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + Boolean isTooBigForAPacket(unsigned numBytes) const; + + static void ourHandleClosure(void* clientData); + +private: + OutPacketBuffer* fOutBuf; + + Boolean fNoFramesLeft; + unsigned fNumFramesUsedSoFar; + unsigned fCurFragmentationOffset; + Boolean fPreviousFrameEndedFragmentation; + + Boolean fIsFirstPacket; + struct timeval fNextSendTime; + unsigned fTimestampPosition; + unsigned fSpecialHeaderPosition; + unsigned fSpecialHeaderSize; // size in bytes of any special header used + unsigned fCurFrameSpecificHeaderPosition; + unsigned fCurFrameSpecificHeaderSize; // size in bytes of cur frame-specific header + unsigned fTotalFrameSpecificHeaderSizes; // size of all frame-specific hdrs in pkt + unsigned fOurMaxPacketSize; + + onSendErrorFunc* fOnSendErrorFunc; + void* fOnSendErrorData; +}; + +#endif diff --git a/includes/live555/liveMedia/MultiFramedRTPSource.hh b/includes/live555/liveMedia/MultiFramedRTPSource.hh new file mode 100644 index 0000000..10eb932 --- /dev/null +++ b/includes/live555/liveMedia/MultiFramedRTPSource.hh @@ -0,0 +1,159 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP source for a common kind of payload format: Those which pack multiple, +// complete codec frames (as many as possible) into each RTP packet. +// C++ header + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#define _MULTI_FRAMED_RTP_SOURCE_HH + +#ifndef _RTP_SOURCE_HH +#include "RTPSource.hh" +#endif + +class BufferedPacket; // forward +class BufferedPacketFactory; // forward + +class LIVEMEDIA_API MultiFramedRTPSource: public RTPSource { +protected: + MultiFramedRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + BufferedPacketFactory* packetFactory = NULL); + // virtual base class + virtual ~MultiFramedRTPSource(); + + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + // Subclasses redefine this to handle any special, payload format + // specific header that follows the RTP header. + + virtual Boolean packetIsUsableInJitterCalculation(unsigned char* packet, + unsigned packetSize); + // The default implementation returns True, but this can be redefined + +protected: + Boolean fCurrentPacketBeginsFrame; + Boolean fCurrentPacketCompletesFrame; + +protected: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + // redefined virtual functions: + virtual void setPacketReorderingThresholdTime(unsigned uSeconds); + +private: + void reset(); + void doGetNextFrame1(); + + static void networkReadHandler(MultiFramedRTPSource* source, int /*mask*/); + void networkReadHandler1(); + + Boolean fAreDoingNetworkReads; + BufferedPacket* fPacketReadInProgress; + Boolean fNeedDelivery; + Boolean fPacketLossInFragmentedFrame; + unsigned char* fSavedTo; + unsigned fSavedMaxSize; + + // A buffer to (optionally) hold incoming pkts that have been reorderered + class ReorderingPacketBuffer* fReorderingBuffer; +}; + + +// A 'packet data' class that's used to implement the above. +// Note that this can be subclassed - if desired - to redefine +// "nextEnclosedFrameParameters()". + +class LIVEMEDIA_API BufferedPacket { +public: + BufferedPacket(); + virtual ~BufferedPacket(); + + Boolean hasUsableData() const { return fTail > fHead; } + unsigned useCount() const { return fUseCount; } + + Boolean fillInData(RTPInterface& rtpInterface, struct sockaddr_storage& fromAddress, Boolean& packetReadWasIncomplete); + void assignMiscParams(unsigned short rtpSeqNo, unsigned rtpTimestamp, + struct timeval presentationTime, + Boolean hasBeenSyncedUsingRTCP, + Boolean rtpMarkerBit, struct timeval timeReceived); + void skip(unsigned numBytes); // used to skip over an initial header + void removePadding(unsigned numBytes); // used to remove trailing bytes + void appendData(unsigned char* newData, unsigned numBytes); + void use(unsigned char* to, unsigned toSize, + unsigned& bytesUsed, unsigned& bytesTruncated, + unsigned short& rtpSeqNo, unsigned& rtpTimestamp, + struct timeval& presentationTime, + Boolean& hasBeenSyncedUsingRTCP, Boolean& rtpMarkerBit); + + BufferedPacket*& nextPacket() { return fNextPacket; } + + unsigned short rtpSeqNo() const { return fRTPSeqNo; } + struct timeval const& timeReceived() const { return fTimeReceived; } + + unsigned char* data() const { return &fBuf[fHead]; } + unsigned dataSize() const { return fTail-fHead; } + Boolean rtpMarkerBit() const { return fRTPMarkerBit; } + Boolean& isFirstPacket() { return fIsFirstPacket; } + unsigned bytesAvailable() const { return fPacketSize - fTail; } + +protected: + virtual void reset(); + virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, + unsigned dataSize); + // The above function has been deprecated. Instead, new subclasses should use: + virtual void getNextEnclosedFrameParameters(unsigned char*& framePtr, + unsigned dataSize, + unsigned& frameSize, + unsigned& frameDurationInMicroseconds); + + unsigned fPacketSize; + unsigned char* fBuf; + unsigned fHead; + unsigned fTail; + +private: + BufferedPacket* fNextPacket; // used to link together packets + + unsigned fUseCount; + unsigned short fRTPSeqNo; + unsigned fRTPTimestamp; + struct timeval fPresentationTime; // corresponding to "fRTPTimestamp" + Boolean fHasBeenSyncedUsingRTCP; + Boolean fRTPMarkerBit; + Boolean fIsFirstPacket; + struct timeval fTimeReceived; +}; + +// A 'factory' class for creating "BufferedPacket" objects. +// If you want to subclass "BufferedPacket", then you'll also +// want to subclass this, to redefine createNewPacket() + +class LIVEMEDIA_API BufferedPacketFactory { +public: + BufferedPacketFactory(); + virtual ~BufferedPacketFactory(); + + virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); +}; + +#endif diff --git a/includes/live555/liveMedia/OggFile.hh b/includes/live555/liveMedia/OggFile.hh new file mode 100644 index 0000000..8617033 --- /dev/null +++ b/includes/live555/liveMedia/OggFile.hh @@ -0,0 +1,179 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A class that encapsulates an Ogg file +// C++ header + +#ifndef _OGG_FILE_HH +#define _OGG_FILE_HH + +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif +#ifndef _HASH_TABLE_HH +#include "HashTable.hh" +#endif + +class OggTrack; // forward +class OggDemux; // forward + +typedef void OggDemuxOnDeletionFunc(void* objectToNotify, OggDemux* demuxBeingDeleted); + +class LIVEMEDIA_API OggFile: public Medium { +public: + typedef void (onCreationFunc)(OggFile* newFile, void* clientData); + static void createNew(UsageEnvironment& env, char const* fileName, + onCreationFunc* onCreation, void* onCreationClientData); + // Note: Unlike most "createNew()" functions, this one doesn't return a new object + // immediately. Instead, because this class requires file reading (to parse the + // Ogg track headers) before a new object can be initialized, the creation of a new object + // is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as + // a parameter to "createNew()". + + OggTrack* lookup(u_int32_t trackNumber); + + OggDemux* newDemux(OggDemuxOnDeletionFunc* onDeletionFunc = NULL, void* objectToNotify = NULL); + // Creates a demultiplexor for extracting tracks from this file. + // (Separate clients will typically have separate demultiplexors.) + + char const* fileName() const { return fFileName; } + unsigned numTracks() const; + + FramedSource* + createSourceForStreaming(FramedSource* baseSource, u_int32_t trackNumber, + unsigned& estBitrate, unsigned& numFiltersInFrontOfTrack); + // Takes a data source (which must be a demultiplexed track from this file) and returns + // a (possibly modified) data source that can be used for streaming. + + RTPSink* createRTPSinkForTrackNumber(u_int32_t trackNumber, Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic); + // Creates a "RTPSink" object that would be appropriate for streaming the specified track, + // or NULL if no appropriate "RTPSink" exists + + class OggTrackTable& trackTable() { return *fTrackTable; } + +private: + OggFile(UsageEnvironment& env, char const* fileName, onCreationFunc* onCreation, void* onCreationClientData); + // called only by createNew() + virtual ~OggFile(); + + static void handleEndOfBosPageParsing(void* clientData); + void handleEndOfBosPageParsing(); + + void addTrack(OggTrack* newTrack); + void removeDemux(OggDemux* demux); + +private: + friend class OggFileParser; + friend class OggDemux; + char const* fFileName; + onCreationFunc* fOnCreation; + void* fOnCreationClientData; + + class OggTrackTable* fTrackTable; + HashTable* fDemuxesTable; + class OggFileParser* fParserForInitialization; +}; + +class LIVEMEDIA_API OggTrack { +public: + OggTrack(); + virtual ~OggTrack(); + + // track parameters + u_int32_t trackNumber; // bitstream serial number + char const* mimeType; // NULL if not known + + unsigned samplingFrequency, numChannels; // for audio tracks + unsigned estBitrate; // estimate, in kbps (for RTCP) + + // Special headers for Vorbis audio, Theora video, and Opus audio tracks: + struct _vtoHdrs { + u_int8_t* header[3]; // "identification", "comment", "setup" + unsigned headerSize[3]; + + // Fields specific to Vorbis audio: + unsigned blocksize[2]; // samples per frame (packet) + unsigned uSecsPerPacket[2]; // computed as (blocksize[i]*1000000)/samplingFrequency + unsigned vorbis_mode_count; + unsigned ilog_vorbis_mode_count_minus_1; + u_int8_t* vorbis_mode_blockflag; + // an array (of size "vorbis_mode_count") of indexes into the (2-entry) "blocksize" array + + // Fields specific to Theora video: + u_int8_t KFGSHIFT; + unsigned uSecsPerFrame; + + } vtoHdrs; + + Boolean weNeedHeaders() const { + return + vtoHdrs.header[0] == NULL || + vtoHdrs.header[1] == NULL || + (vtoHdrs.header[2] == NULL && strcmp(mimeType, "audio/OPUS") != 0); + } +}; + +class LIVEMEDIA_API OggTrackTableIterator { +public: + OggTrackTableIterator(class OggTrackTable& ourTable); + virtual ~OggTrackTableIterator(); + + OggTrack* next(); + +private: + HashTable::Iterator* fIter; +}; + +class LIVEMEDIA_API OggDemux: public Medium { +public: + FramedSource* newDemuxedTrack(u_int32_t& resultTrackNumber); + // Returns a new stream ("FramedSource" subclass) that represents the next media track + // from the file. This function returns NULL when no more media tracks exist. + + FramedSource* newDemuxedTrackByTrackNumber(unsigned trackNumber); + // As above, but creates a new stream for a specific track number within the Matroska file. + // (You should not call this function more than once with the same track number.) + + // Note: We assume that: + // - Every track created by "newDemuxedTrack()" is later read + // - All calls to "newDemuxedTrack()" are made before any track is read + +protected: + friend class OggFile; + friend class OggFileParser; + class OggDemuxedTrack* lookupDemuxedTrack(u_int32_t trackNumber); + + OggDemux(OggFile& ourFile); + virtual ~OggDemux(); + +private: + friend class OggDemuxedTrack; + void removeTrack(u_int32_t trackNumber); + void continueReading(); // called by a demuxed track to tell us that it has a pending read ("doGetNextFrame()") + + static void handleEndOfFile(void* clientData); + void handleEndOfFile(); + +private: + OggFile& fOurFile; + class OggFileParser* fOurParser; + HashTable* fDemuxedTracksTable; + OggTrackTableIterator* fIter; +}; + +#endif diff --git a/includes/live555/liveMedia/OggFileServerDemux.hh b/includes/live555/liveMedia/OggFileServerDemux.hh new file mode 100644 index 0000000..7f0e134 --- /dev/null +++ b/includes/live555/liveMedia/OggFileServerDemux.hh @@ -0,0 +1,85 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A server demultiplexor for an Ogg file +// C++ header + +#ifndef _OGG_FILE_SERVER_DEMUX_HH +#define _OGG_FILE_SERVER_DEMUX_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif + +#ifndef _OGG_FILE_HH +#include "OggFile.hh" +#endif + +class LIVEMEDIA_API OggFileServerDemux: public Medium { +public: + typedef void (onCreationFunc)(OggFileServerDemux* newDemux, void* clientData); + static void createNew(UsageEnvironment& env, char const* fileName, + onCreationFunc* onCreation, void* onCreationClientData); + // Note: Unlike most "createNew()" functions, this one doesn't return a new object immediately. Instead, because this class + // requires file reading (to parse the Ogg 'Track' headers) before a new object can be initialized, the creation of a new + // object is signalled by calling - from the event loop - an 'onCreationFunc' that is passed as a parameter to "createNew()". + + ServerMediaSubsession* newServerMediaSubsession(); + ServerMediaSubsession* newServerMediaSubsession(u_int32_t& resultTrackNumber); + // Returns a new "ServerMediaSubsession" object that represents the next media track + // from the file. This function returns NULL when no more media tracks exist. + + ServerMediaSubsession* newServerMediaSubsessionByTrackNumber(u_int32_t trackNumber); + // As above, but creates a new "ServerMediaSubsession" object for a specific track number + // within the Ogg file. + // (You should not call this function more than once with the same track number.) + + // The following public: member functions are called only by the "ServerMediaSubsession" objects: + + OggFile* ourOggFile() { return fOurOggFile; } + char const* fileName() const { return fFileName; } + + FramedSource* newDemuxedTrack(unsigned clientSessionId, u_int32_t trackNumber); + // Used by the "ServerMediaSubsession" objects to implement their "createNewStreamSource()" virtual function. + +private: + OggFileServerDemux(UsageEnvironment& env, char const* fileName, + onCreationFunc* onCreation, void* onCreationClientData); + // called only by createNew() + virtual ~OggFileServerDemux(); + + 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; + void* fOnCreationClientData; + OggFile* fOurOggFile; + + // Used to implement "newServerMediaSubsession()": + OggTrackTableIterator* fIter; + + // Used to set up demuxing, to implement "newDemuxedTrack()": + unsigned fLastClientSessionId; + OggDemux* fLastCreatedDemux; +}; + +#endif diff --git a/includes/live555/liveMedia/OggFileSink.hh b/includes/live555/liveMedia/OggFileSink.hh new file mode 100644 index 0000000..c3c099e --- /dev/null +++ b/includes/live555/liveMedia/OggFileSink.hh @@ -0,0 +1,79 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// 'Ogg' File Sink (recording a single media track only) +// C++ header + +#ifndef _OGG_FILE_SINK_HH +#define _OGG_FILE_SINK_HH + +#ifndef _FILE_SINK_HH +#include "FileSink.hh" +#endif + +class LIVEMEDIA_API OggFileSink: public FileSink { +public: + static OggFileSink* createNew(UsageEnvironment& env, char const* fileName, + unsigned samplingFrequency = 0, // used for granule_position + char const* configStr = NULL, + // "configStr" is an optional 'SDP format' string (Base64-encoded) + // representing 'packed configuration headers' ("identification", "comment", "setup") + // to prepend to the output. (For 'Vorbis" audio and 'Theora' video.) + unsigned bufferSize = 100000, + Boolean oneFilePerFrame = False); + // See "FileSink.hh" for a description of these parameters. + +protected: + OggFileSink(UsageEnvironment& env, FILE* fid, unsigned samplingFrequency, char const* configStr, + unsigned bufferSize, char const* perFrameFileNamePrefix); + // called only by createNew() + virtual ~OggFileSink(); + +protected: // redefined virtual functions: + virtual Boolean continuePlaying(); + virtual void addData(unsigned char const* data, unsigned dataSize, + struct timeval presentationTime); + virtual void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, + struct timeval presentationTime); + +private: + static void ourOnSourceClosure(void* clientData); + void ourOnSourceClosure(); + +private: + unsigned fSamplingFrequency; + char const* fConfigStr; + Boolean fHaveWrittenFirstFrame, fHaveSeenEOF; + struct timeval fFirstPresentationTime; + int64_t fGranulePosition; + int64_t fGranulePositionAdjustment; // used to ensure that "fGranulePosition" stays monotonic + u_int32_t fPageSequenceNumber; + u_int8_t fPageHeaderBytes[27]; + // the header of each Ogg page, through the "number_page_segments" byte + + // Special fields used for Theora video: + Boolean fIsTheora; + u_int64_t fGranuleIncrementPerFrame; // == 1 << KFGSHIFT + + // Because the last Ogg page before EOF needs to have a special 'eos' bit set in the header, + // we need to defer the writing of each incoming frame. To do this, we maintain a 2nd buffer: + unsigned char* fAltBuffer; + unsigned fAltFrameSize, fAltNumTruncatedBytes; + struct timeval fAltPresentationTime; +}; + +#endif diff --git a/includes/live555/liveMedia/OnDemandServerMediaSubsession.hh b/includes/live555/liveMedia/OnDemandServerMediaSubsession.hh new file mode 100644 index 0000000..2eb7a4f --- /dev/null +++ b/includes/live555/liveMedia/OnDemandServerMediaSubsession.hh @@ -0,0 +1,233 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand. +// C++ header + +#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH +#define _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif +#ifndef _BASIC_UDP_SINK_HH +#include "BasicUDPSink.hh" +#endif +#ifndef _RTCP_HH +#include "RTCP.hh" +#endif + +class LIVEMEDIA_API OnDemandServerMediaSubsession: public ServerMediaSubsession { +protected: // we're a virtual base class + OnDemandServerMediaSubsession(UsageEnvironment& env, Boolean reuseFirstSource, + portNumBits initialPortNum = 6970, + Boolean multiplexRTCPWithRTP = False); + virtual ~OnDemandServerMediaSubsession(); + +protected: // redefined virtual functions + virtual char const* sdpLines(int addressFamily); + virtual void getStreamParameters(unsigned clientSessionId, + struct sockaddr_storage const& clientAddress, + Port const& clientRTPPort, + Port const& clientRTCPPort, + int tcpSocketNum, + unsigned char rtpChannelId, + unsigned char rtcpChannelId, + TLSState* tlsState, + struct sockaddr_storage& destinationAddress, + u_int8_t& destinationTTL, + Boolean& isMulticast, + Port& serverRTPPort, + Port& serverRTCPPort, + void*& streamToken); + virtual void startStream(unsigned clientSessionId, void* streamToken, + TaskFunc* rtcpRRHandler, + void* rtcpRRHandlerClientData, + unsigned short& rtpSeqNum, + unsigned& rtpTimestamp, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData); + virtual void pauseStream(unsigned clientSessionId, void* streamToken); + virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual void seekStream(unsigned clientSessionId, void* streamToken, char*& absStart, char*& absEnd); + virtual void nullSeekStream(unsigned clientSessionId, void* streamToken, + double streamEndTime, u_int64_t& numBytes); + virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale); + virtual float getCurrentNPT(void* streamToken); + virtual FramedSource* getStreamSource(void* streamToken); + virtual void getRTPSinkandRTCP(void* streamToken, + RTPSink*& rtpSink, RTCPInstance*& rtcp); + virtual void deleteStream(unsigned clientSessionId, void*& streamToken); + +protected: // new virtual functions, possibly redefined by subclasses + virtual char const* getAuxSDPLine(RTPSink* rtpSink, + FramedSource* inputSource); + virtual void seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes); + // This routine is used to seek by relative (i.e., NPT) time. + // "streamDuration", if >0.0, specifies how much data to stream, past "seekNPT". (If <=0.0, all remaining data is streamed.) + // "numBytes" returns the size (in bytes) of the data to be streamed, or 0 if unknown or unlimited. + virtual void seekStreamSource(FramedSource* inputSource, char*& absStart, char*& absEnd); + // This routine is used to seek by 'absolute' time. + // "absStart" should be a string of the form "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.Z". + // "absEnd" should be either NULL (for no end time), or a string of the same form as "absStart". + // These strings may be modified in-place, or can be reassigned to a newly-allocated value (after delete[]ing the original). + virtual void setStreamSourceScale(FramedSource* inputSource, float scale); + virtual void setStreamSourceDuration(FramedSource* inputSource, double streamDuration, u_int64_t& numBytes); + virtual void closeStreamSource(FramedSource* inputSource); + +protected: // new virtual functions, defined by all subclasses + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate) = 0; + // "estBitrate" is the stream's estimated bitrate, in kbps + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource) = 0; + +protected: // new virtual functions, may be redefined by a subclass: + virtual Groupsock* createGroupsock(struct sockaddr_storage const& addr, Port port); + virtual RTCPInstance* createRTCP(Groupsock* RTCPgs, unsigned totSessionBW, /* in kbps */ + unsigned char const* cname, RTPSink* sink); + +public: + void multiplexRTCPWithRTP() { fMultiplexRTCPWithRTP = True; } + // An alternative to passing the "multiplexRTCPWithRTP" parameter as True in the constructor + + void setRTCPAppPacketHandler(RTCPAppHandlerFunc* handler, void* clientData); + // Sets a handler to be called if a RTCP "APP" packet arrives from any future client. + // (Any current clients are not affected; any "APP" packets from them will continue to be + // handled by whatever handler existed when the client sent its first RTSP "PLAY" command.) + // (Call with (NULL, NULL) to remove an existing handler - for future clients only) + + void sendRTCPAppPacket(u_int8_t subtype, char const* name, + u_int8_t* appDependentData, unsigned appDependentDataSize); + // Sends a custom RTCP "APP" packet to the most recent client (if "reuseFirstSource" was False), + // or to all current clients (if "reuseFirstSource" was True). + // The parameters correspond to their + // respective fields as described in the RTP/RTCP definition (RFC 3550). + // Note that only the low-order 5 bits of "subtype" are used, and only the first 4 bytes + // of "name" are used. (If "name" has fewer than 4 bytes, or is NULL, + // then the remaining bytes are '\0'.) + +protected: + void setSDPLinesFromRTPSink(RTPSink* rtpSink, FramedSource* inputSource, + unsigned estBitrate); + // used to implement "sdpLines()" + +protected: + char* fSDPLines; + u_int8_t* fMIKEYStateMessage; // used if we're streaming SRTP + unsigned fMIKEYStateMessageSize; // ditto + HashTable* fDestinationsHashTable; // indexed by client session id + +private: + Boolean fReuseFirstSource; + portNumBits fInitialPortNum; + Boolean fMultiplexRTCPWithRTP; + void* fLastStreamToken; + char fCNAME[100]; // for RTCP + RTCPAppHandlerFunc* fAppHandlerTask; + void* fAppHandlerClientData; + friend class StreamState; +}; + + +// A class that represents the state of an ongoing stream. This is used only internally, in the implementation of +// "OnDemandServerMediaSubsession", but we expose the definition here, in case subclasses of "OnDemandServerMediaSubsession" +// want to access it. + +class LIVEMEDIA_API Destinations { +public: + Destinations(struct sockaddr_storage const& destAddr, + Port const& rtpDestPort, + Port const& rtcpDestPort) + : isTCP(False), addr(destAddr), rtpPort(rtpDestPort), rtcpPort(rtcpDestPort) { + } + Destinations(int tcpSockNum, unsigned char rtpChanId, unsigned char rtcpChanId, + TLSState* tlsSt) + : isTCP(True), rtpPort(0) /*dummy*/, rtcpPort(0) /*dummy*/, + tcpSocketNum(tcpSockNum), rtpChannelId(rtpChanId), rtcpChannelId(rtcpChanId), + tlsState(tlsSt) { + } + +public: + Boolean isTCP; + struct sockaddr_storage addr; + Port rtpPort; + Port rtcpPort; + int tcpSocketNum; + unsigned char rtpChannelId, rtcpChannelId; + TLSState* tlsState; +}; + +class LIVEMEDIA_API StreamState { +public: + StreamState(OnDemandServerMediaSubsession& master, + Port const& serverRTPPort, Port const& serverRTCPPort, + RTPSink* rtpSink, BasicUDPSink* udpSink, + unsigned totalBW, FramedSource* mediaSource, + Groupsock* rtpGS, Groupsock* rtcpGS); + virtual ~StreamState(); + + void startPlaying(Destinations* destinations, unsigned clientSessionId, + TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData); + void pause(); + void sendRTCPAppPacket(u_int8_t subtype, char const* name, + u_int8_t* appDependentData, unsigned appDependentDataSize); + void endPlaying(Destinations* destinations, unsigned clientSessionId); + void reclaim(); + + unsigned& referenceCount() { return fReferenceCount; } + + Port const& serverRTPPort() const { return fServerRTPPort; } + Port const& serverRTCPPort() const { return fServerRTCPPort; } + + RTPSink* rtpSink() const { return fRTPSink; } + RTCPInstance* rtcpInstance() const { return fRTCPInstance; } + + float streamDuration() const { return fStreamDuration; } + + FramedSource* mediaSource() const { return fMediaSource; } + float& startNPT() { return fStartNPT; } + +private: + OnDemandServerMediaSubsession& fMaster; + Boolean fAreCurrentlyPlaying; + unsigned fReferenceCount; + + Port fServerRTPPort, fServerRTCPPort; + + RTPSink* fRTPSink; + BasicUDPSink* fUDPSink; + + float fStreamDuration; + unsigned fTotalBW; + RTCPInstance* fRTCPInstance; + + FramedSource* fMediaSource; + float fStartNPT; // initial 'normal play time'; reset after each seek + + Groupsock* fRTPgs; + Groupsock* fRTCPgs; +}; + +#endif diff --git a/includes/live555/liveMedia/OutputFile.hh b/includes/live555/liveMedia/OutputFile.hh new file mode 100644 index 0000000..e3855d6 --- /dev/null +++ b/includes/live555/liveMedia/OutputFile.hh @@ -0,0 +1,31 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Common routines for opening/closing named output files +// C++ header + +#ifndef _OUTPUT_FILE_HH +#define _OUTPUT_FILE_HH + +#include +#include + +LIVEMEDIA_API FILE* OpenOutputFile(UsageEnvironment& env, char const* fileName); + +LIVEMEDIA_API void CloseOutputFile(FILE* fid); + +#endif diff --git a/includes/live555/liveMedia/PassiveServerMediaSubsession.hh b/includes/live555/liveMedia/PassiveServerMediaSubsession.hh new file mode 100644 index 0000000..c8cb6e7 --- /dev/null +++ b/includes/live555/liveMedia/PassiveServerMediaSubsession.hh @@ -0,0 +1,83 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that represents an existing +// 'RTPSink', rather than one that creates new 'RTPSink's on demand. +// C++ header + +#ifndef _PASSIVE_SERVER_MEDIA_SUBSESSION_HH +#define _PASSIVE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif + +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif +#ifndef _RTCP_HH +#include "RTCP.hh" +#endif + +class LIVEMEDIA_API PassiveServerMediaSubsession: public ServerMediaSubsession { +public: + static PassiveServerMediaSubsession* createNew(RTPSink& rtpSink, + RTCPInstance* rtcpInstance = NULL); + +protected: + PassiveServerMediaSubsession(RTPSink& rtpSink, RTCPInstance* rtcpInstance); + // called only by createNew(); + virtual ~PassiveServerMediaSubsession(); + + virtual Boolean rtcpIsMuxed(); + +protected: // redefined virtual functions + virtual char const* sdpLines(int addressFamily); + virtual void getStreamParameters(unsigned clientSessionId, + struct sockaddr_storage const& clientAddress, + Port const& clientRTPPort, + Port const& clientRTCPPort, + int tcpSocketNum, + unsigned char rtpChannelId, + unsigned char rtcpChannelId, + TLSState* tlsSTate, + struct sockaddr_storage& destinationAddress, + u_int8_t& destinationTTL, + Boolean& isMulticast, + Port& serverRTPPort, + Port& serverRTCPPort, + void*& streamToken); + virtual void startStream(unsigned clientSessionId, void* streamToken, + TaskFunc* rtcpRRHandler, + void* rtcpRRHandlerClientData, + unsigned short& rtpSeqNum, + unsigned& rtpTimestamp, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData); + virtual float getCurrentNPT(void* streamToken); + virtual void getRTPSinkandRTCP(void* streamToken, + RTPSink*& rtpSink, RTCPInstance*& rtcp); + virtual void deleteStream(unsigned clientSessionId, void*& streamToken); + +protected: + char* fSDPLines; + RTPSink& fRTPSink; + RTCPInstance* fRTCPInstance; + HashTable* fClientRTCPSourceRecords; // indexed by client session id; used to implement RTCP "RR" handling +}; + +#endif diff --git a/includes/live555/liveMedia/ProxyServerMediaSession.hh b/includes/live555/liveMedia/ProxyServerMediaSession.hh new file mode 100644 index 0000000..a6795e0 --- /dev/null +++ b/includes/live555/liveMedia/ProxyServerMediaSession.hh @@ -0,0 +1,238 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A subclass of "ServerMediaSession" that can be used to create a (unicast) RTSP servers that acts as a 'proxy' for +// another (unicast or multicast) RTSP/RTP stream. +// C++ header + +#ifndef _PROXY_SERVER_MEDIA_SESSION_HH +#define _PROXY_SERVER_MEDIA_SESSION_HH + +#ifndef _SERVER_MEDIA_SESSION_HH +#include "ServerMediaSession.hh" +#endif +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif +#ifndef _RTSP_CLIENT_HH +#include "RTSPClient.hh" +#endif +#ifndef _MEDIA_TRANSCODING_TABLE_HH +#include "MediaTranscodingTable.hh" +#endif + +// A subclass of "RTSPClient", used to refer to the particular "ProxyServerMediaSession" object being used. +// It is used only within the implementation of "ProxyServerMediaSession", but is defined here, in case developers wish to +// subclass it. + +class LIVEMEDIA_API ProxyRTSPClient: public RTSPClient { +public: + ProxyRTSPClient(class ProxyServerMediaSession& ourServerMediaSession, char const* rtspURL, + char const* username, char const* password, + portNumBits tunnelOverHTTPPortNum, int verbosityLevel, int socketNumToServer); + virtual ~ProxyRTSPClient(); + + void continueAfterDESCRIBE(char const* sdpDescription); + void continueAfterLivenessCommand(int resultCode, Boolean serverSupportsGetParameter); + void continueAfterSETUP(int resultCode); + void continueAfterPLAY(int resultCode); + void scheduleReset(); + +private: + void reset(); + int connectToServer(int socketNum, portNumBits remotePortNum); + + Authenticator* auth() { return fOurAuthenticator; } + + void scheduleLivenessCommand(); + static void sendLivenessCommand(void* clientData); + void doReset(); + static void doReset(void* clientData); + + void scheduleDESCRIBECommand(); + static void sendDESCRIBE(void* clientData); + void sendDESCRIBE(); + + static void subsessionTimeout(void* clientData); + void handleSubsessionTimeout(); + +private: + friend class ProxyServerMediaSession; + friend class ProxyServerMediaSubsession; + ProxyServerMediaSession& fOurServerMediaSession; + char* fOurURL; + Authenticator* fOurAuthenticator; + Boolean fStreamRTPOverTCP; + class ProxyServerMediaSubsession *fSetupQueueHead, *fSetupQueueTail; + unsigned fNumSetupsDone; + unsigned fNextDESCRIBEDelay; // in seconds + Boolean fServerSupportsGetParameter, fLastCommandWasPLAY, fDoneDESCRIBE; + TaskToken fLivenessCommandTask, fDESCRIBECommandTask, fSubsessionTimerTask, fResetTask; +}; + + +typedef ProxyRTSPClient* +createNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession, + char const* rtspURL, + char const* username, char const* password, + portNumBits tunnelOverHTTPPortNum, int verbosityLevel, + int socketNumToServer); +ProxyRTSPClient* +defaultCreateNewProxyRTSPClientFunc(ProxyServerMediaSession& ourServerMediaSession, + char const* rtspURL, + char const* username, char const* password, + portNumBits tunnelOverHTTPPortNum, int verbosityLevel, + int socketNumToServer); + +class LIVEMEDIA_API ProxyServerMediaSession: public ServerMediaSession { +public: + static ProxyServerMediaSession* createNew(UsageEnvironment& env, + GenericMediaServer* ourMediaServer, // Note: We can be used by just one server + char const* inputStreamURL, // the "rtsp://" URL of the stream we'll be proxying + char const* streamName = NULL, + char const* username = NULL, char const* password = NULL, + portNumBits tunnelOverHTTPPortNum = 0, + // for streaming the *proxied* (i.e., back-end) stream + int verbosityLevel = 0, + int socketNumToServer = -1, + MediaTranscodingTable* transcodingTable = NULL); + // Hack: "tunnelOverHTTPPortNum" == 0xFFFF (i.e., all-ones) means: Stream RTP/RTCP-over-TCP, but *not* using HTTP + // "verbosityLevel" == 1 means display basic proxy setup info; "verbosityLevel" == 2 means display RTSP client protocol also. + // If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server. + // (In this case, "inputStreamURL" must point to the socket's endpoint, so that it can be accessed via the socket.) + + virtual ~ProxyServerMediaSession(); + + char const* url() const; + + char describeCompletedFlag; + // initialized to 0; set to 1 when the back-end "DESCRIBE" completes. + // (This can be used as a 'watch variable' in "doEventLoop()".) + Boolean describeCompletedSuccessfully() const { return fClientMediaSession != NULL; } + // This can be used - along with "describeCompletedFlag" - to check whether the back-end "DESCRIBE" completed *successfully*. + +protected: + ProxyServerMediaSession(UsageEnvironment& env, GenericMediaServer* ourMediaServer, + char const* inputStreamURL, char const* streamName, + char const* username, char const* password, + portNumBits tunnelOverHTTPPortNum, int verbosityLevel, + int socketNumToServer, + MediaTranscodingTable* transcodingTable, + createNewProxyRTSPClientFunc* ourCreateNewProxyRTSPClientFunc + = defaultCreateNewProxyRTSPClientFunc, + portNumBits initialPortNum = 6970, + Boolean multiplexRTCPWithRTP = False); + + // If you subclass "ProxyRTSPClient", then you will also need to define your own function + // - with signature "createNewProxyRTSPClientFunc" (see above) - that creates a new object + // of this subclass. You should also subclass "ProxyServerMediaSession" and, in your + // subclass's constructor, initialize the parent class (i.e., "ProxyServerMediaSession") + // constructor by passing your new function as the "ourCreateNewProxyRTSPClientFunc" + // parameter. + + // Subclasses may redefine the following functions, if they want "ProxyServerSubsession"s + // to create subclassed "Groupsock" and/or "RTCPInstance" objects: + virtual Groupsock* createGroupsock(struct sockaddr_storage const& addr, Port port); + virtual RTCPInstance* createRTCP(Groupsock* RTCPgs, unsigned totSessionBW, /* in kbps */ + unsigned char const* cname, RTPSink* sink); + + virtual Boolean allowProxyingForSubsession(MediaSubsession const& mss); + // By default, this function always returns True. However, a subclass may redefine this + // if it wishes to restrict which subsessions of a stream get proxied - e.g., if it wishes + // to proxy only video tracks, but not audio (or other) tracks. + +protected: + GenericMediaServer* fOurMediaServer; + ProxyRTSPClient* fProxyRTSPClient; + MediaSession* fClientMediaSession; + +private: + friend class ProxyRTSPClient; + friend class ProxyServerMediaSubsession; + void continueAfterDESCRIBE(char const* sdpDescription); + void resetDESCRIBEState(); // undoes what was done by "contineAfterDESCRIBE()" + +private: + int fVerbosityLevel; + class PresentationTimeSessionNormalizer* fPresentationTimeSessionNormalizer; + createNewProxyRTSPClientFunc* fCreateNewProxyRTSPClientFunc; + MediaTranscodingTable* fTranscodingTable; + portNumBits fInitialPortNum; + Boolean fMultiplexRTCPWithRTP; +}; + + +////////// PresentationTimeSessionNormalizer and PresentationTimeSubsessionNormalizer definitions ////////// + +// The following two classes are used by proxies to convert incoming streams' presentation times into wall-clock-aligned +// presentation times that are suitable for our "RTPSink"s (for the corresponding outgoing streams). +// (For multi-subsession (i.e., audio+video) sessions, the outgoing streams' presentation times retain the same relative +// separation as those of the incoming streams.) + +class LIVEMEDIA_API PresentationTimeSubsessionNormalizer: public FramedFilter { +public: + void setRTPSink(RTPSink* rtpSink) { fRTPSink = rtpSink; } + +private: + friend class PresentationTimeSessionNormalizer; + PresentationTimeSubsessionNormalizer(PresentationTimeSessionNormalizer& parent, FramedSource* inputSource, RTPSource* rtpSource, + char const* codecName, PresentationTimeSubsessionNormalizer* next); + // called only from within "PresentationTimeSessionNormalizer" + virtual ~PresentationTimeSubsessionNormalizer(); + + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: // redefined virtual functions: + virtual void doGetNextFrame(); + +private: + PresentationTimeSessionNormalizer& fParent; + RTPSource* fRTPSource; + RTPSink* fRTPSink; + char const* fCodecName; + PresentationTimeSubsessionNormalizer* fNext; +}; + +class LIVEMEDIA_API PresentationTimeSessionNormalizer: public Medium { +public: + PresentationTimeSessionNormalizer(UsageEnvironment& env); + virtual ~PresentationTimeSessionNormalizer(); + + PresentationTimeSubsessionNormalizer* + createNewPresentationTimeSubsessionNormalizer(FramedSource* inputSource, RTPSource* rtpSource, char const* codecName); + +private: // called only from within "~PresentationTimeSubsessionNormalizer": + friend class PresentationTimeSubsessionNormalizer; + void normalizePresentationTime(PresentationTimeSubsessionNormalizer* ssNormalizer, + struct timeval& toPT, struct timeval const& fromPT); + void removePresentationTimeSubsessionNormalizer(PresentationTimeSubsessionNormalizer* ssNormalizer); + +private: + PresentationTimeSubsessionNormalizer* fSubsessionNormalizers; + PresentationTimeSubsessionNormalizer* fMasterSSNormalizer; // used for subsessions that have been RTCP-synced + + struct timeval fPTAdjustment; // Added to (RTCP-synced) subsession presentation times to 'normalize' them with wall-clock time. +}; + +#endif diff --git a/includes/live555/liveMedia/QCELPAudioRTPSource.hh b/includes/live555/liveMedia/QCELPAudioRTPSource.hh new file mode 100644 index 0000000..d0ed2e1 --- /dev/null +++ b/includes/live555/liveMedia/QCELPAudioRTPSource.hh @@ -0,0 +1,39 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Qualcomm "PureVoice" (aka. "QCELP") Audio RTP Sources +// C++ header + +#ifndef _QCELP_AUDIO_RTP_SOURCE_HH +#define _QCELP_AUDIO_RTP_SOURCE_HH + +#ifndef _RTP_SOURCE_HH +#include "RTPSource.hh" +#endif + +class LIVEMEDIA_API QCELPAudioRTPSource { +public: + static FramedSource* createNew(UsageEnvironment& env, + Groupsock* RTPgs, + RTPSource*& resultRTPSource, + unsigned char rtpPayloadFormat = 12, + unsigned rtpTimestampFrequency = 8000); + // This returns a source to read from, but "resultRTPSource" will + // point to RTP-related state. +}; + +#endif diff --git a/includes/live555/liveMedia/QuickTimeFileSink.hh b/includes/live555/liveMedia/QuickTimeFileSink.hh new file mode 100644 index 0000000..f485b1e --- /dev/null +++ b/includes/live555/liveMedia/QuickTimeFileSink.hh @@ -0,0 +1,192 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A sink that generates a QuickTime file from a composite media session +// C++ header + +#ifndef _QUICKTIME_FILE_SINK_HH +#define _QUICKTIME_FILE_SINK_HH + +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif + +class LIVEMEDIA_API QuickTimeFileSink: public Medium { +public: + static QuickTimeFileSink* createNew(UsageEnvironment& env, + MediaSession& inputSession, + char const* outputFileName, + unsigned bufferSize = 20000, + unsigned short movieWidth = 240, + unsigned short movieHeight = 180, + unsigned movieFPS = 15, + Boolean packetLossCompensate = False, + Boolean syncStreams = False, + Boolean generateHintTracks = False, + Boolean generateMP4Format = False); + + typedef void (afterPlayingFunc)(void* clientData); + Boolean startPlaying(afterPlayingFunc* afterFunc, + void* afterClientData); + + unsigned numActiveSubsessions() const { return fNumSubsessions; } + +protected: + QuickTimeFileSink(UsageEnvironment& env, MediaSession& inputSession, + char const* outputFileName, unsigned bufferSize, + unsigned short movieWidth, unsigned short movieHeight, + unsigned movieFPS, Boolean packetLossCompensate, + Boolean syncStreams, Boolean generateHintTracks, + Boolean generateMP4Format); + // called only by createNew() + virtual ~QuickTimeFileSink(); + + virtual void noteRecordedFrame(MediaSubsession& inputSubsession, + unsigned packetDataSize, struct timeval const& presentationTime); + +private: + Boolean continuePlaying(); + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + static void onSourceClosure(void* clientData); + void onSourceClosure1(); + static void onRTCPBye(void* clientData); + void completeOutputFile(); + +private: + friend class SubsessionIOState; + MediaSession& fInputSession; + FILE* fOutFid; + unsigned fBufferSize; + Boolean fPacketLossCompensate; + Boolean fSyncStreams, fGenerateMP4Format; + struct timeval fNewestSyncTime, fFirstDataTime; + Boolean fAreCurrentlyBeingPlayed; + afterPlayingFunc* fAfterFunc; + void* fAfterClientData; + unsigned fAppleCreationTime; + unsigned fLargestRTPtimestampFrequency; + unsigned fNumSubsessions, fNumSyncedSubsessions; + struct timeval fStartTime; + Boolean fHaveCompletedOutputFile; + +private: + ///// Definitions specific to the QuickTime file format: + + unsigned addWord64(u_int64_t word); + unsigned addWord(unsigned word); + unsigned addHalfWord(unsigned short halfWord); + unsigned addByte(unsigned char byte) { + putc(byte, fOutFid); + return 1; + } + unsigned addZeroWords(unsigned numWords); + unsigned add4ByteString(char const* str); + unsigned addArbitraryString(char const* str, + Boolean oneByteLength = True); + unsigned addAtomHeader(char const* atomName); + unsigned addAtomHeader64(char const* atomName); + // strlen(atomName) must be 4 + void setWord(int64_t filePosn, unsigned size); + void setWord64(int64_t filePosn, u_int64_t size); + + unsigned movieTimeScale() const {return fLargestRTPtimestampFrequency;} + + // Define member functions for outputting various types of atom: +#define _atom(name) unsigned addAtom_##name() + _atom(ftyp); // for MP4 format files + _atom(moov); + _atom(mvhd); + _atom(iods); // for MP4 format files + _atom(trak); + _atom(tkhd); + _atom(edts); + _atom(elst); + _atom(tref); + _atom(hint); + _atom(mdia); + _atom(mdhd); + _atom(hdlr); + _atom(minf); + _atom(smhd); + _atom(vmhd); + _atom(gmhd); + _atom(gmin); + unsigned addAtom_hdlr2(); + _atom(dinf); + _atom(dref); + _atom(alis); + _atom(stbl); + _atom(stsd); + unsigned addAtom_genericMedia(); + unsigned addAtom_soundMediaGeneral(); + _atom(ulaw); + _atom(alaw); + _atom(Qclp); + _atom(wave); + _atom(frma); + _atom(Fclp); + _atom(Hclp); + _atom(mp4a); +// _atom(wave); +// _atom(frma); + _atom(esds); + _atom(srcq); + _atom(h263); + _atom(avc1); + _atom(avcC); + _atom(mp4v); + _atom(rtp); + _atom(tims); + _atom(stts); + _atom(stss); + _atom(stsc); + _atom(stsz); + _atom(co64); + _atom(udta); + _atom(name); + _atom(hnti); + _atom(sdp); + _atom(hinf); + _atom(totl); + _atom(npck); + _atom(tpay); + _atom(trpy); + _atom(nump); + _atom(tpyl); + _atom(dmed); + _atom(dimm); + _atom(drep); + _atom(tmin); + _atom(tmax); + _atom(pmax); + _atom(dmax); + _atom(payt); + unsigned addAtom_dummy(); + +private: + unsigned short fMovieWidth, fMovieHeight; + unsigned fMovieFPS; + int64_t fMDATposition; + int64_t fMVHD_durationPosn; + unsigned fMaxTrackDurationM; // in movie time units + class SubsessionIOState* fCurrentIOState; +}; + +#endif diff --git a/includes/live555/liveMedia/QuickTimeGenericRTPSource.hh b/includes/live555/liveMedia/QuickTimeGenericRTPSource.hh new file mode 100644 index 0000000..1546347 --- /dev/null +++ b/includes/live555/liveMedia/QuickTimeGenericRTPSource.hh @@ -0,0 +1,68 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP Sources containing generic QuickTime stream data, as defined in +// +// C++ header + +#ifndef _QUICKTIME_GENERIC_RTP_SOURCE_HH +#define _QUICKTIME_GENERIC_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API QuickTimeGenericRTPSource: public MultiFramedRTPSource { +public: + static QuickTimeGenericRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency, + char const* mimeTypeString); + + // QuickTime-specific information, set from the QuickTime header + // in each packet. This, along with the data following the header, + // is used by receivers. + struct QTState { + char PCK; + unsigned timescale; + char* sdAtom; + unsigned sdAtomSize; + unsigned short width, height; + // later add other state as needed ##### + } qtState; + +protected: + virtual ~QuickTimeGenericRTPSource(); + +private: + QuickTimeGenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* mimeTypeString); + // called only by createNew() + +private: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + char const* fMIMEtypeString; +}; + +#endif diff --git a/includes/live555/liveMedia/RTCP.hh b/includes/live555/liveMedia/RTCP.hh new file mode 100644 index 0000000..c70392e --- /dev/null +++ b/includes/live555/liveMedia/RTCP.hh @@ -0,0 +1,249 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTCP +// C++ header + +#ifndef _RTCP_HH +#define _RTCP_HH + +#ifndef _RTP_SINK_HH +#include "RTPSink.hh" +#endif +#ifndef _RTP_SOURCE_HH +#include "RTPSource.hh" +#endif +#ifndef _SRTP_CRYPTOGRAPHIC_CONTEXT_HH +#include "SRTPCryptographicContext.hh" +#endif + +class LIVEMEDIA_API SDESItem { +public: + SDESItem(unsigned char tag, unsigned char const* value); + + unsigned char const* data() const {return fData;} + unsigned totalSize() const; + +private: + unsigned char fData[2 + 0xFF]; // first 2 bytes are tag and length +}; + +typedef void RTCPAppHandlerFunc(void* clientData, + u_int8_t subtype, u_int32_t nameBytes/*big-endian order*/, + u_int8_t* appDependentData, unsigned appDependentDataSize); + +class RTCPMemberDatabase; // forward + +typedef void ByeWithReasonHandlerFunc(void* clientData, char const* reason); + +class LIVEMEDIA_API RTCPInstance: public Medium { +public: + static RTCPInstance* createNew(UsageEnvironment& env, Groupsock* RTCPgs, + unsigned totSessionBW, /* in kbps */ + unsigned char const* cname, + RTPSink* sink, + RTPSource* source, + Boolean isSSMTransmitter = False, + SRTPCryptographicContext* crypto = NULL); + + static Boolean lookupByName(UsageEnvironment& env, char const* instanceName, + RTCPInstance*& resultInstance); + + unsigned numMembers() const; + unsigned totSessionBW() const { return fTotSessionBW; } + void setupForSRTCP(); + + void setByeHandler(TaskFunc* handlerTask, void* clientData, + Boolean handleActiveParticipantsOnly = True); + // Assigns a handler routine to be called if a "BYE" arrives. + // The handler is called once only; for subsequent "BYE"s, + // "setByeHandler()" would need to be called again. + // If "handleActiveParticipantsOnly" is True, then the handler is called + // only if the SSRC is for a known sender (if we have a "RTPSource"), + // or if the SSRC is for a known receiver (if we have a "RTPSink"). + // This prevents (for example) the handler for a multicast receiver being + // called if some other multicast receiver happens to exit. + // If "handleActiveParticipantsOnly" is False, then the handler is called + // for any incoming RTCP "BYE". + // (To remove an existing "BYE" handler, call "setByeHandler()" again, with a "handlerTask" of NULL.) + void setByeWithReasonHandler(ByeWithReasonHandlerFunc* handlerTask, void* clientData, + Boolean handleActiveParticipantsOnly = True); + // Like "setByeHandler()", except that a string 'reason for the bye' (received as part of + // the RTCP "BYE" packet) is passed to the handler function (along with "clientData"). + // (The 'reason' parameter to the handler function will be a dynamically-allocated string, + // or NULL, and should be delete[]d by the handler function.) + void setSRHandler(TaskFunc* handlerTask, void* clientData); + void setRRHandler(TaskFunc* handlerTask, void* clientData); + // Assigns a handler routine to be called if a "SR" or "RR" packet + // (respectively) arrives. Unlike "setByeHandler()", the handler will + // be called once for each incoming "SR" or "RR". (To turn off handling, + // call the function again with "handlerTask" (and "clientData") as NULL.) + void setSpecificRRHandler(struct sockaddr_storage const& fromAddress, Port fromPort, + TaskFunc* handlerTask, void* clientData); + // Like "setRRHandler()", but applies only to "RR" packets that come from + // a specific source address and port. (Note that if both a specific + // and a general "RR" handler function is set, then both will be called.) + void unsetSpecificRRHandler(struct sockaddr_storage const& fromAddress, Port fromPort); // equivalent to setSpecificRRHandler(..., NULL, NULL); + void setAppHandler(RTCPAppHandlerFunc* handlerTask, void* clientData); + // Assigns a handler routine to be called whenever an "APP" packet arrives. (To turn off + // handling, call the function again with "handlerTask" (and "clientData") as NULL.) + void sendAppPacket(u_int8_t subtype, char const* name, + u_int8_t* appDependentData, unsigned appDependentDataSize); + // Sends a custom RTCP "APP" packet to the peer(s). The parameters correspond to their + // respective fields as described in the RTP/RTCP definition (RFC 3550). + // Note that only the low-order 5 bits of "subtype" are used, and only the first 4 bytes + // of "name" are used. (If "name" has fewer than 4 bytes, or is NULL, + // then the remaining bytes are '\0'.) + + Groupsock* RTCPgs() const { return fRTCPInterface.gs(); } + + void setStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState); + void addStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState); + void removeStreamSocket(int sockNum, unsigned char streamChannelId) { + fRTCPInterface.removeStreamSocket(sockNum, streamChannelId); + } + // hacks to allow sending RTP over TCP (RFC 2236, section 10.12) + + void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, + void* handlerClientData) { + fRTCPInterface.setAuxilliaryReadHandler(handlerFunc, + handlerClientData); + } + + void injectReport(u_int8_t const* packet, unsigned packetSize, struct sockaddr_storage const& fromAddress); + // Allows an outside party to inject an RTCP report (from other than the network interface) + +protected: + RTCPInstance(UsageEnvironment& env, Groupsock* RTPgs, unsigned totSessionBW, + unsigned char const* cname, + RTPSink* sink, RTPSource* source, + Boolean isSSMTransmitter, + SRTPCryptographicContext* crypto); + // called only by createNew() + virtual ~RTCPInstance(); + + virtual void noteArrivingRR(struct sockaddr_storage const& fromAddressAndPort, + int tcpSocketNum, unsigned char tcpStreamChannelId); + + void incomingReportHandler1(); + +private: + // redefined virtual functions: + virtual Boolean isRTCPInstance() const; + +private: + Boolean addReport(Boolean alwaysAdd = False); + void addSR(); + void addRR(); + void enqueueCommonReportPrefix(unsigned char packetType, u_int32_t SSRC, + unsigned numExtraWords = 0); + void enqueueCommonReportSuffix(); + void enqueueReportBlock(RTPReceptionStats* receptionStats); + void addSDES(); + void addBYE(char const* reason); + + void sendBuiltPacket(); + + static void onExpire(RTCPInstance* instance); + void onExpire1(); + + static void incomingReportHandler(RTCPInstance* instance, int /*mask*/); + void processIncomingReport(unsigned packetSize, struct sockaddr_storage const& fromAddressAndPort, + int tcpSocketNum, unsigned char tcpStreamChannelId); + void onReceive(int typeOfPacket, int totPacketSize, u_int32_t ssrc); + +private: + u_int8_t* fInBuf; + unsigned fNumBytesAlreadyRead; + OutPacketBuffer* fOutBuf; + RTPInterface fRTCPInterface; + unsigned fTotSessionBW; + RTPSink* fSink; + RTPSource* fSource; + Boolean fIsSSMTransmitter; + SRTPCryptographicContext* fCrypto; + + SDESItem fCNAME; + RTCPMemberDatabase* fKnownMembers; + unsigned fOutgoingReportCount; // used for SSRC member aging + + double fAveRTCPSize; + int fIsInitial; + double fPrevReportTime; + double fNextReportTime; + int fPrevNumMembers; + + int fLastSentSize; + int fLastReceivedSize; + u_int32_t fLastReceivedSSRC; + int fTypeOfEvent; + int fTypeOfPacket; + Boolean fHaveJustSentPacket; + unsigned fLastPacketSentSize; + + TaskFunc* fByeHandlerTask; + ByeWithReasonHandlerFunc* fByeWithReasonHandlerTask; + void* fByeHandlerClientData; + Boolean fByeHandleActiveParticipantsOnly; + TaskFunc* fSRHandlerTask; + void* fSRHandlerClientData; + TaskFunc* fRRHandlerTask; + void* fRRHandlerClientData; + AddressPortLookupTable* fSpecificRRHandlerTable; + RTCPAppHandlerFunc* fAppHandlerTask; + void* fAppHandlerClientData; + +public: // because this stuff is used by an external "C" function + void schedule(double nextTime); + void reschedule(double nextTime); + void sendReport(); + void sendBYE(char const* reason = NULL); + int typeOfEvent() {return fTypeOfEvent;} + int sentPacketSize() {return fLastSentSize;} + int packetType() {return fTypeOfPacket;} + int receivedPacketSize() {return fLastReceivedSize;} + int checkNewSSRC(); + void removeLastReceivedSSRC(); + void removeSSRC(u_int32_t ssrc, Boolean alsoRemoveStats); +}; + +// RTCP packet types: +const unsigned char RTCP_PT_SR = 200; +const unsigned char RTCP_PT_RR = 201; +const unsigned char RTCP_PT_SDES = 202; +const unsigned char RTCP_PT_BYE = 203; +const unsigned char RTCP_PT_APP = 204; +const unsigned char RTCP_PT_RTPFB = 205; // Generic RTP Feedback [RFC4585] +const unsigned char RTCP_PT_PSFB = 206; // Payload-specific [RFC4585] +const unsigned char RTCP_PT_XR = 207; // extended report [RFC3611] +const unsigned char RTCP_PT_AVB = 208; // AVB RTCP packet ["Standard for Layer 3 Transport Protocol for Time Sensitive Applications in Local Area Networks." Work in progress.] +const unsigned char RTCP_PT_RSI = 209; // Receiver Summary Information [RFC5760] +const unsigned char RTCP_PT_TOKEN = 210; // Port Mapping [RFC6284] +const unsigned char RTCP_PT_IDMS = 211; // IDMS Settings [RFC7272] + +// SDES tags: +const unsigned char RTCP_SDES_END = 0; +const unsigned char RTCP_SDES_CNAME = 1; +const unsigned char RTCP_SDES_NAME = 2; +const unsigned char RTCP_SDES_EMAIL = 3; +const unsigned char RTCP_SDES_PHONE = 4; +const unsigned char RTCP_SDES_LOC = 5; +const unsigned char RTCP_SDES_TOOL = 6; +const unsigned char RTCP_SDES_NOTE = 7; +const unsigned char RTCP_SDES_PRIV = 8; + +#endif diff --git a/includes/live555/liveMedia/RTPInterface.hh b/includes/live555/liveMedia/RTPInterface.hh new file mode 100644 index 0000000..998e583 --- /dev/null +++ b/includes/live555/liveMedia/RTPInterface.hh @@ -0,0 +1,115 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// An abstraction of a network interface used for RTP (or RTCP). +// (This allows the RTP-over-TCP hack (RFC 2326, section 10.12) to +// be implemented transparently.) +// C++ header + +#ifndef _RTP_INTERFACE_HH +#define _RTP_INTERFACE_HH + +#ifndef _MEDIA_HH +#include "Media.hh" +#endif +#ifndef _TLS_STATE_HH +#include "TLSState.hh" +#endif +#ifndef _GROUPSOCK_HH +#include +#endif + +// Typedef for an optional auxilliary handler function, to be called +// when each new packet is read: +typedef void AuxHandlerFunc(void* clientData, unsigned char* packet, + unsigned& packetSize); + +typedef void ServerRequestAlternativeByteHandler(void* instance, u_int8_t requestByte); +// A hack that allows a handler for RTP/RTCP packets received over TCP to process RTSP commands that may also appear within +// the same TCP connection. A RTSP server implementation would supply a function like this - as a parameter to +// "ServerMediaSubsession::startStream()". + +class LIVEMEDIA_API RTPInterface { +public: + RTPInterface(Medium* owner, Groupsock* gs); + virtual ~RTPInterface(); + + Groupsock* gs() const { return fGS; } + + void setStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState); + void addStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState); + void removeStreamSocket(int sockNum, unsigned char streamChannelId); + static void setServerRequestAlternativeByteHandler(UsageEnvironment& env, int socketNum, + ServerRequestAlternativeByteHandler* handler, void* clientData); + static void clearServerRequestAlternativeByteHandler(UsageEnvironment& env, int socketNum); + + Boolean sendPacket(unsigned char* packet, unsigned packetSize); + void startNetworkReading(TaskScheduler::BackgroundHandlerProc* + handlerProc); + Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, + // out parameters: + unsigned& bytesRead, struct sockaddr_storage& fromAddress, + int& tcpSocketNum, unsigned char& tcpStreamChannelId, + Boolean& packetReadWasIncomplete); + // Note: If "tcpSocketNum" < 0, then the packet was received over UDP, and "tcpStreamChannelId" + // is undefined (and irrelevant). + + + // Otherwise (if "tcpSocketNum" >= 0), the packet was received (interleaved) over TCP, and + // "tcpStreamChannelId" will return the channel id. + + void stopNetworkReading(); + + UsageEnvironment& envir() const { return fOwner->envir(); } + + void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, + void* handlerClientData) { + fAuxReadHandlerFunc = handlerFunc; + fAuxReadHandlerClientData = handlerClientData; + } + + void forgetOurGroupsock() { fGS = NULL; } + // This may be called - *only immediately prior* to deleting this - to prevent our destructor + // from turning off background reading on the 'groupsock'. (This is in case the 'groupsock' + // is also being read from elsewhere.) + +private: + // Helper functions for sending a RTP or RTCP packet over a TCP connection: + Boolean sendRTPorRTCPPacketOverTCP(unsigned char* packet, unsigned packetSize, + int socketNum, unsigned char streamChannelId, + TLSState* tlsState); + Boolean sendDataOverTCP(int socketNum, TLSState* tlsState, + u_int8_t const* data, unsigned dataSize, Boolean forceSendToSucceed); + +private: + friend class SocketDescriptor; + Medium* fOwner; + Groupsock* fGS; + class tcpStreamRecord* fTCPStreams; // optional, for RTP-over-TCP streaming/receiving + + unsigned short fNextTCPReadSize; + // how much data (if any) is available to be read from the TCP stream + int fNextTCPReadStreamSocketNum; + unsigned char fNextTCPReadStreamChannelId; + TLSState* fNextTCPReadTLSState; + TaskScheduler::BackgroundHandlerProc* fReadHandlerProc; // if any + + AuxHandlerFunc* fAuxReadHandlerFunc; + void* fAuxReadHandlerClientData; +}; + +#endif diff --git a/includes/live555/liveMedia/RTPSink.hh b/includes/live555/liveMedia/RTPSink.hh new file mode 100644 index 0000000..d551867 --- /dev/null +++ b/includes/live555/liveMedia/RTPSink.hh @@ -0,0 +1,250 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP Sinks +// C++ header + +#ifndef _RTP_SINK_HH +#define _RTP_SINK_HH + +#ifndef _MEDIA_SINK_HH +#include "MediaSink.hh" +#endif +#ifndef _RTP_INTERFACE_HH +#include "RTPInterface.hh" +#endif +#ifndef _SRTP_CRYPTOGRAPHIC_CONTEXT_HH +#include "SRTPCryptographicContext.hh" +#endif + +class RTPTransmissionStatsDB; // forward + +class LIVEMEDIA_API RTPSink: public MediaSink { +public: + static Boolean lookupByName(UsageEnvironment& env, char const* sinkName, + RTPSink*& resultSink); + + // used by RTSP servers: + Groupsock const& groupsockBeingUsed() const { return *(fRTPInterface.gs()); } + Groupsock& groupsockBeingUsed() { return *(fRTPInterface.gs()); } + + unsigned char rtpPayloadType() const { return fRTPPayloadType; } + unsigned rtpTimestampFrequency() const { return fTimestampFrequency; } + void setRTPTimestampFrequency(unsigned freq) { + fTimestampFrequency = freq; + } + char const* rtpPayloadFormatName() const {return fRTPPayloadFormatName;} + + unsigned numChannels() const { return fNumChannels; } + + void setupForSRTP(Boolean useEncryption); + // sets up keying/encryption state for streaming via SRTP, using default values. + u_int8_t* setupForSRTP(Boolean useEncryption, unsigned& resultMIKEYStateMessageSize); + // as above, but returns the binary MIKEY state + void setupForSRTP(u_int8_t const* MIKEYStateMessage, unsigned MIKEYStateMessageSize); + // as above, but takes a MIKEY state message as parameter + + virtual char const* sdpMediaType() const; // for use in SDP m= lines + virtual char* rtpmapLine() const; // returns a string to be delete[]d + virtual char* keyMgmtLine(); // returns a string to be delete[]d + virtual char const* auxSDPLine(); + // optional SDP line (e.g. a=fmtp:...) + + u_int16_t currentSeqNo() const { return fSeqNo; } + u_int32_t presetNextTimestamp(); + // ensures that the next timestamp to be used will correspond to + // the current 'wall clock' time. + + RTPTransmissionStatsDB& transmissionStatsDB() const { + return *fTransmissionStatsDB; + } + + Boolean nextTimestampHasBeenPreset() const { return fNextTimestampHasBeenPreset; } + Boolean& enableRTCPReports() { return fEnableRTCPReports; } + + void getTotalBitrate(unsigned& outNumBytes, double& outElapsedTime); + // returns the number of bytes sent since the last time that we + // were called, and resets the counter. + + struct timeval const& creationTime() const { return fCreationTime; } + struct timeval const& initialPresentationTime() const { return fInitialPresentationTime; } + struct timeval const& mostRecentPresentationTime() const { return fMostRecentPresentationTime; } + void resetPresentationTimes(); + + // Hacks to allow sending RTP over TCP (RFC 2236, section 10.12): + void setStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState) { + fRTPInterface.setStreamSocket(sockNum, streamChannelId, tlsState); + } + void addStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState) { + fRTPInterface.addStreamSocket(sockNum, streamChannelId, tlsState); + } + void removeStreamSocket(int sockNum, unsigned char streamChannelId) { + fRTPInterface.removeStreamSocket(sockNum, streamChannelId); + } + unsigned& estimatedBitrate() { return fEstimatedBitrate; } // kbps; usually 0 (i.e., unset) + + u_int32_t SSRC() const {return fSSRC;} + // later need a means of changing the SSRC if there's a collision ##### + + SRTPCryptographicContext* getCrypto() const { return fCrypto; } + +protected: + RTPSink(UsageEnvironment& env, + Groupsock* rtpGS, unsigned char rtpPayloadType, + u_int32_t rtpTimestampFrequency, + char const* rtpPayloadFormatName, + unsigned numChannels); + // abstract base class + + virtual ~RTPSink(); + + // used by RTCP: + friend class RTCPInstance; + friend class RTPTransmissionStats; + u_int32_t convertToRTPTimestamp(struct timeval tv); + unsigned packetCount() const {return fPacketCount;} + unsigned octetCount() const {return fOctetCount;} + +protected: + RTPInterface fRTPInterface; + unsigned char fRTPPayloadType; + unsigned fPacketCount, fOctetCount, fTotalOctetCount /*incl RTP hdr*/; + struct timeval fTotalOctetCountStartTime, fInitialPresentationTime, fMostRecentPresentationTime; + u_int32_t fCurrentTimestamp; + u_int16_t fSeqNo; + + // Optional key management and crypto state; used if we are streaming SRTP + MIKEYState* fMIKEYState; + SRTPCryptographicContext* fCrypto; + +private: + // redefined virtual functions: + virtual Boolean isRTPSink() const; + +private: + u_int32_t fSSRC, fTimestampBase; + unsigned fTimestampFrequency; + Boolean fNextTimestampHasBeenPreset; + Boolean fEnableRTCPReports; // whether RTCP "SR" reports should be sent for this sink (default: True) + char const* fRTPPayloadFormatName; + unsigned fNumChannels; + struct timeval fCreationTime; + unsigned fEstimatedBitrate; // set on creation if known; otherwise 0 + + RTPTransmissionStatsDB* fTransmissionStatsDB; +}; + + +class RTPTransmissionStats; // forward + +class RTPTransmissionStatsDB { +public: + unsigned numReceivers() const { return fNumReceivers; } + + class Iterator { + public: + Iterator(RTPTransmissionStatsDB& receptionStatsDB); + virtual ~Iterator(); + + RTPTransmissionStats* next(); + // NULL if none + + private: + HashTable::Iterator* fIter; + }; + + // The following is called whenever a RTCP RR packet is received: + void noteIncomingRR(u_int32_t SSRC, struct sockaddr_storage const& lastFromAddress, + unsigned lossStats, unsigned lastPacketNumReceived, + unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime); + + // The following is called when a RTCP BYE packet is received: + void removeRecord(u_int32_t SSRC); + + RTPTransmissionStats* lookup(u_int32_t SSRC) const; + +private: // constructor and destructor, called only by RTPSink: + friend class RTPSink; + RTPTransmissionStatsDB(RTPSink& rtpSink); + virtual ~RTPTransmissionStatsDB(); + +private: + void add(u_int32_t SSRC, RTPTransmissionStats* stats); + +private: + friend class Iterator; + unsigned fNumReceivers; + RTPSink& fOurRTPSink; + HashTable* fTable; +}; + +class RTPTransmissionStats { +public: + u_int32_t SSRC() const {return fSSRC;} + struct sockaddr_storage const& lastFromAddress() const {return fLastFromAddress;} + unsigned lastPacketNumReceived() const {return fLastPacketNumReceived;} + unsigned firstPacketNumReported() const {return fFirstPacketNumReported;} + unsigned totNumPacketsLost() const {return fTotNumPacketsLost;} + unsigned jitter() const {return fJitter;} + unsigned lastSRTime() const { return fLastSRTime; } + unsigned diffSR_RRTime() const { return fDiffSR_RRTime; } + unsigned roundTripDelay() const; + // The round-trip delay (in units of 1/65536 seconds) computed from + // the most recently-received RTCP RR packet. + struct timeval const& timeCreated() const {return fTimeCreated;} + struct timeval const& lastTimeReceived() const {return fTimeReceived;} + void getTotalOctetCount(u_int32_t& hi, u_int32_t& lo); + void getTotalPacketCount(u_int32_t& hi, u_int32_t& lo); + + // Information which requires at least two RRs to have been received: + unsigned packetsReceivedSinceLastRR() const; + u_int8_t packetLossRatio() const { return fPacketLossRatio; } + // as an 8-bit fixed-point number + int packetsLostBetweenRR() const; + +private: + // called only by RTPTransmissionStatsDB: + friend class RTPTransmissionStatsDB; + RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC); + virtual ~RTPTransmissionStats(); + + void noteIncomingRR(struct sockaddr_storage const& lastFromAddress, + unsigned lossStats, unsigned lastPacketNumReceived, + unsigned jitter, + unsigned lastSRTime, unsigned diffSR_RRTime); + +private: + RTPSink& fOurRTPSink; + u_int32_t fSSRC; + struct sockaddr_storage fLastFromAddress; + unsigned fLastPacketNumReceived; + u_int8_t fPacketLossRatio; + unsigned fTotNumPacketsLost; + unsigned fJitter; + unsigned fLastSRTime; + unsigned fDiffSR_RRTime; + struct timeval fTimeCreated, fTimeReceived; + Boolean fAtLeastTwoRRsHaveBeenReceived; + unsigned fOldLastPacketNumReceived; + unsigned fOldTotNumPacketsLost; + Boolean fFirstPacket; + unsigned fFirstPacketNumReported; + u_int32_t fLastOctetCount, fTotalOctetCount_hi, fTotalOctetCount_lo; + u_int32_t fLastPacketCount, fTotalPacketCount_hi, fTotalPacketCount_lo; +}; + +#endif diff --git a/includes/live555/liveMedia/RTPSource.hh b/includes/live555/liveMedia/RTPSource.hh new file mode 100644 index 0000000..4aa47e2 --- /dev/null +++ b/includes/live555/liveMedia/RTPSource.hh @@ -0,0 +1,272 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP Sources +// C++ header + +#ifndef _RTP_SOURCE_HH +#define _RTP_SOURCE_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif +#ifndef _RTP_INTERFACE_HH +#include "RTPInterface.hh" +#endif +#ifndef _SRTP_CRYPTOGRAPHIC_CONTEXT_HH +#include "SRTPCryptographicContext.hh" +#endif + +class RTPReceptionStatsDB; // forward + +class LIVEMEDIA_API RTPSource: public FramedSource { +public: + static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, + RTPSource*& resultSource); + + Boolean curPacketMarkerBit() const { return fCurPacketMarkerBit; } + + unsigned char rtpPayloadFormat() const { return fRTPPayloadFormat; } + + virtual Boolean hasBeenSynchronizedUsingRTCP(); + + Groupsock* RTPgs() const { return fRTPInterface.gs(); } + + virtual void setPacketReorderingThresholdTime(unsigned uSeconds) = 0; + + void setCrypto(SRTPCryptographicContext* crypto) { fCrypto = crypto; } + + // used by RTCP: + u_int32_t SSRC() const { return fSSRC; } + // Note: This is *our* SSRC, not the SSRC in incoming RTP packets. + // later need a means of changing the SSRC if there's a collision ##### + void registerForMultiplexedRTCPPackets(class RTCPInstance* rtcpInstance) { + fRTCPInstanceForMultiplexedRTCPPackets = rtcpInstance; + } + void deregisterForMultiplexedRTCPPackets() { registerForMultiplexedRTCPPackets(NULL); } + + unsigned timestampFrequency() const {return fTimestampFrequency;} + + RTPReceptionStatsDB& receptionStatsDB() const { + return *fReceptionStatsDB; + } + + u_int32_t lastReceivedSSRC() const { return fLastReceivedSSRC; } + // Note: This is the SSRC in the most recently received RTP packet; not *our* SSRC + + Boolean& enableRTCPReports() { return fEnableRTCPReports; } + Boolean const& enableRTCPReports() const { return fEnableRTCPReports; } + + void setStreamSocket(int sockNum, unsigned char streamChannelId, TLSState* tlsState) { + // hack to allow sending RTP over TCP (RFC 2236, section 10.12) + fRTPInterface.setStreamSocket(sockNum, streamChannelId, tlsState); + } + + void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, + void* handlerClientData) { + fRTPInterface.setAuxilliaryReadHandler(handlerFunc, + handlerClientData); + } + + // Note that RTP receivers will usually not need to call either of the following two functions, because + // RTP sequence numbers and timestamps are usually not useful to receivers. + // (Our implementation of RTP reception already does all needed handling of RTP sequence numbers and timestamps.) + u_int16_t curPacketRTPSeqNum() const { return fCurPacketRTPSeqNum; } +//private: friend class MediaSubsession; // "MediaSubsession" is the only outside class that ever needs to see RTP timestamps! + u_int32_t curPacketRTPTimestamp() const { return fCurPacketRTPTimestamp; } + +protected: + RTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, u_int32_t rtpTimestampFrequency); + // abstract base class + virtual ~RTPSource(); + +protected: + RTPInterface fRTPInterface; + u_int16_t fCurPacketRTPSeqNum; + u_int32_t fCurPacketRTPTimestamp; + Boolean fCurPacketMarkerBit; + Boolean fCurPacketHasBeenSynchronizedUsingRTCP; + u_int32_t fLastReceivedSSRC; + class RTCPInstance* fRTCPInstanceForMultiplexedRTCPPackets; + SRTPCryptographicContext* fCrypto; + +private: + // redefined virtual functions: + virtual Boolean isRTPSource() const; + virtual void getAttributes() const; + +private: + unsigned char fRTPPayloadFormat; + unsigned fTimestampFrequency; + u_int32_t fSSRC; + Boolean fEnableRTCPReports; // whether RTCP "RR" reports should be sent for this source (default: True) + + RTPReceptionStatsDB* fReceptionStatsDB; +}; + + +class RTPReceptionStats; // forward + +class LIVEMEDIA_API RTPReceptionStatsDB { +public: + unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } + unsigned numActiveSourcesSinceLastReset() const { + return fNumActiveSourcesSinceLastReset; + } + + void reset(); + // resets periodic stats (called each time they're used to + // generate a reception report) + + class LIVEMEDIA_API Iterator { + public: + Iterator(RTPReceptionStatsDB& receptionStatsDB); + virtual ~Iterator(); + + RTPReceptionStats* next(Boolean includeInactiveSources = False); + // NULL if none + + private: + HashTable::Iterator* fIter; + }; + + // The following is called whenever a RTP packet is received: + void noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, + u_int32_t rtpTimestamp, + unsigned timestampFrequency, + Boolean useForJitterCalculation, + struct timeval& resultPresentationTime, + Boolean& resultHasBeenSyncedUsingRTCP, + unsigned packetSize /* payload only */); + + // The following is called whenever a RTCP SR packet is received: + void noteIncomingSR(u_int32_t SSRC, + u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, + u_int32_t rtpTimestamp); + + // The following is called when a RTCP BYE packet is received: + void removeRecord(u_int32_t SSRC); + + RTPReceptionStats* lookup(u_int32_t SSRC) const; + +protected: // constructor and destructor, called only by RTPSource: + friend class RTPSource; + RTPReceptionStatsDB(); + virtual ~RTPReceptionStatsDB(); + +protected: + void add(u_int32_t SSRC, RTPReceptionStats* stats); + +protected: + friend class Iterator; + unsigned fNumActiveSourcesSinceLastReset; + +private: + HashTable* fTable; + unsigned fTotNumPacketsReceived; // for all SSRCs +}; + +class LIVEMEDIA_API RTPReceptionStats { +public: + u_int32_t SSRC() const { return fSSRC; } + unsigned numPacketsReceivedSinceLastReset() const { + return fNumPacketsReceivedSinceLastReset; + } + unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } + double totNumKBytesReceived() const; + + unsigned totNumPacketsExpected() const { + return (fHighestExtSeqNumReceived - fBaseExtSeqNumReceived) + 1; + } + + unsigned baseExtSeqNumReceived() const { return fBaseExtSeqNumReceived; } + unsigned lastResetExtSeqNumReceived() const { + return fLastResetExtSeqNumReceived; + } + unsigned highestExtSeqNumReceived() const { + return fHighestExtSeqNumReceived; + } + + unsigned jitter() const; + + unsigned lastReceivedSR_NTPmsw() const { return fLastReceivedSR_NTPmsw; } + unsigned lastReceivedSR_NTPlsw() const { return fLastReceivedSR_NTPlsw; } + struct timeval const& lastReceivedSR_time() const { + return fLastReceivedSR_time; + } + + unsigned minInterPacketGapUS() const { return fMinInterPacketGapUS; } + unsigned maxInterPacketGapUS() const { return fMaxInterPacketGapUS; } + struct timeval const& totalInterPacketGaps() const { + return fTotalInterPacketGaps; + } + +protected: + // called only by RTPReceptionStatsDB: + friend class RTPReceptionStatsDB; + RTPReceptionStats(u_int32_t SSRC, u_int16_t initialSeqNum); + RTPReceptionStats(u_int32_t SSRC); + virtual ~RTPReceptionStats(); + +private: + void noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, + unsigned timestampFrequency, + Boolean useForJitterCalculation, + struct timeval& resultPresentationTime, + Boolean& resultHasBeenSyncedUsingRTCP, + unsigned packetSize /* payload only */); + void noteIncomingSR(u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, + u_int32_t rtpTimestamp); + void init(u_int32_t SSRC); + void initSeqNum(u_int16_t initialSeqNum); + void reset(); + // resets periodic stats (called each time they're used to + // generate a reception report) + +protected: + u_int32_t fSSRC; + unsigned fNumPacketsReceivedSinceLastReset; + unsigned fTotNumPacketsReceived; + u_int32_t fTotBytesReceived_hi, fTotBytesReceived_lo; + Boolean fHaveSeenInitialSequenceNumber; + unsigned fBaseExtSeqNumReceived; + unsigned fLastResetExtSeqNumReceived; + unsigned fHighestExtSeqNumReceived; + int fLastTransit; // used in the jitter calculation + u_int32_t fPreviousPacketRTPTimestamp; + double fJitter; + // The following are recorded whenever we receive a RTCP SR for this SSRC: + unsigned fLastReceivedSR_NTPmsw; // NTP timestamp (from SR), most-signif + unsigned fLastReceivedSR_NTPlsw; // NTP timestamp (from SR), least-signif + struct timeval fLastReceivedSR_time; + struct timeval fLastPacketReceptionTime; + unsigned fMinInterPacketGapUS, fMaxInterPacketGapUS; + struct timeval fTotalInterPacketGaps; + +private: + // Used to convert from RTP timestamp to 'wall clock' time: + Boolean fHasBeenSynchronized; + u_int32_t fSyncTimestamp; + struct timeval fSyncTime; +}; + + +LIVEMEDIA_API Boolean seqNumLT(u_int16_t s1, u_int16_t s2); + // a 'less-than' on 16-bit sequence numbers + +#endif diff --git a/includes/live555/liveMedia/RTSPClient.hh b/includes/live555/liveMedia/RTSPClient.hh new file mode 100644 index 0000000..d8cac0f --- /dev/null +++ b/includes/live555/liveMedia/RTSPClient.hh @@ -0,0 +1,415 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic RTSP client - for a single "rtsp://" URL +// C++ header + +#ifndef _RTSP_CLIENT_HH +#define _RTSP_CLIENT_HH + +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif +#ifndef _DIGEST_AUTHENTICATION_HH +#include "DigestAuthentication.hh" +#endif +#ifndef _TLS_STATE_HH +#include "TLSState.hh" +#endif +#ifndef OMIT_REGISTER_HANDLING +#ifndef _RTSP_SERVER_HH +#include "RTSPServer.hh" // For the optional "HandlerForREGISTERCommand" mini-server +#endif +#endif + +class LIVEMEDIA_API RTSPClient: public Medium { +public: + static RTSPClient* createNew(UsageEnvironment& env, char const* rtspURL, + int verbosityLevel = 0, + char const* applicationName = NULL, + portNumBits tunnelOverHTTPPortNum = 0, + int socketNumToServer = -1); + // If "tunnelOverHTTPPortNum" is non-zero, we tunnel RTSP (and RTP) + // over a HTTP connection with the given port number, using the technique + // described in Apple's document + // If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server. + // (In this case, "rtspURL" must point to the socket's endpoint, so that it can be accessed via the socket.) + + typedef void (responseHandler)(RTSPClient* rtspClient, + int resultCode, char* resultString); + // A function that is called in response to a RTSP command. The parameters are as follows: + // "rtspClient": The "RTSPClient" object on which the original command was issued. + // "resultCode": If zero, then the command completed successfully. If non-zero, then the command did not complete + // successfully, and "resultCode" indicates the error, as follows: + // A positive "resultCode" is a RTSP error code (for example, 404 means "not found") + // A negative "resultCode" indicates a socket/network error; 0-"resultCode" is the standard "errno" code. + // "resultString": A ('\0'-terminated) string returned along with the response, or else NULL. + // In particular: + // "resultString" for a successful "DESCRIBE" command will be the media session's SDP description. + // "resultString" for a successful "OPTIONS" command will be a list of allowed commands. + // Note that this string can be present (i.e., not NULL) even if "resultCode" is non-zero - i.e., an error message. + // Also, "resultString" can be NULL, even if "resultCode" is zero (e.g., if the RTSP command succeeded, but without + // including an appropriate result header). + // Note also that this string is dynamically allocated, and must be freed by the handler (or the caller) + // - using "delete[]". + + unsigned sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "DESCRIBE" command, then returns the "CSeq" sequence number that was used in the command. + // The (programmer-supplied) "responseHandler" function is called later to handle the response + // (or is called immediately - with an error code - if the command cannot be sent). + // "authenticator" (optional) is used for access control. If you have username and password strings, you can use this by + // passing an actual parameter that you created by creating an "Authenticator(username, password) object". + // (Note that if you supply a non-NULL "authenticator" parameter, you need do this only for the first command you send.) + + unsigned sendOptionsCommand(responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "OPTIONS" command, then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendAnnounceCommand(char const* sdpDescription, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "ANNOUNCE" command (with "sdpDescription" as parameter), + // then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendSetupCommand(MediaSubsession& subsession, responseHandler* responseHandler, + Boolean streamOutgoing = False, + Boolean streamUsingTCP = False, + Boolean forceMulticastOnUnspecified = False, + Authenticator* authenticator = NULL); + // Issues a RTSP "SETUP" command, then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendPlayCommand(MediaSession& session, responseHandler* responseHandler, + double start = 0.0f, double end = -1.0f, float scale = 1.0f, + Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "PLAY" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (Note: start=-1 means 'resume'; end=-1 means 'play to end') + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + unsigned sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler, + double start = 0.0f, double end = -1.0f, float scale = 1.0f, + Authenticator* authenticator = NULL); + // Issues a RTSP "PLAY" command on "subsession", then returns the "CSeq" sequence number that was used in the command. + // (Note: start=-1 means 'resume'; end=-1 means 'play to end') + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + // Alternative forms of "sendPlayCommand()", used to send "PLAY" commands that include an 'absolute' time range: + // (The "absStartTime" string (and "absEndTime" string, if present) *must* be of the form + // "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.Z") + unsigned sendPlayCommand(MediaSession& session, responseHandler* responseHandler, + char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, + Authenticator* authenticator = NULL); + unsigned sendPlayCommand(MediaSubsession& subsession, responseHandler* responseHandler, + char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, + Authenticator* authenticator = NULL); + + unsigned sendPauseCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "PAUSE" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + unsigned sendPauseCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "PAUSE" command on "subsession", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendRecordCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "RECORD" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + unsigned sendRecordCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "RECORD" command on "subsession", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendTeardownCommand(MediaSession& session, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "TEARDOWN" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + unsigned sendTeardownCommand(MediaSubsession& subsession, responseHandler* responseHandler, Authenticator* authenticator = NULL); + // Issues a RTSP "TEARDOWN" command on "subsession", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendSetParameterCommand(MediaSession& session, responseHandler* responseHandler, + char const* parameterName, char const* parameterValue, + Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "SET_PARAMETER" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + unsigned sendGetParameterCommand(MediaSession& session, responseHandler* responseHandler, char const* parameterName, + Authenticator* authenticator = NULL); + // Issues an aggregate RTSP "GET_PARAMETER" command on "session", then returns the "CSeq" sequence number that was used in the command. + // (The "responseHandler" and "authenticator" parameters are as described for "sendDescribeCommand".) + + void setRequireValue(char const* requireValue = NULL); + // Sets a string to be used as the value of a "Require:" header to be included in + // subsequent RTSP commands. Call "setRequireValue()" again (i.e., with no parameter) + // to clear this (and so stop "Require:" headers from being included in subsequent cmds). + + void sendDummyUDPPackets(MediaSession& session, unsigned numDummyPackets = 2); + void sendDummyUDPPackets(MediaSubsession& subsession, unsigned numDummyPackets = 2); + // Sends short 'dummy' (i.e., non-RTP or RTCP) UDP packets towards the server, to increase + // the likelihood of RTP/RTCP packets from the server reaching us if we're behind a NAT. + // (If we requested RTP-over-TCP streaming, then these functions have no effect.) + // Our implementation automatically does this just prior to sending each "PLAY" command; + // You should not call these functions yourself unless you know what you're doing. + + void setSpeed(MediaSession& session, float speed = 1.0f); + // Set (recorded) media download speed to given value to support faster download using 'Speed:' + // option on 'PLAY' command. + + Boolean changeResponseHandler(unsigned cseq, responseHandler* newResponseHandler); + // Changes the response handler for the previously-performed command (whose operation returned "cseq"). + // (To turn off any response handling for the command, use a "newResponseHandler" value of NULL. This might be done as part + // of an implementation of a 'timeout handler' on the command, for example.) + // This function returns True iff "cseq" was for a valid previously-performed command (whose response is still unhandled). + + int socketNum() const { return fInputSocketNum; } + + static Boolean lookupByName(UsageEnvironment& env, + char const* sourceName, + RTSPClient*& resultClient); + + Boolean parseRTSPURL(char const* url, + char*& username, char*& password, NetAddress& address, portNumBits& portNum, char const** urlSuffix = NULL); + // Parses "url" as "rtsp://[[:]@][:][/]" + // (Note that the returned "username" and "password" are either NULL, or heap-allocated strings that the caller must later delete[].) + + void setUserAgentString(char const* userAgentName); + // sets an alternative string to be used in RTSP "User-Agent:" headers + + void disallowBasicAuthentication() { fAllowBasicAuthentication = False; } + // call this if you don't want the server to request 'Basic' authentication + // (which would cause the client to send usernames and passwords over the net). + + unsigned sessionTimeoutParameter() const { return fSessionTimeoutParameter; } + + char const* url() const { return fBaseURL; } + + static unsigned responseBufferSize; + +public: // Some compilers complain if this is "private:" + // The state of a request-in-progress: + class LIVEMEDIA_API RequestRecord { + public: + RequestRecord(unsigned cseq, char const* commandName, responseHandler* handler, + MediaSession* session = NULL, MediaSubsession* subsession = NULL, u_int32_t booleanFlags = 0, + double start = 0.0f, double end = -1.0f, float scale = 1.0f, char const* contentStr = NULL); + RequestRecord(unsigned cseq, responseHandler* handler, + char const* absStartTime, char const* absEndTime = NULL, float scale = 1.0f, + MediaSession* session = NULL, MediaSubsession* subsession = NULL); + // alternative constructor for creating "PLAY" requests that include 'absolute' time values + virtual ~RequestRecord(); + + RequestRecord*& next() { return fNext; } + unsigned& cseq() { return fCSeq; } + char const* commandName() const { return fCommandName; } + MediaSession* session() const { return fSession; } + MediaSubsession* subsession() const { return fSubsession; } + u_int32_t booleanFlags() const { return fBooleanFlags; } + double start() const { return fStart; } + double end() const { return fEnd; } + char const* absStartTime() const { return fAbsStartTime; } + char const* absEndTime() const { return fAbsEndTime; } + float scale() const { return fScale; } + char* contentStr() const { return fContentStr; } + responseHandler*& handler() { return fHandler; } + + private: + RequestRecord* fNext; + unsigned fCSeq; + char const* fCommandName; + MediaSession* fSession; + MediaSubsession* fSubsession; + u_int32_t fBooleanFlags; + double fStart, fEnd; + char *fAbsStartTime, *fAbsEndTime; // used for optional 'absolute' (i.e., "time=") range specifications + float fScale; + char* fContentStr; + responseHandler* fHandler; + }; + +protected: + RTSPClient(UsageEnvironment& env, char const* rtspURL, + int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum, int socketNumToServer); + // called only by createNew(); + virtual ~RTSPClient(); + + void reset(); + void setBaseURL(char const* url); + int grabSocket(); // allows a subclass to reuse our input socket, so that it won't get closed when we're deleted + virtual unsigned sendRequest(RequestRecord* request); + virtual Boolean setRequestFields(RequestRecord* request, + char*& cmdURL, Boolean& cmdURLWasAllocated, + char const*& protocolStr, + char*& extraHeaders, Boolean& extraHeadersWereAllocated); + // used to implement "sendRequest()"; subclasses may reimplement this (e.g., when implementing a new command name) + virtual int connectToServer(int socketNum, portNumBits remotePortNum); // used to implement "openConnection()"; result values: -1: failure; 0: pending; 1: success + +private: // redefined virtual functions + virtual Boolean isRTSPClient() const; + +private: + class LIVEMEDIA_API RequestQueue { + public: + RequestQueue(); + RequestQueue(RequestQueue& origQueue); // moves the queue contents to the new queue + virtual ~RequestQueue(); + + void enqueue(RequestRecord* request); // "request" must not be NULL + RequestRecord* dequeue(); + void putAtHead(RequestRecord* request); // "request" must not be NULL + RequestRecord* findByCSeq(unsigned cseq); + Boolean isEmpty() const { return fHead == NULL; } + void reset(); + + private: + RequestRecord* fHead; + RequestRecord* fTail; + }; + + void resetTCPSockets(); + void resetResponseBuffer(); + int openConnection(); // result values: -1: failure; 0: pending; 1: success + char* createAuthenticatorString(char const* cmd, char const* url); + char* createBlocksizeString(Boolean streamUsingTCP); + char* createKeyMgmtString(char const* url, MediaSubsession const& subsession); + void handleRequestError(RequestRecord* request); + Boolean parseResponseCode(char const* line, unsigned& responseCode, char const*& responseString); + void handleIncomingRequest(); + static Boolean checkForHeader(char const* line, char const* headerName, unsigned headerNameLength, char const*& headerParams); + Boolean parseTransportParams(char const* paramsStr, + char*& serverAddressStr, portNumBits& serverPortNum, + unsigned char& rtpChannelId, unsigned char& rtcpChannelId); + Boolean parseScaleParam(char const* paramStr, float& scale); + Boolean parseSpeedParam(char const* paramStr, float& speed); + Boolean parseRTPInfoParams(char const*& paramStr, u_int16_t& seqNum, u_int32_t& timestamp); + Boolean handleSETUPResponse(MediaSubsession& subsession, char const* sessionParamsStr, char const* transportParamsStr, + Boolean streamUsingTCP); + Boolean handlePLAYResponse(MediaSession* session, MediaSubsession* subsession, + char const* scaleParamsStr, const char* speedParamsStr, + char const* rangeParamsStr, char const* rtpInfoParamsStr); + Boolean handleTEARDOWNResponse(MediaSession& session, MediaSubsession& subsession); + Boolean handleGET_PARAMETERResponse(char const* parameterName, char*& resultValueString, char* resultValueStringEnd); + Boolean handleAuthenticationFailure(char const* wwwAuthenticateParamsStr); + Boolean resendCommand(RequestRecord* request); + char const* sessionURL(MediaSession const& session) const; + static void handleAlternativeRequestByte(void*, u_int8_t requestByte); + void handleAlternativeRequestByte1(u_int8_t requestByte); + void constructSubsessionURL(MediaSubsession const& subsession, + char const*& prefix, + char const*& separator, + char const*& suffix); + + // Support for tunneling RTSP-over-HTTP: + Boolean setupHTTPTunneling1(); // send the HTTP "GET" + static void responseHandlerForHTTP_GET(RTSPClient* rtspClient, int responseCode, char* responseString); + void responseHandlerForHTTP_GET1(int responseCode, char* responseString); + Boolean setupHTTPTunneling2(); // send the HTTP "POST" + + // Support for asynchronous connections to the server: + static void connectionHandler(void*, int /*mask*/); + void connectionHandler1(); + + // Support for handling data sent back by a server: + static void incomingDataHandler(void*, int /*mask*/); + void incomingDataHandler1(); + void handleResponseBytes(int newBytesRead); + + // Writing/reading data over a (already set-up) connection: + int write(const char* data, unsigned count); + int read(u_int8_t* buffer, unsigned bufferSize); + +public: + u_int16_t desiredMaxIncomingPacketSize; + // If set to a value >0, then a "Blocksize:" header with this value (minus an allowance for + // IP, UDP, and RTP headers) will be sent with each "SETUP" request. + +protected: + int fVerbosityLevel; + unsigned fCSeq; // sequence number, used in consecutive requests + Authenticator fCurrentAuthenticator; + Boolean fAllowBasicAuthentication; + struct sockaddr_storage fServerAddress; + +private: + portNumBits fTunnelOverHTTPPortNum; + char* fUserAgentHeaderStr; + unsigned fUserAgentHeaderStrLen; + int fInputSocketNum, fOutputSocketNum; + char* fBaseURL; + unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP + char* fLastSessionId; + unsigned fSessionTimeoutParameter; // optionally set in response "Session:" headers + char* fResponseBuffer; + unsigned fResponseBytesAlreadySeen, fResponseBufferBytesLeft; + RequestQueue fRequestsAwaitingConnection, fRequestsAwaitingHTTPTunneling, fRequestsAwaitingResponse; + char* fRequireStr; + + // Support for tunneling RTSP-over-HTTP: + char fSessionCookie[33]; + unsigned fSessionCookieCounter; + Boolean fHTTPTunnelingConnectionIsPending; + + // Optional support for TLS: + ClientTLSState fTLS; + ClientTLSState fPOSTSocketTLS; // used only for RTSP-over-HTTPS + ClientTLSState* fInputTLS; + ClientTLSState* fOutputTLS; + friend class ClientTLSState; +}; + + +#ifndef OMIT_REGISTER_HANDLING +////////// HandlerServerForREGISTERCommand ///////// + +// A simple server that creates a new "RTSPClient" object whenever a "REGISTER" request arrives (specifying the "rtsp://" URL +// of a stream). The new "RTSPClient" object will be created with the specified URL, and passed to the provided handler function. + +typedef void onRTSPClientCreationFunc(RTSPClient* newRTSPClient, Boolean requestStreamingOverTCP); + +class LIVEMEDIA_API HandlerServerForREGISTERCommand: public RTSPServer { +public: + static HandlerServerForREGISTERCommand* createNew(UsageEnvironment& env, onRTSPClientCreationFunc* creationFunc, + Port ourPort = 0, UserAuthenticationDatabase* authDatabase = NULL, + int verbosityLevel = 0, char const* applicationName = NULL); + // If ourPort.num() == 0, we'll choose the port number ourself. (Use the following function to get it.) + portNumBits serverPortNum() const { return ntohs(fServerPort.num()); } + +protected: + HandlerServerForREGISTERCommand(UsageEnvironment& env, onRTSPClientCreationFunc* creationFunc, int ourSocketIPv4, int ourSocketIPv6, Port ourPort, + UserAuthenticationDatabase* authDatabase, int verbosityLevel, char const* applicationName); + // called only by createNew(); + virtual ~HandlerServerForREGISTERCommand(); + + virtual RTSPClient* createNewRTSPClient(char const* rtspURL, int verbosityLevel, char const* applicationName, + int socketNumToServer); + // This function - by default - creates a (base) "RTSPClient" object. If you want to create a subclass + // of "RTSPClient" instead, then subclass this class, and redefine this virtual function. + +protected: // redefined virtual functions + virtual char const* allowedCommandNames(); // "OPTIONS", "REGISTER", and (perhaps) "DEREGISTER" only + virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* proxyURLSuffix, char*& responseStr); + // redefined to return True (for cmd=="REGISTER") + virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* url, char const* urlSuffix, int socketToRemoteServer, + Boolean deliverViaTCP, char const* proxyURLSuffix); + +private: + onRTSPClientCreationFunc* fCreationFunc; + int fVerbosityLevel; + char* fApplicationName; +}; +#endif + +#endif diff --git a/includes/live555/liveMedia/RTSPCommon.hh b/includes/live555/liveMedia/RTSPCommon.hh new file mode 100644 index 0000000..746afe1 --- /dev/null +++ b/includes/live555/liveMedia/RTSPCommon.hh @@ -0,0 +1,65 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Common routines used by both RTSP clients and servers +// C++ header + +#ifndef _RTSP_COMMON_HH +#define _RTSP_COMMON_HH + +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif + +#ifndef _MEDIA_HH +#include // includes some definitions perhaps needed for Borland compilers? +#endif + +#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) +#define _strncasecmp _strnicmp +#define snprintf _snprintf +#else +#define _strncasecmp strncasecmp +#endif + +#define RTSP_PARAM_STRING_MAX 200 + +LIVEMEDIA_API Boolean parseRTSPRequestString(char const *reqStr, unsigned reqStrSize, // in + char *resultCmdName, // out + unsigned resultCmdNameMaxSize, // in + char* resultURLPreSuffix, // out + unsigned resultURLPreSuffixMaxSize, // in + char* resultURLSuffix, // out + unsigned resultURLSuffixMaxSize, // in + char* resultCSeq, // out + unsigned resultCSeqMaxSize, // in + char* resultSessionId, // out + unsigned resultSessionIdMaxSize, // in + unsigned& contentLength, Boolean& urlIsRTSPS); // out + +LIVEMEDIA_API Boolean parseRangeParam(char const* paramStr, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime, Boolean& startTimeIsNow); +LIVEMEDIA_API Boolean parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime, Boolean& startTimeIsNow); + +LIVEMEDIA_API Boolean parseScaleHeader(char const* buf, float& scale); + +LIVEMEDIA_API Boolean RTSPOptionIsSupported(char const* commandName, char const* optionsResponseString); + // Returns True iff the RTSP command "commandName" is mentioned as one of the commands supported in "optionsResponseString" + // (which should be the 'resultString' from a previous RTSP "OPTIONS" request). + +LIVEMEDIA_API char const* dateHeader(); // A "Date:" header that can be used in a RTSP (or HTTP) response + +#endif diff --git a/includes/live555/liveMedia/RTSPRegisterSender.hh b/includes/live555/liveMedia/RTSPRegisterSender.hh new file mode 100644 index 0000000..4facb9f --- /dev/null +++ b/includes/live555/liveMedia/RTSPRegisterSender.hh @@ -0,0 +1,138 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Special objects which, when created, sends a custom RTSP "REGISTER" (or "DEREGISTER") command +// to a specified client. +// C++ header + +#ifndef _RTSP_REGISTER_SENDER_HH +#define _RTSP_REGISTER_SENDER_HH + +#ifndef _RTSP_CLIENT_HH +#include "RTSPClient.hh" +#endif + +class LIVEMEDIA_API RTSPRegisterOrDeregisterSender: public RTSPClient { +public: + virtual ~RTSPRegisterOrDeregisterSender(); +protected: // we're a virtual base class + RTSPRegisterOrDeregisterSender(UsageEnvironment& env, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, + Authenticator* authenticator, + int verbosityLevel, char const* applicationName); + +public: // Some compilers complain if this is "protected:" + // A subclass of "RTSPClient::RequestRecord", specific to our "REGISTER" and "DEREGISTER" commands: + class RequestRecord_REGISTER_or_DEREGISTER: public RTSPClient::RequestRecord { + public: + RequestRecord_REGISTER_or_DEREGISTER(unsigned cseq, char const* cmdName, RTSPClient::responseHandler* rtspResponseHandler, char const* rtspURLToRegisterOrDeregister, char const* proxyURLSuffix); + virtual ~RequestRecord_REGISTER_or_DEREGISTER(); + + char const* proxyURLSuffix() const { return fProxyURLSuffix; } + + protected: + char* fRTSPURLToRegisterOrDeregister; + char* fProxyURLSuffix; + }; + +protected: + portNumBits fRemoteClientPortNum; +}; + +////////// + +class LIVEMEDIA_API RTSPRegisterSender: public RTSPRegisterOrDeregisterSender { +public: + static RTSPRegisterSender* + createNew(UsageEnvironment& env, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToRegister, + RTSPClient::responseHandler* rtspResponseHandler, Authenticator* authenticator = NULL, + Boolean requestStreamingViaTCP = False, char const* proxyURLSuffix = NULL, Boolean reuseConnection = False, + int verbosityLevel = 0, char const* applicationName = NULL); + + void grabConnection(int& sock, struct sockaddr_storage& remoteAddress); // so that the socket doesn't get closed when we're deleted + +protected: + RTSPRegisterSender(UsageEnvironment& env, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToRegister, + RTSPClient::responseHandler* rtspResponseHandler, Authenticator* authenticator, + Boolean requestStreamingViaTCP, char const* proxyURLSuffix, Boolean reuseConnection, + int verbosityLevel, char const* applicationName); + // called only by "createNew()" + virtual ~RTSPRegisterSender(); + + // Redefined virtual functions: + virtual Boolean setRequestFields(RequestRecord* request, + char*& cmdURL, Boolean& cmdURLWasAllocated, + char const*& protocolStr, + char*& extraHeaders, Boolean& extraHeadersWereAllocated); + +public: // Some compilers complain if this is "protected:" + // A subclass of "RequestRecord_REGISTER_or_DEREGISTER", specific to our "REGISTER" command: + class RequestRecord_REGISTER: public RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER { + public: + RequestRecord_REGISTER(unsigned cseq, RTSPClient::responseHandler* rtspResponseHandler, char const* rtspURLToRegister, + Boolean reuseConnection, Boolean requestStreamingViaTCP, char const* proxyURLSuffix); + virtual ~RequestRecord_REGISTER(); + + char const* rtspURLToRegister() const { return fRTSPURLToRegisterOrDeregister; } + Boolean reuseConnection() const { return fReuseConnection; } + Boolean requestStreamingViaTCP() const { return fRequestStreamingViaTCP; } + + private: + Boolean fReuseConnection, fRequestStreamingViaTCP; + }; +}; + +////////// + +class LIVEMEDIA_API RTSPDeregisterSender: public RTSPRegisterOrDeregisterSender { +public: + static RTSPDeregisterSender* + createNew(UsageEnvironment& env, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToDeregister, + RTSPClient::responseHandler* rtspResponseHandler, Authenticator* authenticator = NULL, + char const* proxyURLSuffix = NULL, + int verbosityLevel = 0, char const* applicationName = NULL); + +protected: + RTSPDeregisterSender(UsageEnvironment& env, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, char const* rtspURLToDeregister, + RTSPClient::responseHandler* rtspResponseHandler, Authenticator* authenticator, + char const* proxyURLSuffix, + int verbosityLevel, char const* applicationName); + // called only by "createNew()" + virtual ~RTSPDeregisterSender(); + + // Redefined virtual functions: + virtual Boolean setRequestFields(RequestRecord* request, + char*& cmdURL, Boolean& cmdURLWasAllocated, + char const*& protocolStr, + char*& extraHeaders, Boolean& extraHeadersWereAllocated); + +public: // Some compilers complain if this is "protected:" + // A subclass of "RequestRecord_REGISTER_or_DEREGISTER", specific to our "DEREGISTER" command: + class RequestRecord_DEREGISTER: public RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER { + public: + RequestRecord_DEREGISTER(unsigned cseq, RTSPClient::responseHandler* rtspResponseHandler, char const* rtspURLToDeregister, char const* proxyURLSuffix); + virtual ~RequestRecord_DEREGISTER(); + + char const* rtspURLToDeregister() const { return fRTSPURLToRegisterOrDeregister; } + }; +}; + +#endif diff --git a/includes/live555/liveMedia/RTSPServer.hh b/includes/live555/liveMedia/RTSPServer.hh new file mode 100644 index 0000000..b1dd2f9 --- /dev/null +++ b/includes/live555/liveMedia/RTSPServer.hh @@ -0,0 +1,397 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A RTSP server +// C++ header + +#ifndef _RTSP_SERVER_HH +#define _RTSP_SERVER_HH + +#ifndef _GENERIC_MEDIA_SERVER_HH +#include "GenericMediaServer.hh" +#endif +#ifndef _DIGEST_AUTHENTICATION_HH +#include "DigestAuthentication.hh" +#endif + +class LIVEMEDIA_API RTSPServer: public GenericMediaServer { +public: + static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554, + UserAuthenticationDatabase* authDatabase = NULL, + unsigned reclamationSeconds = 65); + // If ourPort.num() == 0, we'll choose the port number + // Note: The caller is responsible for reclaiming "authDatabase" + // If "reclamationSeconds" > 0, then the "RTSPClientSession" state for + // each client will get reclaimed (and the corresponding RTP stream(s) + // torn down) if no RTSP commands - or RTCP "RR" packets - from the + // client are received in at least "reclamationSeconds" seconds. + + static Boolean lookupByName(UsageEnvironment& env, char const* name, + RTSPServer*& resultServer); + + typedef void (responseHandlerForREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString); + unsigned registerStream(ServerMediaSession* serverMediaSession, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, + responseHandlerForREGISTER* responseHandler, + char const* username = NULL, char const* password = NULL, + Boolean receiveOurStreamViaTCP = False, + char const* proxyURLSuffix = NULL); + // 'Register' the stream represented by "serverMediaSession" with the given remote client (specifed by name and port number). + // This is done using our custom "REGISTER" RTSP command. + // The function returns a unique number that can be used to identify the request; this number is also passed to "responseHandler". + // When a response is received from the remote client (or the "REGISTER" request fails), the specified response handler + // (if non-NULL) is called. (Note that the "resultString" passed to the handler was dynamically allocated, + // and should be delete[]d by the handler after use.) + // If "receiveOurStreamViaTCP" is True, then we're requesting that the remote client access our stream using RTP/RTCP-over-TCP. + // (Otherwise, the remote client may choose regular RTP/RTCP-over-UDP streaming.) + // "proxyURLSuffix" (optional) is used only when the remote client is also a proxy server. + // It tells the proxy server the suffix that it should use in its "rtsp://" URL (when front-end clients access the stream) + + typedef void (responseHandlerForDEREGISTER)(RTSPServer* rtspServer, unsigned requestId, int resultCode, char* resultString); + unsigned deregisterStream(ServerMediaSession* serverMediaSession, + char const* remoteClientNameOrAddress, portNumBits remoteClientPortNum, + responseHandlerForDEREGISTER* responseHandler, + char const* username = NULL, char const* password = NULL, + char const* proxyURLSuffix = NULL); + // Used to turn off a previous "registerStream()" - using our custom "DEREGISTER" RTSP command. + + char* rtspURL(ServerMediaSession const* serverMediaSession, + int clientSocket = -1, Boolean useIPv6 = False) const; + // returns a "rtsp://" URL that could be used to access the + // specified session (which must already have been added to + // us using "addServerMediaSession()". + // This string is dynamically allocated; caller should delete[] + // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine + // the IP address to be used in the URL.) + // Shortcuts: + char* ipv4rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) { + return rtspURL(serverMediaSession, clientSocket, False); + } + char* ipv6rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1) { + return rtspURL(serverMediaSession, clientSocket, True); + } + + char* rtspURLPrefix(int clientSocket = -1, Boolean useIPv6 = False) const; + // like "rtspURL()", except that it returns just the common prefix used by + // each session's "rtsp://" URL. + // This string is dynamically allocated; caller should delete[] + // Shortcuts: + char* ipv4rtspURLPrefix(int clientSocket = -1) { return rtspURLPrefix(clientSocket, False); } + char* ipv6rtspURLPrefix(int clientSocket = -1) { return rtspURLPrefix(clientSocket, True); } + + UserAuthenticationDatabase* setAuthenticationDatabase(UserAuthenticationDatabase* newDB); + // Changes the server's authentication database to "newDB", returning a pointer to the old database (if there was one). + // "newDB" may be NULL (you can use this to disable authentication at runtime, if desired). + + void disableStreamingRTPOverTCP() { + fAllowStreamingRTPOverTCP = False; + } + + Boolean setUpTunnelingOverHTTP(Port httpPort); + // (Attempts to) enable RTSP-over-HTTP tunneling on the specified port. + // Returns True iff the specified port can be used in this way (i.e., it's not already being used for a separate HTTP server). + // Note: RTSP-over-HTTP tunneling is described in + // http://mirror.informatimago.com/next/developer.apple.com/quicktime/icefloe/dispatch028.html + // and http://images.apple.com/br/quicktime/pdf/QTSS_Modules.pdf + portNumBits httpServerPortNum() const; // in host byte order. (Returns 0 if not present.) + + void setTLSState(char const* certFileName, char const* privKeyFileName, + Boolean weServeSRTP = True, Boolean weEncryptSRTP = True); + +protected: + RTSPServer(UsageEnvironment& env, + int ourSocketIPv4, int ourSocketIPv6, Port ourPort, + UserAuthenticationDatabase* authDatabase, + unsigned reclamationSeconds); + // called only by createNew(); + virtual ~RTSPServer(); + + virtual char const* allowedCommandNames(); // used to implement "RTSPClientConnection::handleCmd_OPTIONS()" + virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* proxyURLSuffix, char*& responseStr); + // used to implement "RTSPClientConnection::handleCmd_REGISTER()" + // Note: "responseStr" is dynamically allocated (or NULL), and should be delete[]d after the call + virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* url, char const* urlSuffix, int socketToRemoteServer, + Boolean deliverViaTCP, char const* proxyURLSuffix); + // used to implement "RTSPClientConnection::handleCmd_REGISTER()" + + virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName); + virtual Boolean specialClientAccessCheck(int clientSocket, + struct sockaddr_storage const& clientAddr, + char const* urlSuffix); + // a hook that allows subclassed servers to do server-specific access checking + // on each client (e.g., based on client IP address), without using digest authentication. + virtual Boolean specialClientUserAccessCheck(int clientSocket, + struct sockaddr_storage const& clientAddr, + char const* urlSuffix, char const *username); + // another hook that allows subclassed servers to do server-specific access checking + // - this time after normal digest authentication has already taken place (and would otherwise allow access). + // (This test can only be used to further restrict access, not to grant additional access.) + virtual void specialHandlingOfAuthenticationFailure(int clientSocket, + struct sockaddr_storage const& clientAddr, + char const* urlSuffix); + // a hook that allows subclassed servers to take extra action whenevever an authentication failure occurs + +public: // redefined virtual functions + virtual Boolean isRTSPServer() const; + virtual void addServerMediaSession(ServerMediaSession* serverMediaSession); + +public: // should be protected, but some old compilers complain otherwise + // The state of a TCP connection used by a RTSP client: + class RTSPClientSession; // forward + class RTSPClientConnection: public GenericMediaServer::ClientConnection { + public: + // A data structure that's used to implement the "REGISTER" command: + class ParamsForREGISTER { + public: + ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix, + Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix); + virtual ~ParamsForREGISTER(); + private: + friend class RTSPClientConnection; + char const* fCmd; + RTSPClientConnection* fOurConnection; + char* fURL; + char* fURLSuffix; + Boolean fReuseConnection, fDeliverViaTCP; + char* fProxyURLSuffix; + }; + protected: // redefined virtual functions: + virtual void handleRequestBytes(int newBytesRead); + + protected: + RTSPClientConnection(RTSPServer& ourServer, + int clientSocket, struct sockaddr_storage const& clientAddr, + Boolean useTLS = False); + virtual ~RTSPClientConnection(); + + friend class RTSPServer; + friend class RTSPClientSession; + + // Make the handler functions for each command virtual, to allow subclasses to reimplement them, if necessary: + virtual void handleCmd_OPTIONS(); + // You probably won't need to subclass/reimplement this function; reimplement "RTSPServer::allowedCommandNames()" instead. + virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire server + virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server + virtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); + static void DESCRIBELookupCompletionFunction(void* clientData, ServerMediaSession* sessionLookedUp); + virtual void handleCmd_DESCRIBE_afterLookup(ServerMediaSession* session); + virtual void handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* url, char const* urlSuffix, char const* fullRequestStr, + Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix); + // You probably won't need to subclass/reimplement this function; + // reimplement "RTSPServer::weImplementREGISTER()" and "RTSPServer::implementCmd_REGISTER()" instead. + virtual void handleCmd_bad(); + virtual void handleCmd_notSupported(); + virtual void handleCmd_redirect(char const* urlSuffix); + virtual void handleCmd_notFound(); + virtual void handleCmd_sessionNotFound(); + virtual void handleCmd_unsupportedTransport(); + // Support for optional RTSP-over-HTTP tunneling: + virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize, + char* urlSuffix, unsigned urlSuffixMaxSize, + char* sessionCookie, unsigned sessionCookieMaxSize, + char* acceptStr, unsigned acceptStrMaxSize); + virtual void handleHTTPCmd_notSupported(); + virtual void handleHTTPCmd_notFound(); + virtual void handleHTTPCmd_OPTIONS(); + virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie); + virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize); + virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr); + protected: + void resetRequestBuffer(); + void closeSocketsRTSP(); + static void handleAlternativeRequestByte(void*, u_int8_t requestByte); + void handleAlternativeRequestByte1(u_int8_t requestByte); + Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr); + void changeClientInputSocket(int newSocketNum, ServerTLSState const* newTLSState, + unsigned char const* extraData, unsigned extraDataSize); + // used to implement RTSP-over-HTTP tunneling + static void continueHandlingREGISTER(ParamsForREGISTER* params); + virtual void continueHandlingREGISTER1(ParamsForREGISTER* params); + + // Shortcuts for setting up a RTSP response (prior to sending it): + void setRTSPResponse(char const* responseStr); + void setRTSPResponse(char const* responseStr, u_int32_t sessionId); + void setRTSPResponse(char const* responseStr, char const* contentStr); + void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr); + + RTSPServer& fOurRTSPServer; // same as ::fOurServer + int& fClientInputSocket; // aliased to ::fOurSocket + int fClientOutputSocket; + ServerTLSState fPOSTSocketTLS; // used only for RTSP-over-HTTPS + int fAddressFamily; + Boolean fIsActive; + unsigned char* fLastCRLF; + unsigned fRecursionCount; + char const* fCurrentCSeq; + Authenticator fCurrentAuthenticator; // used if access control is needed + char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling + unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3) + unsigned fScheduledDelayedTask; + }; + + // The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server: + class LIVEMEDIA_API RTSPClientSession: public GenericMediaServer::ClientSession { + protected: + RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId); + virtual ~RTSPClientSession(); + + friend class RTSPServer; + friend class RTSPClientConnection; + // Make the handler functions for each command virtual, to allow subclasses to redefine them: + virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection, + char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); + static void SETUPLookupCompletionFunction1(void* clientData, ServerMediaSession* sessionLookedUp); + virtual void handleCmd_SETUP_afterLookup1(ServerMediaSession* sms); + static void SETUPLookupCompletionFunction2(void* clientData, ServerMediaSession* sessionLookedUp); + virtual void handleCmd_SETUP_afterLookup2(ServerMediaSession* sms); + virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection, + char const* cmdName, + char const* urlPreSuffix, char const* urlSuffix, + char const* fullRequestStr); + virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection, + ServerMediaSubsession* subsession); + virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection, + ServerMediaSubsession* subsession, char const* fullRequestStr); + virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection, + ServerMediaSubsession* subsession); + virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection, + ServerMediaSubsession* subsession, char const* fullRequestStr); + virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection, + ServerMediaSubsession* subsession, char const* fullRequestStr); + protected: + void deleteStreamByTrack(unsigned trackNum); + void reclaimStreamStates(); + Boolean isMulticast() const { return fIsMulticast; } + + // Shortcuts for setting up a RTSP response (prior to sending it): + void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr) { ourClientConnection->setRTSPResponse(responseStr); } + void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId) { ourClientConnection->setRTSPResponse(responseStr, sessionId); } + void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, contentStr); } + void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, sessionId, contentStr); } + + protected: + RTSPServer& fOurRTSPServer; // same as ::fOurServer + Boolean fIsMulticast, fStreamAfterSETUP; + unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP + Boolean usesTCPTransport() const { return fTCPStreamIdCount > 0; } + unsigned fNumStreamStates; + struct streamState { + ServerMediaSubsession* subsession; + int tcpSocketNum; + void* streamToken; + } * fStreamStates; + + // Member variables used to implement "handleCmd_SETUP()": + RTSPServer::RTSPClientConnection* fOurClientConnection; + char const* fURLPreSuffix; char const* fURLSuffix; char const* fFullRequestStr; char const* fTrackId; + }; + +protected: // redefined virtual functions + // If you subclass "RTSPClientConnection", then you must also redefine this virtual function in order + // to create new objects of your subclass: + virtual ClientConnection* createNewClientConnection(int clientSocket, struct sockaddr_storage const& clientAddr); + +protected: + // If you subclass "RTSPClientSession", then you must also redefine this virtual function in order + // to create new objects of your subclass: + virtual ClientSession* createNewClientSession(u_int32_t sessionId); + +private: + static void incomingConnectionHandlerHTTPIPv4(void*, int /*mask*/); + void incomingConnectionHandlerHTTPIPv4(); + static void incomingConnectionHandlerHTTPIPv6(void*, int /*mask*/); + void incomingConnectionHandlerHTTPIPv6(); + + void noteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum); + void unnoteTCPStreamingOnSocket(int socketNum, RTSPClientSession* clientSession, unsigned trackNum); + void stopTCPStreamingOnSocket(int socketNum); + +private: + friend class RTSPClientConnection; + friend class RTSPClientSession; + friend class RegisterRequestRecord; + friend class DeregisterRequestRecord; + int fHTTPServerSocketIPv4, fHTTPServerSocketIPv6; // for optional RTSP-over-HTTP tunneling + Port fHTTPServerPort; // ditto + HashTable* fClientConnectionsForHTTPTunneling; // maps client-supplied 'session cookie' strings to "RTSPClientConnection"s + // (used only for optional RTSP-over-HTTP tunneling) + HashTable* fTCPStreamingDatabase; + // maps TCP socket numbers to ids of sessions that are streaming over it (RTP/RTCP-over-TCP) + HashTable* fPendingRegisterOrDeregisterRequests; + unsigned fRegisterOrDeregisterRequestCounter; + UserAuthenticationDatabase* fAuthDB; + Boolean fAllowStreamingRTPOverTCP; // by default, True + Boolean fOurConnectionsUseTLS; // by default, False + Boolean fWeServeSRTP; // used only if "fOurConnectionsUseTLS" is True + Boolean fWeEncryptSRTP; // used only if "fWeServeSRTP" is True +}; + + +////////// A subclass of "RTSPServer" that implements the "REGISTER" command to set up proxying on the specified URL ////////// + +class LIVEMEDIA_API RTSPServerWithREGISTERProxying: public RTSPServer { +public: + static RTSPServerWithREGISTERProxying* createNew(UsageEnvironment& env, Port ourPort = 554, + UserAuthenticationDatabase* authDatabase = NULL, + UserAuthenticationDatabase* authDatabaseForREGISTER = NULL, + unsigned reclamationSeconds = 65, + Boolean streamRTPOverTCP = False, + int verbosityLevelForProxying = 0, + char const* backEndUsername = NULL, + char const* backEndPassword = NULL); + +protected: + RTSPServerWithREGISTERProxying(UsageEnvironment& env, int ourSocketIPv4, int ourSocketIPv6, Port ourPort, + UserAuthenticationDatabase* authDatabase, UserAuthenticationDatabase* authDatabaseForREGISTER, + unsigned reclamationSeconds, + Boolean streamRTPOverTCP, int verbosityLevelForProxying, + char const* backEndUsername, char const* backEndPassword); + // called only by createNew(); + virtual ~RTSPServerWithREGISTERProxying(); + +protected: // redefined virtual functions + virtual char const* allowedCommandNames(); + virtual Boolean weImplementREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* proxyURLSuffix, char*& responseStr); + virtual void implementCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/, + char const* url, char const* urlSuffix, int socketToRemoteServer, + Boolean deliverViaTCP, char const* proxyURLSuffix); + virtual UserAuthenticationDatabase* getAuthenticationDatabaseForCommand(char const* cmdName); + +private: + Boolean fStreamRTPOverTCP; + int fVerbosityLevelForProxying; + unsigned fRegisteredProxyCounter; + char* fAllowedCommandNames; + UserAuthenticationDatabase* fAuthDBForREGISTER; + char* fBackEndUsername; + char* fBackEndPassword; +}; + + +// A special version of "parseTransportHeader()", used just for parsing the "Transport:" header +// in an incoming "REGISTER" command: +LIVEMEDIA_API void parseTransportHeaderForREGISTER(char const* buf, // in + Boolean &reuseConnection, // out + Boolean& deliverViaTCP, // out + char*& proxyURLSuffix); // out + +#endif diff --git a/includes/live555/liveMedia/RawVideoFrameParameters.hh b/includes/live555/liveMedia/RawVideoFrameParameters.hh new file mode 100644 index 0000000..f001f59 --- /dev/null +++ b/includes/live555/liveMedia/RawVideoFrameParameters.hh @@ -0,0 +1,37 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Parameters used for streaming (transmitting and receiving) raw video frames over RTP +// C++ header + +#ifndef _RAW_VIDEO_FRAME_PARAMETERS_HH +#define _RAW_VIDEO_FRAME_PARAMETERS_HH + +class LIVEMEDIA_API RawVideoFrameParameters { +public: + RawVideoFrameParameters(unsigned width, unsigned height, unsigned depth, char const* sampling); + virtual ~RawVideoFrameParameters(); + +public: + u_int16_t pgroupSize; // in octets + u_int16_t numPixelsInPgroup; + u_int32_t scanLineSize; // in octets + u_int32_t frameSize; // in octets + u_int16_t scanLineIterationStep; // usually 1, but 2 for sampling=="YCbCr-4:2:0" +}; + +#endif diff --git a/includes/live555/liveMedia/RawVideoRTPSink.hh b/includes/live555/liveMedia/RawVideoRTPSink.hh new file mode 100644 index 0000000..3d6956b --- /dev/null +++ b/includes/live555/liveMedia/RawVideoRTPSink.hh @@ -0,0 +1,71 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for Raw video +// C++ header + +#ifndef _RAW_VIDEO_RTP_SINK_HH +#define _RAW_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +#ifndef _RAW_VIDEO_FRAME_PARAMETERS_HH +#include "RawVideoFrameParameters.hh" +#endif + +class LIVEMEDIA_API RawVideoRTPSink: public VideoRTPSink { +public: + static RawVideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, + unsigned width, unsigned height, unsigned depth, // as defined by RFC 4175, sec 6.1 + char const* sampling, char const* colorimetry); + +protected: + RawVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, + unsigned width, unsigned height, unsigned depth, + char const* sampling, char const* colorimetry); + // called only by createNew() + + virtual ~RawVideoRTPSink(); + +private: // redefined virtual functions: + virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; + virtual unsigned computeOverflowForNewFrame(unsigned newFrameSize) const; + +private: + char* fFmtpSDPLine; + unsigned fLineIndex; + RawVideoFrameParameters fP; + + unsigned getNumLinesInPacket(unsigned fragOffset, u_int16_t*& lengths, u_int16_t*& offsets) const; + // return the number of lines, their lengths and offsets from the fragmentation offset of the whole frame. + // call delete[] on lengths and offsets after use of the function +}; + +#endif diff --git a/includes/live555/liveMedia/RawVideoRTPSource.hh b/includes/live555/liveMedia/RawVideoRTPSource.hh new file mode 100644 index 0000000..f3f70e7 --- /dev/null +++ b/includes/live555/liveMedia/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-2024 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 LIVEMEDIA_API 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/includes/live555/liveMedia/SIPClient.hh b/includes/live555/liveMedia/SIPClient.hh new file mode 100644 index 0000000..15b7aa9 --- /dev/null +++ b/includes/live555/liveMedia/SIPClient.hh @@ -0,0 +1,150 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic SIP client +// C++ header + +#ifndef _SIP_CLIENT_HH +#define _SIP_CLIENT_HH + +#ifndef _MEDIA_SESSION_HH +#include "MediaSession.hh" +#endif +#ifndef _NET_ADDRESS_HH +#include "NetAddress.hh" +#endif +#ifndef _DIGEST_AUTHENTICATION_HH +#include "DigestAuthentication.hh" +#endif + +// Possible states in the "INVITE" transition diagram (RFC 3261, Figure 5) +enum inviteClientState { Calling, Proceeding, Completed, Terminated }; + +class LIVEMEDIA_API SIPClient: public Medium { +public: + static SIPClient* createNew(UsageEnvironment& env, + unsigned char desiredAudioRTPPayloadFormat, + char const* mimeSubtype = NULL, + int verbosityLevel = 0, + char const* applicationName = NULL); + + void setProxyServer(struct sockaddr_storage const& proxyServerAddress, + portNumBits proxyServerPortNum); + + void setClientStartPortNum(portNumBits clientStartPortNum) { + fClientStartPortNum = clientStartPortNum; + } + + char* invite(char const* url, Authenticator* authenticator = NULL); + // Issues a SIP "INVITE" command + // Returns the session SDP description if this command succeeds + char* inviteWithPassword(char const* url, + char const* username, char const* password); + // Uses "invite()" to do an "INVITE" - first + // without using "password", then (if we get an Unauthorized + // response) with an authentication response computed from "password" + + Boolean sendACK(); // on current call + Boolean sendBYE(); // on current call + + static Boolean parseSIPURL(UsageEnvironment& env, char const* url, + NetAddress& address, portNumBits& portNum); + // (ignores any "[:]@" in "url") + static Boolean parseSIPURLUsernamePassword(char const* url, + char*& username, + char*& password); + char const* getInviteSdpReply() const { return fInviteSDPDescriptionReturned; } + + void setUserAgentString(char const* userAgentName); + // sets an alternative string to be used in SIP "User-Agent:" headers + +protected: + virtual ~SIPClient(); + +private: + SIPClient(UsageEnvironment& env, + unsigned char desiredAudioRTPPayloadFormat, + char const* mimeSubtype, + int verbosityLevel, + char const* applicationName); + // called only by createNew(); + + void reset(); + + // Routines used to implement invite*(): + char* invite1(Authenticator* authenticator); + Boolean processURL(char const* url); + Boolean sendINVITE(); + static void inviteResponseHandler(void* clientData, int mask); + void doInviteStateMachine(unsigned responseCode); + void doInviteStateTerminated(unsigned responseCode); + TaskToken fTimerA, fTimerB, fTimerD; + static void timerAHandler(void* clientData); + static void timerBHandler(void* clientData); + static void timerDHandler(void* clientData); + unsigned const fT1; // in microseconds + unsigned fTimerALen; // in microseconds; initially fT1, then doubles + unsigned fTimerACount; + + // Routines used to implement all commands: + char* createAuthenticatorString(Authenticator const* authenticator, + char const* cmd, char const* url); + Boolean sendRequest(char const* requestString, unsigned requestLength); + unsigned getResponseCode(); + unsigned getResponse(char*& responseBuffer, unsigned responseBufferSize); + Boolean parseResponseCode(char const* line, unsigned& responseCode); + +private: + // Set for all calls: + unsigned char fDesiredAudioRTPPayloadFormat; + char* fMIMESubtype; + unsigned fMIMESubtypeSize; + int fVerbosityLevel; + unsigned fCSeq; // sequence number, used in consecutive requests + char const* fApplicationName; + unsigned fApplicationNameSize; + char const* fOurAddressStr; + unsigned fOurAddressStrSize; + portNumBits fOurPortNum; + Groupsock* fOurSocket; + char* fUserAgentHeaderStr; + unsigned fUserAgentHeaderStrLen; + + // Set for each call: + char const* fURL; + unsigned fURLSize; + struct sockaddr_storage fServerAddress; + Boolean fServerAddressIsSet; + portNumBits fServerPortNum; // in host order + portNumBits fClientStartPortNum; // in host order + unsigned fCallId, fFromTag; // set by us + char const* fToTagStr; // set by the responder + unsigned fToTagStrSize; + Authenticator fValidAuthenticator; + char const* fUserName; // 'user' name used in "From:" & "Contact:" lines + unsigned fUserNameSize; + + char* fInviteSDPDescription; + char* fInviteSDPDescriptionReturned; + char* fInviteCmd; + unsigned fInviteCmdSize; + Authenticator* fWorkingAuthenticator; + inviteClientState fInviteClientState; + char fEventLoopStopFlag; +}; + +#endif diff --git a/includes/live555/liveMedia/SRTPCryptographicContext.hh b/includes/live555/liveMedia/SRTPCryptographicContext.hh new file mode 100644 index 0000000..c465b2b --- /dev/null +++ b/includes/live555/liveMedia/SRTPCryptographicContext.hh @@ -0,0 +1,152 @@ +/********** +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 +**********/ +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. +// The SRTP 'Cryptographic Context', used in all of our uses of SRTP. +// Definition + +#ifndef _SRTP_CRYPTOGRAPHIC_CONTEXT_HH +#define _SRTP_CRYPTOGRAPHIC_CONTEXT_HH + +#ifndef _MIKEY_HH +#include "MIKEY.hh" +#endif + +class LIVEMEDIA_API SRTPCryptographicContext { +public: + SRTPCryptographicContext(MIKEYState const& mikeyState); + virtual ~SRTPCryptographicContext(); + + // Authenticate (if necessary) and decrypt (if necessary) incoming SRTP and SRTCP packets. + // Returns True iff the packet is well-formed and authenticates OK. + // ("outPacketSize" will be <= "inPacketSize".) + Boolean processIncomingSRTPPacket(u_int8_t* buffer, unsigned inPacketSize, + unsigned& outPacketSize); + Boolean processIncomingSRTCPPacket(u_int8_t* buffer, unsigned inPacketSize, + unsigned& outPacketSize); + + // Encrypt (if necessary) and add an authentication tag (if necessary) to an outgoing + // RTP and RTCP packet. + // Returns True iff the packet is well-formed. + // ("outPacketSize" will be >= "inPacketSize"; there must be enough space at the end of + // "buffer" for the extra (4+10 bytes for SRTP; 4+4+10 bytes for SRTCP).) + Boolean processOutgoingSRTPPacket(u_int8_t* buffer, unsigned inPacketSize, + unsigned& outPacketSize); + Boolean processOutgoingSRTCPPacket(u_int8_t* buffer, unsigned inPacketSize, + unsigned& outPacketSize); + +#ifndef NO_OPENSSL +private: + // Definitions specific to the "SRTP_AES128_CM_HMAC_SHA1_80" ciphersuite. + // Later generalize to support more SRTP ciphersuites ##### +#define SRTP_CIPHER_KEY_LENGTH (128/8) // in bytes +#define SRTP_CIPHER_SALT_LENGTH (112/8) // in bytes +#define SRTP_MKI_LENGTH 4 // in bytes +#define SRTP_AUTH_KEY_LENGTH (160/8) // in bytes +#define SRTP_AUTH_TAG_LENGTH (80/8) // in bytes + + struct derivedKeys { + u_int8_t cipherKey[SRTP_CIPHER_KEY_LENGTH]; + u_int8_t salt[SRTP_CIPHER_SALT_LENGTH]; + u_int8_t authKey[SRTP_AUTH_KEY_LENGTH]; + }; + + struct allDerivedKeys { + derivedKeys srtp; + derivedKeys srtcp; + }; + + typedef enum { + label_srtp_encryption = 0x00, + label_srtp_msg_auth = 0x01, + label_srtp_salt = 0x02, + label_srtcp_encryption = 0x03, + label_srtcp_msg_auth = 0x04, + label_srtcp_salt = 0x05 + } SRTPKeyDerivationLabel; + + unsigned generateSRTPAuthenticationTag(u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int8_t* resultAuthenticationTag); + // returns the size of the resulting authentication tag + unsigned generateSRTCPAuthenticationTag(u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int8_t* resultAuthenticationTag); + // returns the size of the resulting authentication tag + + Boolean verifySRTPAuthenticationTag(u_int8_t* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int32_t roc, u_int8_t const* authenticationTag); + Boolean verifySRTCPAuthenticationTag(u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int8_t const* authenticationTag); + + void decryptSRTPPacket(u_int64_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes); + void decryptSRTCPPacket(u_int32_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes); + + void encryptSRTPPacket(u_int64_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes); + void encryptSRTCPPacket(u_int32_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes); + + unsigned generateAuthenticationTag(derivedKeys& keysToUse, + u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int8_t* resultAuthenticationTag); + // returns the size of the resulting authentication tag + // "resultAuthenticationTag" must point to an array of at least SRTP_AUTH_TAG_LENGTH + Boolean verifyAuthenticationTag(derivedKeys& keysToUse, + u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate, + u_int8_t const* authenticationTag); + + void cryptData(derivedKeys& keys, u_int64_t index, u_int32_t ssrc, + u_int8_t* data, unsigned numDataBytes); + + void performKeyDerivation(); + + void deriveKeysFromMaster(u_int8_t const* masterKey, u_int8_t const* salt, + allDerivedKeys& allKeysResult); + // used to implement "performKeyDerivation()" + void deriveSingleKey(u_int8_t const* masterKey, u_int8_t const* salt, + SRTPKeyDerivationLabel label, + unsigned resultKeyLength, u_int8_t* resultKey); + // used to implement "deriveKeysFromMaster()". + // ("resultKey" must be an existing buffer, of size >= "resultKeyLength") + +private: + MIKEYState const& fMIKEYState; + + // Master key + salt: + u_int8_t const* masterKeyPlusSalt() const { return fMIKEYState.keyData(); } + + u_int8_t const* masterKey() const { return &masterKeyPlusSalt()[0]; } + u_int8_t const* masterSalt() const { return &masterKeyPlusSalt()[SRTP_CIPHER_KEY_LENGTH]; } + + Boolean weEncryptSRTP() const { return fMIKEYState.encryptSRTP(); } + Boolean weEncryptSRTCP() const { return fMIKEYState.encryptSRTCP(); } + Boolean weAuthenticate() const { return fMIKEYState.useAuthentication(); } + u_int32_t MKI() const { return fMIKEYState.MKI(); } + + // Derived (i.e., session) keys: + allDerivedKeys fDerivedKeys; + + // State used for handling the reception of SRTP packets: + Boolean fHaveReceivedSRTPPackets; + u_int16_t fPreviousHighRTPSeqNum; + u_int32_t fReceptionROC; // rollover counter + + // State used for handling the sending of SRTP packets: + Boolean fHaveSentSRTPPackets; + u_int32_t fSendingROC; + + // State used for handling the sending of SRTCP packets: + u_int32_t fSRTCPIndex; +#endif +}; + +#endif diff --git a/includes/live555/liveMedia/ServerMediaSession.hh b/includes/live555/liveMedia/ServerMediaSession.hh new file mode 100644 index 0000000..ee1b26a --- /dev/null +++ b/includes/live555/liveMedia/ServerMediaSession.hh @@ -0,0 +1,200 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A data structure that represents a session that consists of +// potentially multiple (audio and/or video) sub-sessions +// (This data structure is used for media *streamers* - i.e., servers. +// For media receivers, use "MediaSession" instead.) +// C++ header + +#ifndef _SERVER_MEDIA_SESSION_HH +#define _SERVER_MEDIA_SESSION_HH + +#ifndef _RTCP_HH +#include "RTCP.hh" +#endif + +class ServerMediaSubsession; // forward + +class LIVEMEDIA_API ServerMediaSession: public Medium { +public: + static ServerMediaSession* createNew(UsageEnvironment& env, + char const* streamName = NULL, + char const* info = NULL, + char const* description = NULL, + Boolean isSSM = False, + char const* miscSDPLines = NULL); + + static Boolean lookupByName(UsageEnvironment& env, + char const* mediumName, + ServerMediaSession*& resultSession); + + char* generateSDPDescription(int addressFamily); // based on the entire session + // Note: The caller is responsible for freeing the returned string + + char const* streamName() const { return fStreamName; } + + Boolean addSubsession(ServerMediaSubsession* subsession); + unsigned numSubsessions() const { return fSubsessionCounter; } + + void testScaleFactor(float& scale); // sets "scale" to the actual supported scale + float duration() const; + // a result == 0 means an unbounded session (the default) + // a result < 0 means: subsession durations differ; the result is -(the largest). + // a result > 0 means: this is the duration of a bounded session + + virtual void noteLiveness(); + // called whenever a client - accessing this media - notes liveness. + // The default implementation does nothing, but subclasses can redefine this - e.g., if you + // want to remove long-unused "ServerMediaSession"s from the server. + + unsigned referenceCount() const { return fReferenceCount; } + void incrementReferenceCount() { ++fReferenceCount; } + void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; } + Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; } + + void deleteAllSubsessions(); + // Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state + // Note: If you have already added this "ServerMediaSession" to a server then, before calling this function, + // you must first close any client connections that use it, + // by calling "GenericMediaServer::closeAllClientSessionsForServerMediaSession()". + + Boolean streamingUsesSRTP; // by default, False + Boolean streamingIsEncrypted; // by default, False + +protected: + ServerMediaSession(UsageEnvironment& env, char const* streamName, + char const* info, char const* description, + Boolean isSSM, char const* miscSDPLines); + // called only by "createNew()" + + virtual ~ServerMediaSession(); + +private: // redefined virtual functions + virtual Boolean isServerMediaSession() const; + +private: + Boolean fIsSSM; + + // Linkage fields: + friend class ServerMediaSubsessionIterator; + ServerMediaSubsession* fSubsessionsHead; + ServerMediaSubsession* fSubsessionsTail; + unsigned fSubsessionCounter; + + char* fStreamName; + char* fInfoSDPString; + char* fDescriptionSDPString; + char* fMiscSDPLines; + struct timeval fCreationTime; + unsigned fReferenceCount; + Boolean fDeleteWhenUnreferenced; +}; + + +class LIVEMEDIA_API ServerMediaSubsessionIterator { +public: + ServerMediaSubsessionIterator(ServerMediaSession& session); + virtual ~ServerMediaSubsessionIterator(); + + ServerMediaSubsession* next(); // NULL if none + void reset(); + +private: + ServerMediaSession& fOurSession; + ServerMediaSubsession* fNextPtr; +}; + + +class LIVEMEDIA_API ServerMediaSubsession: public Medium { +public: + unsigned trackNumber() const { return fTrackNumber; } + char const* trackId(); + virtual char const* sdpLines(int addressFamily) = 0; + virtual void getStreamParameters(unsigned clientSessionId, // in + struct sockaddr_storage const& clientAddress, // in + Port const& clientRTPPort, // in + Port const& clientRTCPPort, // in + int tcpSocketNum, // in (-1 means use UDP, not TCP) + unsigned char rtpChannelId, // in (used if TCP) + unsigned char rtcpChannelId, // in (used if TCP) + TLSState* tlsState, // in (used if TCP) + struct sockaddr_storage& destinationAddress, // in out + u_int8_t& destinationTTL, // in out + Boolean& isMulticast, // out + Port& serverRTPPort, // out + Port& serverRTCPPort, // out + void*& streamToken // out + ) = 0; + virtual void startStream(unsigned clientSessionId, void* streamToken, + TaskFunc* rtcpRRHandler, + void* rtcpRRHandlerClientData, + unsigned short& rtpSeqNum, + unsigned& rtpTimestamp, + ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler, + void* serverRequestAlternativeByteHandlerClientData) = 0; + virtual void pauseStream(unsigned clientSessionId, void* streamToken); + virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, + double streamDuration, u_int64_t& numBytes); + // This routine is used to seek by relative (i.e., NPT) time. + // "streamDuration", if >0.0, specifies how much data to stream, past "seekNPT". (If <=0.0, all remaining data is streamed.) + // "numBytes" returns the size (in bytes) of the data to be streamed, or 0 if unknown or unlimited. + virtual void seekStream(unsigned clientSessionId, void* streamToken, char*& absStart, char*& absEnd); + // This routine is used to seek by 'absolute' time. + // "absStart" should be a string of the form "YYYYMMDDTHHMMSSZ" or "YYYYMMDDTHHMMSS.Z". + // "absEnd" should be either NULL (for no end time), or a string of the same form as "absStart". + // These strings may be modified in-place, or can be reassigned to a newly-allocated value (after delete[]ing the original). + virtual void nullSeekStream(unsigned clientSessionId, void* streamToken, + double streamEndTime, u_int64_t& numBytes); + // Called whenever we're handling a "PLAY" command without a specified start time. + virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale); + virtual float getCurrentNPT(void* streamToken); + virtual FramedSource* getStreamSource(void* streamToken); + virtual void getRTPSinkandRTCP(void* streamToken, + RTPSink*& rtpSink, RTCPInstance*& rtcp) = 0; + // Returns pointers to the "RTPSink" and "RTCPInstance" objects for "streamToken". + // (This can be useful if you want to get the associated 'Groupsock' objects, for example.) + // You must not delete these objects, or start/stop playing them; instead, that is done + // using the "startStream()" and "deleteStream()" functions. + virtual void deleteStream(unsigned clientSessionId, void*& streamToken); + + virtual void testScaleFactor(float& scale); // sets "scale" to the actual supported scale + virtual float duration() const; + // returns 0 for an unbounded session (the default) + // returns > 0 for a bounded session + virtual void getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime) const; + // Subclasses can reimplement this iff they support seeking by 'absolute' time. + +protected: // we're a virtual base class + ServerMediaSubsession(UsageEnvironment& env); + virtual ~ServerMediaSubsession(); + + char const* rangeSDPLine() const; + // returns a string to be delete[]d + + ServerMediaSession* fParentSession; + +private: + friend class ServerMediaSession; + friend class ServerMediaSubsessionIterator; + ServerMediaSubsession* fNext; + + unsigned fTrackNumber; // within an enclosing ServerMediaSession + char const* fTrackId; +}; + +#endif diff --git a/includes/live555/liveMedia/SimpleRTPSink.hh b/includes/live555/liveMedia/SimpleRTPSink.hh new file mode 100644 index 0000000..fd8ff8e --- /dev/null +++ b/includes/live555/liveMedia/SimpleRTPSink.hh @@ -0,0 +1,76 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A simple RTP sink that packs frames into each outgoing +// packet, without any fragmentation or special headers. +// C++ header + +#ifndef _SIMPLE_RTP_SINK_HH +#define _SIMPLE_RTP_SINK_HH + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#include "MultiFramedRTPSink.hh" +#endif + +class LIVEMEDIA_API SimpleRTPSink: public MultiFramedRTPSink { +public: + static SimpleRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* sdpMediaTypeString, + char const* rtpPayloadFormatName, + unsigned numChannels = 1, + Boolean allowMultipleFramesPerPacket = True, + Boolean doNormalMBitRule = True); + // "doNormalMBitRule" means: If the medium (i.e., "sdpMediaTypeString") is other than "audio", set the RTP "M" bit + // on each outgoing packet iff it contains the last (or only) fragment of a frame. + // Otherwise (i.e., if "doNormalMBitRule" is False, or the medium is "audio"), leave the "M" bit unset. + + void setMBitOnNextPacket() { fSetMBitOnNextPacket = True; } // hack for optionally setting the RTP 'M' bit from outside the class + +protected: + SimpleRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* sdpMediaTypeString, + char const* rtpPayloadFormatName, + unsigned numChannels, + Boolean allowMultipleFramesPerPacket, + Boolean doNormalMBitRule); + // called only by createNew() + + virtual ~SimpleRTPSink(); + +protected: // redefined virtual functions + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual char const* sdpMediaType() const; + +private: + char const* fSDPMediaTypeString; + Boolean fAllowMultipleFramesPerPacket; + Boolean fSetMBitOnLastFrames, fSetMBitOnNextPacket; +}; + +#endif diff --git a/includes/live555/liveMedia/SimpleRTPSource.hh b/includes/live555/liveMedia/SimpleRTPSource.hh new file mode 100644 index 0000000..25d90ef --- /dev/null +++ b/includes/live555/liveMedia/SimpleRTPSource.hh @@ -0,0 +1,65 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A RTP source for a simple RTP payload format that +// - doesn't have any special headers following the RTP header +// (if necessary, the "offset" parameter can be used to specify a +// special header that we just skip over) +// - doesn't have any special framing apart from the packet data itself +// C++ header + +#ifndef _SIMPLE_RTP_SOURCE_HH +#define _SIMPLE_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API SimpleRTPSource: public MultiFramedRTPSource { +public: + static SimpleRTPSource* createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* mimeTypeString, + unsigned offset = 0, + Boolean doNormalMBitRule = True); + // "doNormalMBitRule" means: If the medium is not audio, use the RTP "M" + // bit on each incoming packet to indicate the last (or only) fragment + // of a frame. Otherwise (i.e., if "doNormalMBitRule" is False, or the medium is "audio"), the "M" bit is ignored. + +protected: + SimpleRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency, + char const* mimeTypeString, unsigned offset, + Boolean doNormalMBitRule); + // called only by createNew(), or by subclass constructors + virtual ~SimpleRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + char const* fMIMEtypeString; + unsigned fOffset; + Boolean fUseMBitForFrameEnd; +}; + +#endif diff --git a/includes/live555/liveMedia/StreamReplicator.hh b/includes/live555/liveMedia/StreamReplicator.hh new file mode 100644 index 0000000..70e187e --- /dev/null +++ b/includes/live555/liveMedia/StreamReplicator.hh @@ -0,0 +1,84 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// An class that can be used to create (possibly multiple) 'replicas' of an incoming stream. +// C++ header + +#ifndef _STREAM_REPLICATOR_HH +#define _STREAM_REPLICATOR_HH + +#ifndef _FRAMED_SOURCE_HH +#include "FramedSource.hh" +#endif + +class StreamReplica; // forward + +class LIVEMEDIA_API StreamReplicator: public Medium { +public: + static StreamReplicator* createNew(UsageEnvironment& env, FramedSource* inputSource, Boolean deleteWhenLastReplicaDies = True); + // If "deleteWhenLastReplicaDies" is True (the default), then the "StreamReplicator" object is deleted when (and only when) + // all replicas have been deleted. (In this case, you must *not* call "Medium::close()" on the "StreamReplicator" object, + // unless you never created any replicas from it to begin with.) + // If "deleteWhenLastReplicaDies" is False, then the "StreamReplicator" object remains in existence, even when all replicas + // have been deleted. (This allows you to create new replicas later, if you wish.) In this case, you delete the + // "StreamReplicator" object by calling "Medium::close()" on it - but you must do so only when "numReplicas()" returns 0. + + FramedSource* createStreamReplica(); + + unsigned numReplicas() const { return fNumReplicas; } + + FramedSource* inputSource() const { return fInputSource; } + + // Call before destruction if you want to prevent the destructor from closing the input source + void detachInputSource() { fInputSource = NULL; } + +protected: + StreamReplicator(UsageEnvironment& env, FramedSource* inputSource, Boolean deleteWhenLastReplicaDies); + // called only by "createNew()" + virtual ~StreamReplicator(); + +private: + // Routines called by replicas to implement frame delivery, and the stopping/restarting/deletion of replicas: + friend class StreamReplica; + void getNextFrame(StreamReplica* replica); + void deactivateStreamReplica(StreamReplica* replica); + void removeStreamReplica(StreamReplica* replica); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, + struct timeval presentationTime, unsigned durationInMicroseconds); + + static void onSourceClosure(void* clientData); + void onSourceClosure(); + + void deliverReceivedFrame(); + +private: + FramedSource* fInputSource; + Boolean fDeleteWhenLastReplicaDies, fInputSourceHasClosed; + unsigned fNumReplicas, fNumActiveReplicas, fNumDeliveriesMadeSoFar; + int fFrameIndex; // 0 or 1; used to figure out if a replica is requesting the current frame, or the next frame + + StreamReplica* fPrimaryReplica; // the first replica that requests each frame. We use its buffer when copying to the others. + StreamReplica* fReplicasAwaitingCurrentFrame; // other than the 'primary' replica + StreamReplica* fReplicasAwaitingNextFrame; // replicas that have already received the current frame, and have asked for the next +}; +#endif diff --git a/includes/live555/liveMedia/T140TextRTPSink.hh b/includes/live555/liveMedia/T140TextRTPSink.hh new file mode 100644 index 0000000..2ee23df --- /dev/null +++ b/includes/live555/liveMedia/T140TextRTPSink.hh @@ -0,0 +1,103 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for T.140 text (RFC 2793) +// C++ header + +#ifndef _T140_TEXT_RTP_SINK_HH +#define _T140_TEXT_RTP_SINK_HH + +#ifndef _TEXT_RTP_SINK_HH +#include "TextRTPSink.hh" +#endif +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +class T140IdleFilter; + +class LIVEMEDIA_API T140TextRTPSink: public TextRTPSink { +public: + static T140TextRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + +protected: + T140TextRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + // called only by createNew() + + virtual ~T140TextRTPSink(); + +protected: // redefined virtual functions: + virtual Boolean continuePlaying(); + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + +protected: + T140IdleFilter* fOurIdleFilter; + Boolean fAreInIdlePeriod; +}; + + +////////// T140IdleFilter definition ////////// + +// Because the T.140 text RTP payload format specification recommends that (empty) RTP packets be sent during 'idle periods' +// when no new text is available, we implement "T140TextRTPSink" using a separate "T140IdleFilter" class - sitting in front +// - that delivers, to the "T140TextRTPSink", a continuous sequence of (possibly) empty frames. +// (Note: This class should be used only by "T140TextRTPSink", or a subclass.) + +class LIVEMEDIA_API T140IdleFilter: public FramedFilter { +public: + T140IdleFilter(UsageEnvironment& env, FramedSource* inputSource); + virtual ~T140IdleFilter(); + +private: // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + + static void handleIdleTimeout(void* clientData); + void handleIdleTimeout(); + + void deliverFromBuffer(); + void deliverEmptyFrame(); + + static void onSourceClosure(void* clientData); + void onSourceClosure(); + +private: + TaskToken fIdleTimerTask; + unsigned fBufferSize, fNumBufferedBytes; + char* fBuffer; + unsigned fBufferedNumTruncatedBytes; // a count of truncated bytes from the upstream + struct timeval fBufferedDataPresentationTime; + unsigned fBufferedDataDurationInMicroseconds; +}; + +#endif diff --git a/includes/live555/liveMedia/TLSState.hh b/includes/live555/liveMedia/TLSState.hh new file mode 100644 index 0000000..c5c9658 --- /dev/null +++ b/includes/live555/liveMedia/TLSState.hh @@ -0,0 +1,100 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// State encapsulating a TLS connection +// C++ header + +#ifndef _TLS_STATE_HH +#define _TLS_STATE_HH + +#ifndef _NET_COMMON_H +#include "NetCommon.h" +#endif +#ifndef _BOOLEAN_HH +#include "Boolean.hh" +#endif +#ifndef _USAGE_ENVIRONMENT_HH +#include "UsageEnvironment.hh" +#endif +#ifndef NO_OPENSSL +#include +#endif + +class LIVEMEDIA_API TLSState { +public: + Boolean isNeeded; + + int write(const char* data, unsigned count); + int read(u_int8_t* buffer, unsigned bufferSize); + + void nullify(); // clear the state so that the destructor will have no effect + +protected: // we're an abstract base class + TLSState(); + virtual ~TLSState(); + +#ifndef NO_OPENSSL + void initLibrary(); + void reset(); + +protected: + Boolean fHasBeenSetup; + SSL_CTX* fCtx; + SSL* fCon; +#endif +}; + +class LIVEMEDIA_API ClientTLSState: public TLSState { +public: + ClientTLSState(class RTSPClient& client); + virtual ~ClientTLSState(); + + int connect(int socketNum); // returns: <0 (error), 0 (pending), >0 (success) + +#ifndef NO_OPENSSL +private: + Boolean setup(int socketNum); + +private: + class RTSPClient& fClient; +#endif +}; + +class LIVEMEDIA_API ServerTLSState: public TLSState { +public: + ServerTLSState(UsageEnvironment& env); + virtual ~ServerTLSState(); + + void setCertificateAndPrivateKeyFileNames(char const* certFileName, char const* privKeyFileName); + void assignStateFrom(ServerTLSState const& from); + + int accept(int socketNum); // returns: <0 (error), 0 (pending), >0 (success) + + Boolean tlsAcceptIsNeeded; + +#ifndef NO_OPENSSL +private: + Boolean setup(int socketNum); + +private: + UsageEnvironment& fEnv; + char const* fCertificateFileName; + char const* fPrivateKeyFileName; +#endif +}; + +#endif diff --git a/includes/live555/liveMedia/TextRTPSink.hh b/includes/live555/liveMedia/TextRTPSink.hh new file mode 100644 index 0000000..033b004 --- /dev/null +++ b/includes/live555/liveMedia/TextRTPSink.hh @@ -0,0 +1,41 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic RTP sink for text codecs (abstract base class) +// C++ header + +#ifndef _TEXT_RTP_SINK_HH +#define _TEXT_RTP_SINK_HH + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#include "MultiFramedRTPSink.hh" +#endif + +class LIVEMEDIA_API TextRTPSink: public MultiFramedRTPSink { +protected: + TextRTPSink(UsageEnvironment& env, + Groupsock* rtpgs, unsigned char rtpPayloadType, + unsigned rtpTimestampFrequency, + char const* rtpPayloadFormatName); + // (we're an abstract base class) + virtual ~TextRTPSink(); + +private: // redefined virtual functions: + virtual char const* sdpMediaType() const; +}; + +#endif diff --git a/includes/live555/liveMedia/TheoraVideoRTPSink.hh b/includes/live555/liveMedia/TheoraVideoRTPSink.hh new file mode 100644 index 0000000..c71f687 --- /dev/null +++ b/includes/live555/liveMedia/TheoraVideoRTPSink.hh @@ -0,0 +1,72 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for Theora video +// C++ header + +#ifndef _THEORA_VIDEO_RTP_SINK_HH +#define _THEORA_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API TheoraVideoRTPSink: public VideoRTPSink { +public: + static TheoraVideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, + // The following headers provide the 'configuration' information, for the SDP description: + u_int8_t* identificationHeader, unsigned identificationHeaderSize, + u_int8_t* commentHeader, unsigned commentHeaderSize, + u_int8_t* setupHeader, unsigned setupHeaderSize, + u_int32_t identField = 0xFACADE); + + static TheoraVideoRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, + char const* configStr); + // an optional variant of "createNew()" that takes a Base-64-encoded 'configuration' string, + // rather than the raw configuration headers as parameter. + +protected: + TheoraVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, + u_int8_t* identificationHeader, unsigned identificationHeaderSize, + u_int8_t* commentHeader, unsigned commentHeaderSize, + u_int8_t* setupHeader, unsigned setupHeaderSize, + u_int32_t identField); + // called only by createNew() + + virtual ~TheoraVideoRTPSink(); + +private: // redefined virtual functions: + virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; + +private: + u_int32_t fIdent; // "Ident" field used by this stream. (Only the low 24 bits of this are used.) + char* fFmtpSDPLine; +}; + +#endif diff --git a/includes/live555/liveMedia/TheoraVideoRTPSource.hh b/includes/live555/liveMedia/TheoraVideoRTPSource.hh new file mode 100644 index 0000000..d11c574 --- /dev/null +++ b/includes/live555/liveMedia/TheoraVideoRTPSource.hh @@ -0,0 +1,53 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Theora Video Audio RTP Sources +// C++ header + +#ifndef _THEORA_VIDEO_RTP_SOURCE_HH +#define _THEORA_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API TheoraVideoRTPSource: public MultiFramedRTPSource { +public: + static TheoraVideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat); + + u_int32_t curPacketIdent() const { return fCurPacketIdent; } // The current "Ident" field; only the low-order 24 bits are used + +protected: + TheoraVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat); + // called only by createNew() + + virtual ~TheoraVideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + u_int32_t fCurPacketIdent; // only the low-order 24 bits are used +}; + +#endif diff --git a/includes/live555/liveMedia/VP8VideoRTPSink.hh b/includes/live555/liveMedia/VP8VideoRTPSink.hh new file mode 100644 index 0000000..628283c --- /dev/null +++ b/includes/live555/liveMedia/VP8VideoRTPSink.hh @@ -0,0 +1,50 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for VP8 video +// C++ header + +#ifndef _VP8_VIDEO_RTP_SINK_HH +#define _VP8_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API VP8VideoRTPSink: public VideoRTPSink { +public: + static VP8VideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + +protected: + VP8VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + // called only by createNew() + + virtual ~VP8VideoRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/VP8VideoRTPSource.hh b/includes/live555/liveMedia/VP8VideoRTPSource.hh new file mode 100644 index 0000000..76561d3 --- /dev/null +++ b/includes/live555/liveMedia/VP8VideoRTPSource.hh @@ -0,0 +1,50 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// VP8 Video RTP Sources +// C++ header + +#ifndef _VP8_VIDEO_RTP_SOURCE_HH +#define _VP8_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API VP8VideoRTPSource: public MultiFramedRTPSource { +public: + static VP8VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + +protected: + VP8VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + + virtual ~VP8VideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/VP9VideoRTPSink.hh b/includes/live555/liveMedia/VP9VideoRTPSink.hh new file mode 100644 index 0000000..bc93e86 --- /dev/null +++ b/includes/live555/liveMedia/VP9VideoRTPSink.hh @@ -0,0 +1,50 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for VP9 video +// C++ header + +#ifndef _VP9_VIDEO_RTP_SINK_HH +#define _VP9_VIDEO_RTP_SINK_HH + +#ifndef _VIDEO_RTP_SINK_HH +#include "VideoRTPSink.hh" +#endif + +class LIVEMEDIA_API VP9VideoRTPSink: public VideoRTPSink { +public: + static VP9VideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + +protected: + VP9VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat); + // called only by createNew() + + virtual ~VP9VideoRTPSink(); + +private: // redefined virtual functions: + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual + Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; +}; + +#endif diff --git a/includes/live555/liveMedia/VP9VideoRTPSource.hh b/includes/live555/liveMedia/VP9VideoRTPSource.hh new file mode 100644 index 0000000..f25f36c --- /dev/null +++ b/includes/live555/liveMedia/VP9VideoRTPSource.hh @@ -0,0 +1,50 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// VP9 Video RTP Sources +// C++ header + +#ifndef _VP9_VIDEO_RTP_SOURCE_HH +#define _VP9_VIDEO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API VP9VideoRTPSource: public MultiFramedRTPSource { +public: + static VP9VideoRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency = 90000); + +protected: + VP9VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + + virtual ~VP9VideoRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; +}; + +#endif diff --git a/includes/live555/liveMedia/VideoRTPSink.hh b/includes/live555/liveMedia/VideoRTPSink.hh new file mode 100644 index 0000000..926eae5 --- /dev/null +++ b/includes/live555/liveMedia/VideoRTPSink.hh @@ -0,0 +1,41 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A generic RTP sink for video codecs (abstract base class) +// C++ header + +#ifndef _VIDEO_RTP_SINK_HH +#define _VIDEO_RTP_SINK_HH + +#ifndef _MULTI_FRAMED_RTP_SINK_HH +#include "MultiFramedRTPSink.hh" +#endif + +class LIVEMEDIA_API VideoRTPSink: public MultiFramedRTPSink { +protected: + VideoRTPSink(UsageEnvironment& env, + Groupsock* rtpgs, unsigned char rtpPayloadType, + unsigned rtpTimestampFrequency, + char const* rtpPayloadFormatName); + // (we're an abstract base class) + virtual ~VideoRTPSink(); + +private: // redefined virtual functions: + virtual char const* sdpMediaType() const; +}; + +#endif diff --git a/includes/live555/liveMedia/VorbisAudioRTPSink.hh b/includes/live555/liveMedia/VorbisAudioRTPSink.hh new file mode 100644 index 0000000..d7090d2 --- /dev/null +++ b/includes/live555/liveMedia/VorbisAudioRTPSink.hh @@ -0,0 +1,85 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// RTP sink for Vorbis audio +// C++ header + +#ifndef _VORBIS_AUDIO_RTP_SINK_HH +#define _VORBIS_AUDIO_RTP_SINK_HH + +#ifndef _AUDIO_RTP_SINK_HH +#include "AudioRTPSink.hh" +#endif + +class LIVEMEDIA_API VorbisAudioRTPSink: public AudioRTPSink { +public: + static VorbisAudioRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, + u_int32_t rtpTimestampFrequency, unsigned numChannels, + // The following headers provide the 'configuration' information, for the SDP description: + u_int8_t* identificationHeader, unsigned identificationHeaderSize, + u_int8_t* commentHeader, unsigned commentHeaderSize, + u_int8_t* setupHeader, unsigned setupHeaderSize, + u_int32_t identField = 0xFACADE); + + static VorbisAudioRTPSink* + createNew(UsageEnvironment& env, Groupsock* RTPgs, u_int8_t rtpPayloadFormat, + u_int32_t rtpTimestampFrequency, unsigned numChannels, + char const* configStr); + // an optional variant of "createNew()" that takes a Base-64-encoded 'configuration' string, + // rather than the raw configuration headers as parameter. + +protected: + VorbisAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, + u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, unsigned numChannels, + u_int8_t* identificationHeader, unsigned identificationHeaderSize, + u_int8_t* commentHeader, unsigned commentHeaderSize, + u_int8_t* setupHeader, unsigned setupHeaderSize, + u_int32_t identField); + // called only by createNew() + + virtual ~VorbisAudioRTPSink(); + +private: // redefined virtual functions: + virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line + + virtual void doSpecialFrameHandling(unsigned fragmentationOffset, + unsigned char* frameStart, + unsigned numBytesInFrame, + struct timeval framePresentationTime, + unsigned numRemainingBytes); + virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, + unsigned numBytesInFrame) const; + virtual unsigned specialHeaderSize() const; + virtual unsigned frameSpecificHeaderSize() const; + +private: + u_int32_t fIdent; // "Ident" field used by this stream. (Only the low 24 bits of this are used.) + char* fFmtpSDPLine; +}; + + +// A general function used by both "VorbisAudioRTPSink" and "TheoraVideoRTPSink" to construct +// a Base64-encoded 'config' string (for SDP) from "identification", "comment", "setup" headers. +// (Note: The result string was heap-allocated, and the caller should delete[] it afterwards.) + +LIVEMEDIA_API char* generateVorbisOrTheoraConfigStr(u_int8_t* identificationHeader, unsigned identificationHeaderSize, + u_int8_t* commentHeader, unsigned commentHeaderSize, + u_int8_t* setupHeader, unsigned setupHeaderSize, + u_int32_t identField); + +#endif diff --git a/includes/live555/liveMedia/VorbisAudioRTPSource.hh b/includes/live555/liveMedia/VorbisAudioRTPSource.hh new file mode 100644 index 0000000..01513bf --- /dev/null +++ b/includes/live555/liveMedia/VorbisAudioRTPSource.hh @@ -0,0 +1,66 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Vorbis Audio RTP Sources +// C++ header + +#ifndef _VORBIS_AUDIO_RTP_SOURCE_HH +#define _VORBIS_AUDIO_RTP_SOURCE_HH + +#ifndef _MULTI_FRAMED_RTP_SOURCE_HH +#include "MultiFramedRTPSource.hh" +#endif + +class LIVEMEDIA_API VorbisAudioRTPSource: public MultiFramedRTPSource { +public: + static VorbisAudioRTPSource* + createNew(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + + u_int32_t curPacketIdent() const { return fCurPacketIdent; } // The current "Ident" field; only the low-order 24 bits are used + +protected: + VorbisAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, + unsigned char rtpPayloadFormat, + unsigned rtpTimestampFrequency); + // called only by createNew() + + virtual ~VorbisAudioRTPSource(); + +protected: + // redefined virtual functions: + virtual Boolean processSpecialHeader(BufferedPacket* packet, + unsigned& resultSpecialHeaderSize); + virtual char const* MIMEtype() const; + +private: + u_int32_t fCurPacketIdent; // only the low-order 24 bits are used +}; + +LIVEMEDIA_API void parseVorbisOrTheoraConfigStr(char const* configStr, + u_int8_t*& identificationHdr, unsigned& identificationHdrSize, + u_int8_t*& commentHdr, unsigned& commentHdrSize, + u_int8_t*& setupHdr, unsigned& setupHdrSize, + u_int32_t& identField); + // Returns (in each of the result parameters) unpacked Vorbis or Theora + // "identification", "comment", and "setup" headers that were specified in a + // "config" string (in the SDP description for a Vorbis/RTP or Theora/RTP stream). + // Each of the "*Hdr" result arrays are dynamically allocated by this routine, + // and must be delete[]d by the caller. + +#endif diff --git a/includes/live555/liveMedia/WAVAudioFileServerMediaSubsession.hh b/includes/live555/liveMedia/WAVAudioFileServerMediaSubsession.hh new file mode 100644 index 0000000..bf5308a --- /dev/null +++ b/includes/live555/liveMedia/WAVAudioFileServerMediaSubsession.hh @@ -0,0 +1,68 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s +// on demand, from an WAV audio file. +// C++ header + +#ifndef _WAV_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH +#define _WAV_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH + +#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH +#include "FileServerMediaSubsession.hh" +#endif + +class LIVEMEDIA_API WAVAudioFileServerMediaSubsession: public FileServerMediaSubsession{ +public: + static WAVAudioFileServerMediaSubsession* + createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, + Boolean convertToULaw = False); + // If "convertToULaw" is True, 16-bit audio streams are converted to + // 8-bit u-law audio prior to streaming. + +protected: + WAVAudioFileServerMediaSubsession(UsageEnvironment& env, char const* fileName, + Boolean reuseFirstSource, Boolean convertToULaw); + // called only by createNew(); + virtual ~WAVAudioFileServerMediaSubsession(); + +protected: // redefined virtual functions + virtual void seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes); + virtual void setStreamSourceScale(FramedSource* inputSource, float scale); + virtual void setStreamSourceDuration(FramedSource* inputSource, double streamDuration, u_int64_t& numBytes); + + virtual FramedSource* createNewStreamSource(unsigned clientSessionId, + unsigned& estBitrate); + virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, + unsigned char rtpPayloadTypeIfDynamic, + FramedSource* inputSource); + virtual void testScaleFactor(float& scale); + virtual float duration() const; + +protected: + Boolean fConvertToULaw; + + // The following parameters of the input stream are set after + // "createNewStreamSource" is called: + unsigned char fAudioFormat; + unsigned char fBitsPerSample; + unsigned fSamplingFrequency; + unsigned fNumChannels; + float fFileDuration; +}; + +#endif diff --git a/includes/live555/liveMedia/WAVAudioFileSource.hh b/includes/live555/liveMedia/WAVAudioFileSource.hh new file mode 100644 index 0000000..0a3eb88 --- /dev/null +++ b/includes/live555/liveMedia/WAVAudioFileSource.hh @@ -0,0 +1,86 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// A WAV audio file source +// NOTE: Samples are returned in little-endian order (the same order in which +// they were stored in the file). +// C++ header + +#ifndef _WAV_AUDIO_FILE_SOURCE_HH +#define _WAV_AUDIO_FILE_SOURCE_HH + +#ifndef _AUDIO_INPUT_DEVICE_HH +#include "AudioInputDevice.hh" +#endif + +typedef enum { + WA_PCM = 0x01, + WA_PCMA = 0x06, + WA_PCMU = 0x07, + WA_IMA_ADPCM = 0x11, + WA_UNKNOWN +} WAV_AUDIO_FORMAT; + + +class LIVEMEDIA_API WAVAudioFileSource: public AudioInputDevice { +public: + + static WAVAudioFileSource* createNew(UsageEnvironment& env, + char const* fileName); + + unsigned numPCMBytes() const; + void setScaleFactor(int scale); + void seekToPCMByte(unsigned byteNumber); + void limitNumBytesToStream(unsigned numBytesToStream); + // if "numBytesToStream" is >0, then we limit the stream to that number of bytes, before treating it as EOF + + unsigned char getAudioFormat(); + +protected: + WAVAudioFileSource(UsageEnvironment& env, FILE* fid); + // called only by createNew() + + virtual ~WAVAudioFileSource(); + + static void fileReadableHandler(WAVAudioFileSource* source, int mask); + void doReadFromFile(); + +private: + // redefined virtual functions: + virtual void doGetNextFrame(); + virtual void doStopGettingFrames(); + virtual Boolean setInputPort(int portIndex); + virtual double getAverageLevel() const; + +protected: + unsigned fPreferredFrameSize; + +private: + FILE* fFid; + double fPlayTimePerSample; // useconds + Boolean fFidIsSeekable; + unsigned fLastPlayTime; // useconds + Boolean fHaveStartedReading; + unsigned fWAVHeaderSize; + unsigned fFileSize; + int fScaleFactor; + Boolean fLimitNumBytesToStream; + unsigned fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True + unsigned char fAudioFormat; +}; + +#endif diff --git a/includes/live555/liveMedia/export.h b/includes/live555/liveMedia/export.h new file mode 100644 index 0000000..4447473 --- /dev/null +++ b/includes/live555/liveMedia/export.h @@ -0,0 +1,30 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif // #ifdef __cplusplus + + +#if _WIN32 +# define LIVEMEDIA_EXPORT_API __declspec (dllexport) +# define LIVEMEDIA_IMPORT_API __declspec (dllimport) +#else // #ifndef _WIN32 +# define LIVEMEDIA_EXPORT_API __attribute__ ((visibility("default"))) +# define LIVEMEDIA_IMPORT_API __attribute__ ((visibility("default"))) +#endif // #if _WIN32 + + +#ifndef LIVEMEDIA_STATIC +# ifdef LIVEMEDIA_EXPORTS +# define LIVEMEDIA_API LIVEMEDIA_EXPORT_API +# else +# define LIVEMEDIA_API LIVEMEDIA_IMPORT_API +# endif // #ifdef LIVEMEDIA_EXPORTS +#else // #ifndef LIVEMEDIA_STATIC +# define LIVEMEDIA_API +#endif // #endif LIVEMEDIA_STATIC + + +#ifdef __cplusplus +} // extern "C" { +#endif // #ifdef __cplusplus diff --git a/includes/live555/liveMedia/liveMedia.hh b/includes/live555/liveMedia/liveMedia.hh new file mode 100644 index 0000000..90dae63 --- /dev/null +++ b/includes/live555/liveMedia/liveMedia.hh @@ -0,0 +1,137 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Inclusion of header files representing the interface +// for the entire library +// +// Programs that use the library can include this header file, +// instead of each of the individual media header files + +#ifndef _LIVEMEDIA_HH +#define _LIVEMEDIA_HH +#include "JPEG2000VideoRTPSource.hh" +#include "JPEG2000VideoRTPSink.hh" +//#include "JPEG2000VideoStreamFramer.hh" +//#include "JPEG2000VideoFileServerMediaSubsession.hh" +#include "MPEG1or2AudioRTPSink.hh" +#include "MP3ADURTPSink.hh" +#include "MPEG1or2VideoRTPSink.hh" +#include "MPEG4ESVideoRTPSink.hh" +#include "AMRAudioFileSink.hh" +#include "H264VideoFileSink.hh" +#include "H265VideoFileSink.hh" +#include "OggFileSink.hh" +#include "BasicUDPSink.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 "MPEG2TransportStreamFromPESSource.hh" +#include "MPEG2TransportStreamFromESSource.hh" +#include "MPEG2TransportStreamFramer.hh" +#include "ADTSAudioFileSource.hh" +#include "ADTSAudioStreamDiscreteFramer.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 "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 "RawVideoRTPSink.hh" +#include "MPEG1or2VideoStreamDiscreteFramer.hh" +#include "MPEG4VideoStreamDiscreteFramer.hh" +#include "DeviceSource.hh" +#include "AudioInputDevice.hh" +#include "WAVAudioFileSource.hh" +#include "StreamReplicator.hh" +#include "RTSPRegisterSender.hh" +#include "RTSPClient.hh" +#include "SIPClient.hh" +#include "QuickTimeFileSink.hh" +#include "QuickTimeGenericRTPSource.hh" +#include "AVIFileSink.hh" +#include "PassiveServerMediaSubsession.hh" +#include "MPEG4VideoFileServerMediaSubsession.hh" +#include "H264VideoFileServerMediaSubsession.hh" +#include "H265VideoFileServerMediaSubsession.hh" +#include "WAVAudioFileServerMediaSubsession.hh" +#include "AMRAudioFileServerMediaSubsession.hh" +#include "AMRAudioFileSource.hh" +#include "AMRAudioRTPSink.hh" +#include "T140TextRTPSink.hh" +#include "MP3AudioFileServerMediaSubsession.hh" +#include "MPEG1or2VideoFileServerMediaSubsession.hh" +#include "MPEG1or2FileServerDemux.hh" +#include "MPEG2TransportFileServerMediaSubsession.hh" +#include "H263plusVideoFileServerMediaSubsession.hh" +#include "ADTSAudioFileServerMediaSubsession.hh" +#include "DVVideoFileServerMediaSubsession.hh" +#include "AC3AudioFileServerMediaSubsession.hh" +#include "MPEG2TransportUDPServerMediaSubsession.hh" +#include "MatroskaFileServerDemux.hh" +#include "OggFileServerDemux.hh" +#include "MPEG2TransportStreamDemux.hh" +#include "ProxyServerMediaSession.hh" +#include "HLSSegmenter.hh" +#include "MPEG2TransportStreamAccumulator.hh" + +#endif diff --git a/includes/live555/liveMedia/liveMedia_version.hh b/includes/live555/liveMedia/liveMedia_version.hh new file mode 100644 index 0000000..3a9f7f6 --- /dev/null +++ b/includes/live555/liveMedia/liveMedia_version.hh @@ -0,0 +1,25 @@ +/********** +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 +**********/ +// Version information for the "liveMedia" library +// Copyright (c) 1996-2024 Live Networks, Inc. All rights reserved. + +#ifndef _LIVEMEDIA_VERSION_HH +#define _LIVEMEDIA_VERSION_HH + +#define LIVEMEDIA_LIBRARY_VERSION_STRING "2024.02.15" +#define LIVEMEDIA_LIBRARY_VERSION_INT 1707955200 + +#endif diff --git a/includes/live555/liveMedia/ourMD5.hh b/includes/live555/liveMedia/ourMD5.hh new file mode 100644 index 0000000..c0aa2ec --- /dev/null +++ b/includes/live555/liveMedia/ourMD5.hh @@ -0,0 +1,38 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Because MD5 may not be implemented (at least, with the same interface) on all systems, +// we have our own implementation. +// C++ header + +#ifndef _OUR_MD5_HH +#define _OUR_MD5_HH + +extern char* our_MD5Data(unsigned char const* data, unsigned dataSize, char* outputDigest); + // "outputDigest" must be either NULL (in which case this function returns a heap-allocated + // buffer, which should be later delete[]d by the caller), or else it must point to + // a (>=)33-byte buffer (which this function will also return). + +extern unsigned char* our_MD5DataRaw(unsigned char const* data, unsigned dataSize, + unsigned char* outputDigest); + // Like "ourMD5Data()", except that it returns the digest in 'raw' binary form, rather than + // as an ASCII hex string. + // "outputDigest" must be either NULL (in which case this function returns a heap-allocated + // buffer, which should be later delete[]d by the caller), or else it must point to + // a (>=)16-byte buffer (which this function will also return). + +#endif diff --git a/includes/live555/liveMedia/uLawAudioFilter.hh b/includes/live555/liveMedia/uLawAudioFilter.hh new file mode 100644 index 0000000..0bd576e --- /dev/null +++ b/includes/live555/liveMedia/uLawAudioFilter.hh @@ -0,0 +1,208 @@ +/********** +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-2024 Live Networks, Inc. All rights reserved. +// Filters for converting between raw PCM audio and uLaw +// C++ header + +#ifndef _ULAW_AUDIO_FILTER_HH +#define _ULAW_AUDIO_FILTER_HH + +#ifndef _FRAMED_FILTER_HH +#include "FramedFilter.hh" +#endif + +////////// 16-bit PCM (in various byte orderings) -> 8-bit u-Law ////////// + +class LIVEMEDIA_API uLawFromPCMAudioSource: public FramedFilter { +public: + static uLawFromPCMAudioSource* + createNew(UsageEnvironment& env, FramedSource* inputSource, + int byteOrdering = 0); + // "byteOrdering" == 0 => host order (the default) + // "byteOrdering" == 1 => little-endian order + // "byteOrdering" == 2 => network (i.e., big-endian) order + +protected: + uLawFromPCMAudioSource(UsageEnvironment& env, FramedSource* inputSource, + int byteOrdering); + // called only by createNew() + virtual ~uLawFromPCMAudioSource(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + int fByteOrdering; + unsigned char* fInputBuffer; + unsigned fInputBufferSize; +}; + + +////////// u-Law -> 16-bit PCM (in host order) ////////// + +class LIVEMEDIA_API PCMFromuLawAudioSource: public FramedFilter { +public: + static PCMFromuLawAudioSource* + createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + PCMFromuLawAudioSource(UsageEnvironment& env, + FramedSource* inputSource); + // called only by createNew() + virtual ~PCMFromuLawAudioSource(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + +private: + unsigned char* fInputBuffer; + unsigned fInputBufferSize; +}; + + +////////// 16-bit values (in host order) -> 16-bit network order ////////// + +class LIVEMEDIA_API NetworkFromHostOrder16: public FramedFilter { +public: + static NetworkFromHostOrder16* + createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + NetworkFromHostOrder16(UsageEnvironment& env, FramedSource* inputSource); + // called only by createNew() + virtual ~NetworkFromHostOrder16(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); +}; + + +////////// 16-bit values (in network order) -> 16-bit host order ////////// + +class LIVEMEDIA_API HostFromNetworkOrder16: public FramedFilter { +public: + static HostFromNetworkOrder16* + createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + HostFromNetworkOrder16(UsageEnvironment& env, FramedSource* inputSource); + // called only by createNew() + virtual ~HostFromNetworkOrder16(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); +}; + + +////////// 16-bit values: little-endian <-> big-endian ////////// + +class LIVEMEDIA_API EndianSwap16: public FramedFilter { +public: + static EndianSwap16* createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + EndianSwap16(UsageEnvironment& env, FramedSource* inputSource); + // called only by createNew() + virtual ~EndianSwap16(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); +}; + + +////////// 24-bit values: little-endian <-> big-endian ////////// + +class LIVEMEDIA_API EndianSwap24: public FramedFilter { +public: + static EndianSwap24* createNew(UsageEnvironment& env, FramedSource* inputSource); + +protected: + EndianSwap24(UsageEnvironment& env, FramedSource* inputSource); + // called only by createNew() + virtual ~EndianSwap24(); + +private: + // Redefined virtual functions: + virtual void doGetNextFrame(); + +private: + static void afterGettingFrame(void* clientData, unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); + void afterGettingFrame1(unsigned frameSize, + unsigned numTruncatedBytes, + struct timeval presentationTime, + unsigned durationInMicroseconds); +}; + +#endif diff --git a/includes/myws.hpp b/includes/myws.hpp new file mode 100644 index 0000000..5ce83c6 --- /dev/null +++ b/includes/myws.hpp @@ -0,0 +1,7 @@ + +#ifndef _MYWS +#define _MYWS + +extern int myws(int atgc, char **argv); + +#endif diff --git a/includes/nlohmann/adl_serializer.hpp b/includes/nlohmann/adl_serializer.hpp new file mode 100644 index 0000000..56a606c --- /dev/null +++ b/includes/nlohmann/adl_serializer.hpp @@ -0,0 +1,55 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @sa https://json.nlohmann.me/api/adl_serializer/ +template +struct adl_serializer +{ + /// @brief convert a JSON value to any value type + /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ + template + static auto from_json(BasicJsonType && j, TargetType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + -> decltype(::nlohmann::from_json(std::forward(j), val), void()) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /// @brief convert a JSON value to any value type + /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ + template + static auto from_json(BasicJsonType && j) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) + -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) + { + return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); + } + + /// @brief convert any value type to a JSON value + /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ + template + static auto to_json(BasicJsonType& j, TargetType && val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/byte_container_with_subtype.hpp b/includes/nlohmann/byte_container_with_subtype.hpp new file mode 100644 index 0000000..91382cd --- /dev/null +++ b/includes/nlohmann/byte_container_with_subtype.hpp @@ -0,0 +1,103 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // uint8_t, uint64_t +#include // tie +#include // move + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @brief an internal type for a backed binary type +/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + using container_type = BinaryType; + using subtype_type = std::uint64_t; + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + + /// @brief sets the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ + void set_subtype(subtype_type subtype_) noexcept + { + m_subtype = subtype_; + m_has_subtype = true; + } + + /// @brief return the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ + constexpr subtype_type subtype() const noexcept + { + return m_has_subtype ? m_subtype : static_cast(-1); + } + + /// @brief return whether the value has a subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /// @brief clears the binary subtype + /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + subtype_type m_subtype = 0; + bool m_has_subtype = false; +}; + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/abi_macros.hpp b/includes/nlohmann/detail/abi_macros.hpp new file mode 100644 index 0000000..f48b9eb --- /dev/null +++ b/includes/nlohmann/detail/abi_macros.hpp @@ -0,0 +1,100 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif diff --git a/includes/nlohmann/detail/conversions/from_json.hpp b/includes/nlohmann/detail/conversions/from_json.hpp new file mode 100644 index 0000000..aa2f0cb --- /dev/null +++ b/includes/nlohmann/detail/conversions/from_json.hpp @@ -0,0 +1,497 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + { + JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j)); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); + } +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + { + JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j)); + } + b = *j.template get_ptr(); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename StringType, + enable_if_t < + std::is_assignable::value + && is_detected_exact::value + && !std::is_same::value + && !is_json_ref::value, int > = 0 > +inline void from_json(const BasicJsonType& j, StringType& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + + s = *j.template get_ptr(); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +#if !JSON_DISABLE_ENUM_SERIALIZATION +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} +#endif // JSON_DISABLE_ENUM_SERIALIZATION + +// forward_list doesn't have an insert method +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + l.clear(); + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + l.resize(j.size()); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) +{ + arr = *j.template get_ptr(); +} + +template +auto from_json_array_impl(const BasicJsonType& j, std::array& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value, + int> = 0> +auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + j.template get(), + void()) +{ + using std::end; + + ConstructibleArrayType ret; + ret.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(ret, end(ret)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template::value, + int> = 0> +inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, + priority_tag<0> /*unused*/) +{ + using std::end; + + ConstructibleArrayType ret; + std::transform( + j.begin(), j.end(), std::inserter(ret, end(ret)), + [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get(), +void()) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + from_json_array_impl(j, arr, priority_tag<3> {}); +} + +template < typename BasicJsonType, typename T, std::size_t... Idx > +std::array from_json_inplace_array_impl(BasicJsonType&& j, + identity_tag> /*unused*/, index_sequence /*unused*/) +{ + return { { std::forward(j).at(Idx).template get()... } }; +} + +template < typename BasicJsonType, typename T, std::size_t N > +auto from_json(BasicJsonType&& j, identity_tag> tag) +-> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); +} + +template +inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) + { + JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j)); + } + + bin = *j.template get_ptr(); +} + +template::value, int> = 0> +inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); + } + + ConstructibleObjectType ret; + const auto* inner_object = j.template get_ptr(); + using value_type = typename ConstructibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(ret, ret.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); + obj = std::move(ret); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > +inline void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); + } +} + +template +std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) +{ + return std::make_tuple(std::forward(j).at(Idx).template get()...); +} + +template < typename BasicJsonType, class A1, class A2 > +std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) +{ + return {std::forward(j).at(0).template get(), + std::forward(j).at(1).template get()}; +} + +template +inline void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) +{ + p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); +} + +template +std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) +{ + return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) +{ + t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +auto from_json(BasicJsonType&& j, TupleRelated&& t) +-> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + + return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); +} + +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +template +inline void from_json(const BasicJsonType& j, std_fs::path& p) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); + } + p = *j.template get_ptr(); +} +#endif + +struct from_json_fn +{ + template + auto operator()(const BasicJsonType& j, T&& val) const + noexcept(noexcept(from_json(j, std::forward(val)))) + -> decltype(from_json(j, std::forward(val))) + { + return from_json(j, std::forward(val)); + } +}; + +} // namespace detail + +#ifndef JSON_HAS_CPP_17 +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +#endif +JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers) + detail::static_const::value; +#ifndef JSON_HAS_CPP_17 +} // namespace +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/conversions/to_chars.hpp b/includes/nlohmann/detail/conversions/to_chars.hpp new file mode 100644 index 0000000..e10741c --- /dev/null +++ b/includes/nlohmann/detail/conversions/to_chars.hpp @@ -0,0 +1,1118 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2009 Florian Loitsch +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const auto bits = static_cast(reinterpret_bits(value)); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + if (n >= 100000) + { + pow10 = 100000; + return 6; + } + if (n >= 10000) + { + pow10 = 10000; + return 5; + } + if (n >= 1000) + { + pow10 = 1000; + return 4; + } + if (n >= 100) + { + pow10 = 100; + return 3; + } + if (n >= 10) + { + pow10 = 10; + return 2; + } + + pow10 = 1; + return 1; +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10{}; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/conversions/to_json.hpp b/includes/nlohmann/detail/conversions/to_json.hpp new file mode 100644 index 0000000..e39b779 --- /dev/null +++ b/includes/nlohmann/detail/conversions/to_json.hpp @@ -0,0 +1,446 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // copy +#include // begin, end +#include // string +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +////////////////// +// constructors // +////////////////// + +/* + * Note all external_constructor<>::construct functions need to call + * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an + * allocated value (e.g., a string). See bug issue + * https://github.com/nlohmann/json/issues/2865 for more information. + */ + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::boolean; + j.m_data.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value = std::move(s); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::string; + j.m_data.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::binary; + j.m_data.m_value = typename BasicJsonType::binary_t(b); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::binary; + j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b)); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_float; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_unsigned; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::number_integer; + j.m_data.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = arr; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = std::move(arr); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value.array = j.template create(begin(arr), end(arr)); + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = value_t::array; + j.m_data.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_data.m_value.array->push_back(x); + j.set_parent(j.m_data.m_value.array->back()); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::array; + j.m_data.m_value = value_t::array; + j.m_data.m_value.array->resize(arr.size()); + if (arr.size() > 0) + { + std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin()); + } + j.set_parents(); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value = obj; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value = std::move(obj); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_data.m_value.destroy(j.m_data.m_type); + j.m_data.m_type = value_t::object; + j.m_data.m_value.object = j.template create(begin(obj), end(obj)); + j.set_parents(); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template < typename BasicJsonType, typename BoolRef, + enable_if_t < + ((std::is_same::reference, BoolRef>::value + && !std::is_same ::reference, typename BasicJsonType::boolean_t&>::value) + || (std::is_same::const_reference, BoolRef>::value + && !std::is_same ::const_reference>, + typename BasicJsonType::boolean_t >::value)) + && std::is_convertible::value, int > = 0 > +inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept +{ + external_constructor::construct(j, static_cast(b)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +#if !JSON_DISABLE_ENUM_SERIALIZATION +template::value, int> = 0> +inline void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} +#endif // JSON_DISABLE_ENUM_SERIALIZATION + +template +inline void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template +inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) +{ + external_constructor::construct(j, bin); +} + +template::value, int> = 0> +inline void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + int > = 0 > +inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + external_constructor::construct(j, arr); +} + +template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > +inline void to_json(BasicJsonType& j, const std::pair& p) +{ + j = { p.first, p.second }; +} + +// for https://github.com/nlohmann/json/pull/1134 +template>::value, int> = 0> +inline void to_json(BasicJsonType& j, const T& b) +{ + j = { {b.key(), b.value()} }; +} + +template +inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +{ + j = { std::get(t)... }; +} + +template::value, int > = 0> +inline void to_json(BasicJsonType& j, const T& t) +{ + to_json_tuple_impl(j, t, make_index_sequence::value> {}); +} + +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM +template +inline void to_json(BasicJsonType& j, const std_fs::path& p) +{ + j = p.string(); +} +#endif + +struct to_json_fn +{ + template + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } +}; +} // namespace detail + +#ifndef JSON_HAS_CPP_17 +/// namespace to hold default `to_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +#endif +JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) + detail::static_const::value; +#ifndef JSON_HAS_CPP_17 +} // namespace +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/exceptions.hpp b/includes/nlohmann/detail/exceptions.hpp new file mode 100644 index 0000000..5974d7b --- /dev/null +++ b/includes/nlohmann/detail/exceptions.hpp @@ -0,0 +1,257 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +//////////////// +// exceptions // +//////////////// + +/// @brief general exception of the @ref basic_json class +/// @sa https://json.nlohmann.me/api/basic_json/exception/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) + + static std::string name(const std::string& ename, int id_) + { + return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); + } + + static std::string diagnostics(std::nullptr_t /*leaf_element*/) + { + return ""; + } + + template + static std::string diagnostics(const BasicJsonType* leaf_element) + { +#if JSON_DIAGNOSTICS + std::vector tokens; + for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent) + { + switch (current->m_parent->type()) + { + case value_t::array: + { + for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i) + { + if (¤t->m_parent->m_data.m_value.array->operator[](i) == current) + { + tokens.emplace_back(std::to_string(i)); + break; + } + } + break; + } + + case value_t::object: + { + for (const auto& element : *current->m_parent->m_data.m_value.object) + { + if (&element.second == current) + { + tokens.emplace_back(element.first.c_str()); + break; + } + } + break; + } + + case value_t::null: // LCOV_EXCL_LINE + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + break; // LCOV_EXCL_LINE + } + } + + if (tokens.empty()) + { + return ""; + } + + auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, + [](const std::string & a, const std::string & b) + { + return concat(a, '/', detail::escape(b)); + }); + return concat('(', str, ") "); +#else + static_cast(leaf_element); + return ""; +#endif + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/// @brief exception indicating a parse error +/// @sa https://json.nlohmann.me/api/basic_json/parse_error/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + template::value, int> = 0> + static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("parse_error", id_), "parse error", + position_string(pos), ": ", exception::diagnostics(context), what_arg); + return {id_, pos.chars_read_total, w.c_str()}; + } + + template::value, int> = 0> + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("parse_error", id_), "parse error", + (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), + ": ", exception::diagnostics(context), what_arg); + return {id_, byte_, w.c_str()}; + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return concat(" at line ", std::to_string(pos.lines_read + 1), + ", column ", std::to_string(pos.chars_read_current_line)); + } +}; + +/// @brief exception indicating errors with iterators +/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ +class invalid_iterator : public exception +{ + public: + template::value, int> = 0> + static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/// @brief exception indicating executing a member function with a wrong type +/// @sa https://json.nlohmann.me/api/basic_json/type_error/ +class type_error : public exception +{ + public: + template::value, int> = 0> + static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/// @brief exception indicating access out of the defined range +/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ +class out_of_range : public exception +{ + public: + template::value, int> = 0> + static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/// @brief exception indicating other library errors +/// @sa https://json.nlohmann.me/api/basic_json/other_error/ +class other_error : public exception +{ + public: + template::value, int> = 0> + static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) + { + const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg); + return {id_, w.c_str()}; + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/hash.hpp b/includes/nlohmann/detail/hash.hpp new file mode 100644 index 0000000..4464e8e --- /dev/null +++ b/includes/nlohmann/detail/hash.hpp @@ -0,0 +1,129 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // uint8_t +#include // size_t +#include // hash + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@brief hash a JSON value + +The hash function tries to rely on std::hash where possible. Furthermore, the +type of the JSON value is taken into account to have different hash values for +null, 0, 0U, and false, etc. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + using string_t = typename BasicJsonType::string_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + const auto type = static_cast(j.type()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, static_cast(j.get_binary().subtype())); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/binary_reader.hpp b/includes/nlohmann/detail/input/binary_reader.hpp new file mode 100644 index 0000000..a6e100e --- /dev/null +++ b/includes/nlohmann/detail/input/binary_reader.hpp @@ -0,0 +1,3009 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // generate_n +#include // array +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf +#include // memcpy +#include // back_inserter +#include // numeric_limits +#include // char_traits, string +#include // make_pair, move +#include // vector + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type +}; + +/*! +@brief determine system byte order + +@return true if and only if system's byte order is little endian + +@note from https://stackoverflow.com/a/1001328/266378 +*/ +static inline bool little_endianness(int num = 1) noexcept +{ + return *reinterpret_cast(&num) == 1; +} + +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR, MessagePack, and UBJSON values +*/ +template> +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using json_sax_t = SAX; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename char_traits::int_type; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format) + { + (void)detail::is_sax_static_asserts {}; + } + + // make class move-only + binary_reader(const binary_reader&) = delete; + binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + binary_reader& operator=(const binary_reader&) = delete; + binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~binary_reader() = default; + + /*! + @param[in] format the binary format to parse + @param[in] sax_ a SAX event processor + @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags + + @return whether parsing was successful + */ + JSON_HEDLEY_NON_NULL(3) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + sax = sax_; + bool result = false; + + switch (format) + { + case input_format_t::bson: + result = parse_bson_internal(); + break; + + case input_format_t::cbor: + result = parse_cbor_internal(true, tag_handler); + break; + + case input_format_t::msgpack: + result = parse_msgpack_internal(); + break; + + case input_format_t::ubjson: + case input_format_t::bjdata: + result = parse_ubjson_internal(); + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + // strict mode: next byte must be EOF + if (result && strict) + { + if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata) + { + get_ignore_noop(); + } + else + { + get(); + } + + if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, + exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); + } + } + + return result; + } + + private: + ////////// + // BSON // + ////////// + + /*! + @brief Reads in a BSON-object and passes it to the SAX-parser. + @return whether a valid BSON-value was passed to the SAX parser + */ + bool parse_bson_internal() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) + { + return false; + } + + return sax->end_object(); + } + + /*! + @brief Parses a C-style string from the BSON input. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @return `true` if the \x00-byte indicating the end of the string was + encountered before the EOF; false` indicates an unexpected EOF. + */ + bool get_bson_cstr(string_t& result) + { + auto out = std::back_inserter(result); + while (true) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + { + return false; + } + if (current == 0x00) + { + return true; + } + *out++ = static_cast(current); + } + } + + /*! + @brief Parses a zero-terminated string of length @a len from the BSON + input. + @param[in] len The length (including the zero-byte at the end) of the + string to be read. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 1 + @return `true` if the string was successfully parsed + */ + template + bool get_bson_string(const NumberType len, string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 1)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); + } + + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != char_traits::eof(); + } + + /*! + @brief Parses a byte array input of length @a len from the BSON input. + @param[in] len The length of the byte array to be read. + @param[in,out] result A reference to the binary variable where the read + array is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 0 + @return `true` if the byte array was successfully parsed + */ + template + bool get_bson_binary(const NumberType len, binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 0)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); + } + + // All BSON binary values have a subtype + std::uint8_t subtype{}; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); + + return get_binary(input_format_t::bson, len, result); + } + + /*! + @brief Read a BSON document element of the given @a element_type. + @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html + @param[in] element_type_parse_position The position in the input stream, + where the `element_type` was read. + @warning Not all BSON element types are supported yet. An unsupported + @a element_type will give rise to a parse_error.114: + Unsupported BSON record type 0x... + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_internal(const char_int_type element_type, + const std::size_t element_type_parse_position) + { + switch (element_type) + { + case 0x01: // double + { + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + } + + case 0x02: // string + { + std::int32_t len{}; + string_t value; + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + } + + case 0x03: // object + { + return parse_bson_internal(); + } + + case 0x04: // array + { + return parse_bson_array(); + } + + case 0x05: // binary + { + std::int32_t len{}; + binary_t value; + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + } + + case 0x08: // boolean + { + return sax->boolean(get() != 0); + } + + case 0x0A: // null + { + return sax->null(); + } + + case 0x10: // int32 + { + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + case 0x12: // int64 + { + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + default: // anything else not supported (yet) + { + std::array cr{{}}; + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + const std::string cr_str{cr.data()}; + return sax->parse_error(element_type_parse_position, cr_str, + parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); + } + } + } + + /*! + @brief Read a BSON element list (as specified in the BSON-spec) + + The same binary layout is used for objects and arrays, hence it must be + indicated with the argument @a is_array which one is expected + (true --> array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array( + conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(static_cast(-1), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(conditional_static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(static_cast(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + + case cbor_tag_handler_t::ignore: + { + // ignore binary subtype + switch (current) + { + case 0xD8: + { + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xD9: + { + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDA: + { + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDB: + { + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + return parse_cbor_internal(true, tag_handler); + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); + } + } + } + + /*! + @param[in] len the length of the array or static_cast(-1) for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != static_cast(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or static_cast(-1) for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + if (len != 0) + { + string_t key; + if (len != static_cast(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(conditional_static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); + } + + /*! + @param[out] dim an integer vector storing the ND array dimensions + @return whether reading ND array size vector is successful + */ + bool get_ubjson_ndarray_size(std::vector& dim) + { + std::pair size_and_type; + size_t dimlen = 0; + bool no_ndarray = true; + + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) + { + return false; + } + + if (size_and_type.first != npos) + { + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) + { + return false; + } + dim.push_back(dimlen); + } + } + } + else + { + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) + { + return false; + } + dim.push_back(dimlen); + get_ignore_noop(); + } + } + return true; + } + + /*! + @param[out] result determined size + @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector + or ndarray dimension is not allowed; `false` means ndarray + is allowed; for output, `true` means an ndarray is found; + is_ndarray can only return `true` when its initial value + is `false` + @param[in] prefix type marker if already read, otherwise set to 0 + + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) + { + if (prefix == 0) + { + prefix = get_ignore_noop(); + } + + switch (prefix) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (number < 0) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, + exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = static_cast(number); + return true; + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = conditional_static_cast(number); + return true; + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + if (!value_in_range_of(number)) + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + exception_message(input_format, "integer value overflow", "size"), nullptr)); + } + result = detail::conditional_static_cast(number); + return true; + } + + case '[': + { + if (input_format != input_format_t::bjdata) + { + break; + } + if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); + } + std::vector dim; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) + { + return false; + } + if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector + { + result = dim.at(dim.size() - 1); + return true; + } + if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format + { + for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container + { + if ( i == 0 ) + { + result = 0; + return true; + } + } + + string_t key = "_ArraySize_"; + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) + { + return false; + } + result = 1; + for (auto i : dim) + { + result *= i; + if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() + { + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast(i)))) + { + return false; + } + } + is_ndarray = true; + return sax->end_array(); + } + result = 0; + return true; + } + + default: + break; + } + auto last_token = get_token_string(); + std::string message; + + if (input_format != input_format_t::bjdata) + { + message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token; + } + else + { + message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; + } + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result, bool inside_ndarray = false) + { + result.first = npos; // size + result.second = 0; // type + bool is_ndarray = false; + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (input_format == input_format_t::bjdata + && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second))) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); + } + + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + if (inside_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray can not be recursive", "size"), nullptr)); + } + result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters + } + return is_error; + } + + if (current == '#') + { + const bool is_error = get_ubjson_size_value(result.first, is_ndarray); + if (input_format == input_format_t::bjdata && is_ndarray) + { + return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, + exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); + } + return is_error; + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case char_traits::eof(): // EOF + return unexpect_eof(input_format, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format, number) && sax->number_integer(number); + } + + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'h': + { + if (input_format != input_format_t::bjdata) + { + break; + } + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte2 << 8u) + byte1); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 'd': + { + float number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, + exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + break; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata): + // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]} + + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + size_and_type.second &= ~(static_cast(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker + auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t) + { + return p.first < t; + }); + string_t key = "_ArrayType_"; + if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); + } + + string_t type = it->second; // sax->string() takes a reference + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) + { + return false; + } + + if (size_and_type.second == 'C') + { + size_and_type.second = 'U'; + } + + key = "_ArrayData_"; + if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) + { + return false; + } + + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + + return (sax->end_array() && sax->end_object()); + } + + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + // do not accept ND-array size in objects in BJData + if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, + exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); + } + + string_t key; + if (size_and_type.first != npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + bool no_ndarray = true; + auto res = get_ubjson_size_value(size, no_ndarray); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + using ia_type = decltype(detail::input_adapter(number_vector)); + auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + case token_type::uninitialized: + case token_type::literal_true: + case token_type::literal_false: + case token_type::literal_null: + case token_type::value_string: + case token_type::begin_array: + case token_type::begin_object: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::parse_error: + case token_type::end_of_input: + case token_type::literal_or_value: + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianness, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + On the other hand, BSON and BJData use little endian and should reorder + on big endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // step 1: read input into array with system's byte order + std::array vec{}; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + { + return false; + } + + // reverse byte order prior to conversion if necessary + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + case input_format_t::bjdata: + error_msg += "BJData"; + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + return concat(error_msg, ' ', context, ": ", detail); + } + + private: + static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast(-1); + + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianness + const bool is_little_endian = little_endianness(); + + /// input format + const input_format_t input_format = input_format_t::json; + + /// the SAX parser + json_sax_t* sax = nullptr; + + // excluded markers in bjdata optimized type +#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \ + make_array('F', 'H', 'N', 'S', 'T', 'Z', '[', '{') + +#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ + make_array( \ + bjd_type{'C', "char"}, \ + bjd_type{'D', "double"}, \ + bjd_type{'I', "int16"}, \ + bjd_type{'L', "int64"}, \ + bjd_type{'M', "uint64"}, \ + bjd_type{'U', "uint8"}, \ + bjd_type{'d', "single"}, \ + bjd_type{'i', "int8"}, \ + bjd_type{'l', "int32"}, \ + bjd_type{'m', "uint32"}, \ + bjd_type{'u', "uint16"}) + + JSON_PRIVATE_UNLESS_TESTED: + // lookup tables + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers = + JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_; + + using bjd_type = std::pair; + // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map = + JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_; + +#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ +#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr std::size_t binary_reader::npos; +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/input_adapters.hpp b/includes/nlohmann/detail/input/input_adapters.hpp new file mode 100644 index 0000000..33fca3e --- /dev/null +++ b/includes/nlohmann/detail/input/input_adapters.hpp @@ -0,0 +1,492 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // size_t +#include // strlen +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +#ifndef JSON_NO_IO + #include // FILE * + #include // istream +#endif // JSON_NO_IO + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; + +//////////////////// +// input adapters // +//////////////////// + +#ifndef JSON_NO_IO +/*! +Input adapter for stdio file access. This adapter read only 1 byte and do not use any + buffer. This adapter is a very low level adapter. +*/ +class file_input_adapter +{ + public: + using char_type = char; + + JSON_HEDLEY_NON_NULL(2) + explicit file_input_adapter(std::FILE* f) noexcept + : m_file(f) + { + JSON_ASSERT(m_file != nullptr); + } + + // make class move-only + file_input_adapter(const file_input_adapter&) = delete; + file_input_adapter(file_input_adapter&&) noexcept = default; + file_input_adapter& operator=(const file_input_adapter&) = delete; + file_input_adapter& operator=(file_input_adapter&&) = delete; + ~file_input_adapter() = default; + + std::char_traits::int_type get_character() noexcept + { + return std::fgetc(m_file); + } + + private: + /// the file pointer to read from + std::FILE* m_file; +}; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter +{ + public: + using char_type = char; + + ~input_stream_adapter() + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags, except eof + if (is != nullptr) + { + is->clear(is->rdstate() & std::ios::eofbit); + } + } + + explicit input_stream_adapter(std::istream& i) + : is(&i), sb(i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&&) = delete; + + input_stream_adapter(input_stream_adapter&& rhs) noexcept + : is(rhs.is), sb(rhs.sb) + { + rhs.is = nullptr; + rhs.sb = nullptr; + } + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, e.g. 0xFFFFFFFF. + std::char_traits::int_type get_character() + { + auto res = sb->sbumpc(); + // set eof manually, as we don't use the istream interface. + if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + + private: + /// the associated input stream + std::istream* is = nullptr; + std::streambuf* sb = nullptr; +}; +#endif // JSON_NO_IO + +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter +{ + public: + using char_type = typename std::iterator_traits::value_type; + + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) + {} + + typename char_traits::int_type get_character() + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + auto result = char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + + return char_traits::eof(); + } + + private: + IteratorType current; + IteratorType end; + + template + friend struct wide_string_input_helper; + + bool empty() const + { + return current == end; + } +}; + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper +{ + // UTF-32 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc || wc >= 0xE000) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else + { + if (JSON_HEDLEY_UNLIKELY(!input.empty())) + { + const auto wc2 = static_cast(input.get_character()); + const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); + utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } + } +}; + +// Wraps another input adapter to convert wide character types into individual bytes. +template +class wide_string_input_adapter +{ + public: + using char_type = char; + + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} + + typename std::char_traits::int_type get_character() noexcept + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + fill_buffer(); + + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); + } + + // use buffer + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + BaseInputAdapter base_adapter; + + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(std::move(first), std::move(last)); + } +}; + +template +struct is_iterator_of_multibyte +{ + using value_type = typename std::iterator_traits::value_type; + enum + { + value = sizeof(value_type) > 1 + }; +}; + +template +struct iterator_input_adapter_factory::value>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) +{ + using factory_type = iterator_input_adapter_factory; + return factory_type::create(first, last); +} + +// Convenience shorthand from container to iterator +// Enables ADL on begin(container) and end(container) +// Encloses the using declarations in namespace for not to leak them to outside scope + +namespace container_input_adapter_factory_impl +{ + +using std::begin; +using std::end; + +template +struct container_input_adapter_factory {}; + +template +struct container_input_adapter_factory< ContainerType, + void_t()), end(std::declval()))>> + { + using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); + + static adapter_type create(const ContainerType& container) +{ + return input_adapter(begin(container), end(container)); +} + }; + +} // namespace container_input_adapter_factory_impl + +template +typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) +{ + return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); +} + +#ifndef JSON_NO_IO +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) +{ + return file_input_adapter(file); +} + +inline input_stream_adapter input_adapter(std::istream& stream) +{ + return input_stream_adapter(stream); +} + +inline input_stream_adapter input_adapter(std::istream&& stream) +{ + return input_stream_adapter(stream); +} +#endif // JSON_NO_IO + +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + +// Null-delimited strings, and the like. +template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > +contiguous_bytes_input_adapter input_adapter(CharT b) +{ + auto length = std::strlen(reinterpret_cast(b)); + const auto* ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); +} + +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + return input_adapter(array, array + N); +} + +// This class only handles inputs of input_buffer_adapter type. +// It's required so that expressions like {ptr, len} can be implicitly cast +// to the correct adapter. +class span_input_adapter +{ + public: + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > + span_input_adapter(CharT b, std::size_t l) + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + span_input_adapter(IteratorType first, IteratorType last) + : ia(input_adapter(first, last)) {} + + contiguous_bytes_input_adapter&& get() + { + return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) + } + + private: + contiguous_bytes_input_adapter ia; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/json_sax.hpp b/includes/nlohmann/detail/input/json_sax.hpp new file mode 100644 index 0000000..c772521 --- /dev/null +++ b/includes/nlohmann/detail/input/json_sax.hpp @@ -0,0 +1,727 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include // string +#include // move +#include // vector + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief a floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string value was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string value. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary value was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary value. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + json_sax() = default; + json_sax(const json_sax&) = default; + json_sax(json_sax&&) noexcept = default; + json_sax& operator=(const json_sax&) = default; + json_sax& operator=(json_sax&&) noexcept = default; + virtual ~json_sax() = default; +}; + +namespace detail +{ +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @param[in,out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) + : root(r), allow_exceptions(allow_exceptions_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_object()); + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool end_array() + { + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(ref_stack.back()->is_array()); + + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_data.m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + + json_sax_dom_callback_parser(BasicJsonType& r, + const parser_callback_t cb, + const bool allow_exceptions_ = true) + : root(r), callback(cb), allow_exceptions(allow_exceptions_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + // check object limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back()) + { + if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + } + else + { + ref_stack.back()->set_parents(); + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + // check array limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (keep) + { + ref_stack.back()->set_parents(); + } + else + { + // discard array + *ref_stack.back() = discarded; + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, & root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); + return {true, & (ref_stack.back()->m_data.m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = static_cast(-1)) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = static_cast(-1)) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/lexer.hpp b/includes/nlohmann/detail/input/lexer.hpp new file mode 100644 index 0000000..4b3bf77 --- /dev/null +++ b/includes/nlohmann/detail/input/lexer.hpp @@ -0,0 +1,1633 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // localeconv +#include // size_t +#include // snprintf +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // char_traits, string +#include // move +#include // vector + +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////// +// lexer // +/////////// + +template +class lexer_base +{ + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + JSON_HEDLEY_RETURNS_NON_NULL + JSON_HEDLEY_CONST + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_unsigned: + case token_type::value_integer: + case token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } +}; +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer : public lexer_base +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename char_traits::int_type; + + public: + using token_type = typename lexer_base::token_type; + + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~lexer() = default; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + JSON_ASSERT(current == 'u'); + int codepoint = 0; + + const auto factors = { 12u, 8u, 4u, 0u }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' && current <= '9') + { + codepoint += static_cast((static_cast(current) - 0x30u) << factor); + } + else if (current >= 'A' && current <= 'F') + { + codepoint += static_cast((static_cast(current) - 0x37u) << factor); + } + else if (current >= 'a' && current <= 'f') + { + codepoint += static_cast((static_cast(current) - 0x57u) << factor); + } + else + { + return -1; + } + } + + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 8259. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + JSON_ASSERT(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = static_cast( + // high surrogate occupies the most significant 22 bits + (static_cast(codepoint1) << 10u) + // low surrogate occupies the least significant 15 bits + + static_cast(codepoint2) + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result, so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00u); + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(static_cast(codepoint)); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + + case 0x1F: + { + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + continue; + } + } + } + + default: + continue; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 8259. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 8259. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() // lgtm [cpp/use-of-goto] + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // all other characters are rejected outside scan_number() + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + JSON_HEDLEY_NON_NULL(2) + token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type return_type) + { + JSON_ASSERT(char_traits::to_char_type(current) == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_HEDLEY_UNLIKELY(char_traits::to_char_type(get()) != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + char_int_type get() + { + ++position.chars_read_total; + ++position.chars_read_current_line; + + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia.get_character(); + } + + if (JSON_HEDLEY_LIKELY(current != char_traits::eof())) + { + token_string.push_back(char_traits::to_char_type(current)); + } + + if (current == '\n') + { + ++position.lines_read; + position.chars_read_current_line = 0; + } + + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. + */ + void unget() + { + next_unget = true; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + + if (JSON_HEDLEY_LIKELY(current != char_traits::eof())) + { + JSON_ASSERT(!token_string.empty()); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(char_int_type c) + { + token_buffer.push_back(static_cast(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr position_t get_position() const noexcept + { + return position; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if (static_cast(c) <= '\x1F') + { + // escape control characters + std::array cs{{}}; + static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + result += cs.data(); + } + else + { + // add character as is + result.push_back(static_cast(c)); + } + } + + return result; + } + + /// return syntax error message + JSON_HEDLEY_RETURNS_NON_NULL + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + // check if we completely parse the BOM + return get() == 0xBB && get() == 0xBF; + } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + + token_type scan() + { + // initially, skip the BOM + if (position.chars_read_total == 0 && !skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + skip_whitespace(); + + // ignore comments + while (ignore_comments && current == '/') + { + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); + } + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + { + std::array true_literal = {{static_cast('t'), static_cast('r'), static_cast('u'), static_cast('e')}}; + return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); + } + case 'f': + { + std::array false_literal = {{static_cast('f'), static_cast('a'), static_cast('l'), static_cast('s'), static_cast('e')}}; + return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); + } + case 'n': + { + std::array null_literal = {{static_cast('n'), static_cast('u'), static_cast('l'), static_cast('l')}}; + return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); + } + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + InputAdapterType ia; + + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + + /// the current character + char_int_type current = char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the start position of the current token + position_t position {}; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char_int_type decimal_point_char = '.'; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/parser.hpp b/includes/nlohmann/detail/input/parser.hpp new file mode 100644 index 0000000..bdf85ba --- /dev/null +++ b/includes/nlohmann/detail/input/parser.hpp @@ -0,0 +1,519 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +#include +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : std::uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + + result.assert_invariant(); + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); + } + case token_type::end_of_input: + { + if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + case token_type::uninitialized: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::literal_or_value: + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); + } + + // states.back() is false -> object + + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += concat("while parsing ", context, ' '); + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += concat(m_lexer.get_error_message(), "; last read: '", + m_lexer.get_token_string(), '\''); + } + else + { + error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += concat("; expected ", lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/input/position_t.hpp b/includes/nlohmann/detail/input/position_t.hpp new file mode 100644 index 0000000..8ac7c78 --- /dev/null +++ b/includes/nlohmann/detail/input/position_t.hpp @@ -0,0 +1,37 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/iterators/internal_iterator.hpp b/includes/nlohmann/detail/iterators/internal_iterator.hpp new file mode 100644 index 0000000..2991ee6 --- /dev/null +++ b/includes/nlohmann/detail/iterators/internal_iterator.hpp @@ -0,0 +1,35 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/iterators/iter_impl.hpp b/includes/nlohmann/detail/iterators/iter_impl.hpp new file mode 100644 index 0000000..4447091 --- /dev/null +++ b/includes/nlohmann/detail/iterators/iter_impl.hpp @@ -0,0 +1,751 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) +{ + /// the iterator with BasicJsonType of different const-ness + using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + /// allow basic_json to access private members + friend other_iter_impl; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + // superficial check for the LegacyBidirectionalIterator named requirement + static_assert(std::is_base_of::value + && std::is_base_of::iterator_category>::value, + "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); + + public: + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + iter_impl() = default; + ~iter_impl() = default; + iter_impl(iter_impl&&) noexcept = default; + iter_impl& operator=(iter_impl&&) noexcept = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + if (&other != this) + { + m_object = other.m_object; + m_it = other.m_it; + } + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_data.m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_data.m_value.array->end(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); + return &*m_it.array_iterator; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator==(const IterImpl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator!=(const IterImpl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_data.m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + JSON_PRIVATE_UNLESS_TESTED: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/iterators/iteration_proxy.hpp b/includes/nlohmann/detail/iterators/iteration_proxy.hpp new file mode 100644 index 0000000..76293de --- /dev/null +++ b/includes/nlohmann/detail/iterators/iteration_proxy.hpp @@ -0,0 +1,242 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t +#include // input_iterator_tag +#include // string, to_string +#include // tuple_size, get, tuple_element +#include // move + +#if JSON_HAS_RANGES + #include // enable_borrowed_range +#endif + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +void int_to_string( string_type& target, std::size_t value ) +{ + // For ADL + using std::to_string; + target = to_string(value); +} +template class iteration_proxy_value +{ + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_value; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::input_iterator_tag; + using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; + + private: + /// the iterator + IteratorType anchor{}; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable string_type array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + string_type empty_str{}; + + public: + explicit iteration_proxy_value() = default; + explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) + noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_default_constructible::value) + : anchor(std::move(it)) + , array_index(array_index_) + {} + + iteration_proxy_value(iteration_proxy_value const&) = default; + iteration_proxy_value& operator=(iteration_proxy_value const&) = default; + // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions + iteration_proxy_value(iteration_proxy_value&&) + noexcept(std::is_nothrow_move_constructible::value + && std::is_nothrow_move_constructible::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) + iteration_proxy_value& operator=(iteration_proxy_value&&) + noexcept(std::is_nothrow_move_assignable::value + && std::is_nothrow_move_assignable::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) + ~iteration_proxy_value() = default; + + /// dereference operator (needed for range-based for) + const iteration_proxy_value& operator*() const + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_value& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) + { + auto tmp = iteration_proxy_value(anchor, array_index); + ++anchor; + ++array_index; + return tmp; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_value& o) const + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_value& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + const string_type& key() const + { + JSON_ASSERT(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + int_to_string( array_index_str, array_index ); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } +}; + +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// the container to iterate + typename IteratorType::pointer container = nullptr; + + public: + explicit iteration_proxy() = default; + + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(&cont) {} + + iteration_proxy(iteration_proxy const&) = default; + iteration_proxy& operator=(iteration_proxy const&) = default; + iteration_proxy(iteration_proxy&&) noexcept = default; + iteration_proxy& operator=(iteration_proxy&&) noexcept = default; + ~iteration_proxy() = default; + + /// return iterator begin (needed for range-based for) + iteration_proxy_value begin() const noexcept + { + return iteration_proxy_value(container->begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_value end() const noexcept + { + return iteration_proxy_value(container->end()); + } +}; + +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) +{ + return i.key(); +} +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) +{ + return i.value(); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// The Addition to the STD Namespace is required to add +// Structured Bindings Support to the iteration_proxy_value class +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +namespace std +{ + +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::iteration_proxy_value> // NOLINT(cert-dcl58-cpp) + : public std::integral_constant {}; + +template +class tuple_element> // NOLINT(cert-dcl58-cpp) +{ + public: + using type = decltype( + get(std::declval < + ::nlohmann::detail::iteration_proxy_value> ())); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +} // namespace std + +#if JSON_HAS_RANGES + template + inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy> = true; +#endif diff --git a/includes/nlohmann/detail/iterators/iterator_traits.hpp b/includes/nlohmann/detail/iterators/iterator_traits.hpp new file mode 100644 index 0000000..84cc27a --- /dev/null +++ b/includes/nlohmann/detail/iterators/iterator_traits.hpp @@ -0,0 +1,61 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // random_access_iterator_tag + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/iterators/json_reverse_iterator.hpp b/includes/nlohmann/detail/iterators/json_reverse_iterator.hpp new file mode 100644 index 0000000..006d549 --- /dev/null +++ b/includes/nlohmann/detail/iterators/json_reverse_iterator.hpp @@ -0,0 +1,130 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/iterators/primitive_iterator.hpp b/includes/nlohmann/detail/iterators/primitive_iterator.hpp new file mode 100644 index 0000000..0b6e849 --- /dev/null +++ b/includes/nlohmann/detail/iterators/primitive_iterator.hpp @@ -0,0 +1,132 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // ptrdiff_t +#include // numeric_limits + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + JSON_PRIVATE_UNLESS_TESTED: + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/json_custom_base_class.hpp b/includes/nlohmann/detail/json_custom_base_class.hpp new file mode 100644 index 0000000..d1e2916 --- /dev/null +++ b/includes/nlohmann/detail/json_custom_base_class.hpp @@ -0,0 +1,39 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // conditional, is_same + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief Default base class of the @ref basic_json class. + +So that the correct implementations of the copy / move ctors / assign operators +of @ref basic_json do not require complex case distinctions +(no base class / custom base class used as customization point), +@ref basic_json always has a base class. +By default, this class is used because it is empty and thus has no effect +on the behavior of @ref basic_json. +*/ +struct json_default_base {}; + +template +using json_base_class = typename std::conditional < + std::is_same::value, + json_default_base, + T + >::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/json_pointer.hpp b/includes/nlohmann/detail/json_pointer.hpp new file mode 100644 index 0000000..4fdcd9a --- /dev/null +++ b/includes/nlohmann/detail/json_pointer.hpp @@ -0,0 +1,988 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // all_of +#include // isdigit +#include // errno, ERANGE +#include // strtoull +#ifndef JSON_NO_IO + #include // ostream +#endif // JSON_NO_IO +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document +/// @sa https://json.nlohmann.me/api/json_pointer/ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + template + friend class json_pointer; + + template + struct string_t_helper + { + using type = T; + }; + + NLOHMANN_BASIC_JSON_TPL_DECLARATION + struct string_t_helper + { + using type = StringType; + }; + + public: + // for backwards compatibility accept BasicJsonType + using string_t = typename string_t_helper::type; + + /// @brief create JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ + explicit json_pointer(const string_t& s = "") + : reference_tokens(split(s)) + {} + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ + string_t to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + string_t{}, + [](const string_t& a, const string_t& b) + { + return detail::concat(a, '/', detail::escape(b)); + }); + } + + /// @brief return a string representation of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) + operator string_t() const + { + return to_string(); + } + +#ifndef JSON_NO_IO + /// @brief write string representation of the JSON pointer to stream + /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ + friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) + { + o << ptr.to_string(); + return o; + } +#endif + + /// @brief append another JSON pointer at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /// @brief append an unescaped reference token at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(string_t token) + { + push_back(std::move(token)); + return *this; + } + + /// @brief append an array index at the end of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) + { + return json_pointer(lhs) /= std::move(token); + } + + /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ + friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) + { + return json_pointer(lhs) /= array_idx; + } + + /// @brief returns the parent of this JSON pointer + /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /// @brief remove last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + reference_tokens.pop_back(); + } + + /// @brief return last reference token + /// @sa https://json.nlohmann.me/api/json_pointer/back/ + const string_t& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + return reference_tokens.back(); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(const string_t& token) + { + reference_tokens.push_back(token); + } + + /// @brief append an unescaped token at the end of the reference pointer + /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ + void push_back(string_t&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /// @brief return whether pointer points to the root document + /// @sa https://json.nlohmann.me/api/json_pointer/empty/ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + template + static typename BasicJsonType::size_type array_index(const string_t& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); + } + + const char* p = s.c_str(); + char* p_end = nullptr; + errno = 0; // strtoull doesn't reset errno + const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) + if (p == p_end // invalid input or empty string + || errno == ERANGE // out of range + || JSON_HEDLEY_UNLIKELY(static_cast(p_end - p) != s.size())) // incomplete read + { + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) + { + JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + JSON_PRIVATE_UNLESS_TESTED: + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + private: + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + template + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto* result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_data.m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + template + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, detail::concat( + "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), + ") is out of range"), ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + template + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const string_t& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == string_t::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == string_t::npos) + start = (slash == string_t::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != string_t::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); + } + } + + // finally, store the reference token + detail::unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + template + static void flatten(const string_t& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_data.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) + { + flatten(detail::concat(reference_string, '/', std::to_string(i)), + value.m_data.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_data.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_data.m_value.object) + { + flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); + } + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + template + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_data.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + // can't use conversion operator because of ambiguity + json_pointer convert() const& + { + json_pointer result; + result.reference_tokens = reference_tokens; + return result; + } + + json_pointer convert()&& + { + json_pointer result; + result.reference_tokens = std::move(reference_tokens); + return result; + } + + public: +#if JSON_HAS_THREE_WAY_COMPARISON + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + bool operator==(const json_pointer& rhs) const noexcept + { + return reference_tokens == rhs.reference_tokens; + } + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) + bool operator==(const string_t& rhs) const + { + return *this == json_pointer(rhs); + } + + /// @brief 3-way compares two JSON pointers + template + std::strong_ordering operator<=>(const json_pointer& rhs) const noexcept // *NOPAD* + { + return reference_tokens <=> rhs.reference_tokens; // *NOPAD* + } +#else + /// @brief compares two JSON pointers for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for equality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator==(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointers for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept; + + /// @brief compares JSON pointer and string for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const json_pointer& lhs, + const StringType& rhs); + + /// @brief compares string and JSON pointer for inequality + /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator!=(const StringType& lhs, + const json_pointer& rhs); + + /// @brief compares two JSON pointer for less-than + template + // NOLINTNEXTLINE(readability-redundant-declaration) + friend bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept; +#endif + + private: + /// the reference tokens + std::vector reference_tokens; +}; + +#if !JSON_HAS_THREE_WAY_COMPARISON +// functions cannot be defined inside class due to ODR violations +template +inline bool operator==(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens == rhs.reference_tokens; +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const json_pointer& lhs, + const StringType& rhs) +{ + return lhs == json_pointer(rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) +inline bool operator==(const StringType& lhs, + const json_pointer& rhs) +{ + return json_pointer(lhs) == rhs; +} + +template +inline bool operator!=(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const json_pointer& lhs, + const StringType& rhs) +{ + return !(lhs == rhs); +} + +template::string_t> +JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) +inline bool operator!=(const StringType& lhs, + const json_pointer& rhs) +{ + return !(lhs == rhs); +} + +template +inline bool operator<(const json_pointer& lhs, + const json_pointer& rhs) noexcept +{ + return lhs.reference_tokens < rhs.reference_tokens; +} +#endif + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/json_ref.hpp b/includes/nlohmann/detail/json_ref.hpp new file mode 100644 index 0000000..b8bb6a7 --- /dev/null +++ b/includes/nlohmann/detail/json_ref.hpp @@ -0,0 +1,78 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + {} + + json_ref(const value_type& value) + : value_ref(&value) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + {} + + // class should be movable only + json_ref(json_ref&&) noexcept = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (value_ref == nullptr) + { + return std::move(owned_value); + } + return *value_ref; + } + + value_type const& operator*() const + { + return value_ref ? *value_ref : owned_value; + } + + value_type const* operator->() const + { + return &** this; + } + + private: + mutable value_type owned_value = nullptr; + value_type const* value_ref = nullptr; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/macro_scope.hpp b/includes/nlohmann/detail/macro_scope.hpp new file mode 100644 index 0000000..97127a6 --- /dev/null +++ b/includes/nlohmann/detail/macro_scope.hpp @@ -0,0 +1,482 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // declval, pair +#include +#include + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +#include + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif diff --git a/includes/nlohmann/detail/macro_unscope.hpp b/includes/nlohmann/detail/macro_unscope.hpp new file mode 100644 index 0000000..c6620d1 --- /dev/null +++ b/includes/nlohmann/detail/macro_unscope.hpp @@ -0,0 +1,45 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +// restore clang diagnostic settings +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_THROW +#undef JSON_PRIVATE_UNLESS_TESTED +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL +#undef JSON_INLINE_VARIABLE +#undef JSON_NO_UNIQUE_ADDRESS +#undef JSON_DISABLE_ENUM_SERIALIZATION +#undef JSON_USE_GLOBAL_UDLS + +#ifndef JSON_TEST_KEEP_MACROS + #undef JSON_CATCH + #undef JSON_TRY + #undef JSON_HAS_CPP_11 + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_20 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #undef JSON_HAS_THREE_WAY_COMPARISON + #undef JSON_HAS_RANGES + #undef JSON_HAS_STATIC_RTTI + #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#include diff --git a/includes/nlohmann/detail/meta/call_std/begin.hpp b/includes/nlohmann/detail/meta/call_std/begin.hpp new file mode 100644 index 0000000..364cc89 --- /dev/null +++ b/includes/nlohmann/detail/meta/call_std/begin.hpp @@ -0,0 +1,17 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/call_std/end.hpp b/includes/nlohmann/detail/meta/call_std/end.hpp new file mode 100644 index 0000000..463f070 --- /dev/null +++ b/includes/nlohmann/detail/meta/call_std/end.hpp @@ -0,0 +1,17 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/cpp_future.hpp b/includes/nlohmann/detail/meta/cpp_future.hpp new file mode 100644 index 0000000..412b5aa --- /dev/null +++ b/includes/nlohmann/detail/meta/cpp_future.hpp @@ -0,0 +1,171 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + +#pragma once + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/detected.hpp b/includes/nlohmann/detail/meta/detected.hpp new file mode 100644 index 0000000..1db9bf9 --- /dev/null +++ b/includes/nlohmann/detail/meta/detected.hpp @@ -0,0 +1,70 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/identity_tag.hpp b/includes/nlohmann/detail/meta/identity_tag.hpp new file mode 100644 index 0000000..269deff --- /dev/null +++ b/includes/nlohmann/detail/meta/identity_tag.hpp @@ -0,0 +1,21 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// dispatching helper struct +template struct identity_tag {}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/is_sax.hpp b/includes/nlohmann/detail/meta/is_sax.hpp new file mode 100644 index 0000000..4e02bc1 --- /dev/null +++ b/includes/nlohmann/detail/meta/is_sax.hpp @@ -0,0 +1,159 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // size_t +#include // declval +#include // string + +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using null_function_t = decltype(std::declval().null()); + +template +using boolean_function_t = + decltype(std::declval().boolean(std::declval())); + +template +using number_integer_function_t = + decltype(std::declval().number_integer(std::declval())); + +template +using number_unsigned_function_t = + decltype(std::declval().number_unsigned(std::declval())); + +template +using number_float_function_t = decltype(std::declval().number_float( + std::declval(), std::declval())); + +template +using string_function_t = + decltype(std::declval().string(std::declval())); + +template +using binary_function_t = + decltype(std::declval().binary(std::declval())); + +template +using start_object_function_t = + decltype(std::declval().start_object(std::declval())); + +template +using key_function_t = + decltype(std::declval().key(std::declval())); + +template +using end_object_function_t = decltype(std::declval().end_object()); + +template +using start_array_function_t = + decltype(std::declval().start_array(std::declval())); + +template +using end_array_function_t = decltype(std::declval().end_array()); + +template +using parse_error_function_t = decltype(std::declval().parse_error( + std::declval(), std::declval(), + std::declval())); + +template +struct is_sax +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static constexpr bool value = + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value; +}; + +template +struct is_sax_static_asserts +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static_assert(is_detected_exact::value, + "Missing/invalid function: bool null()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_integer(number_integer_t)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool string(string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool binary(binary_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_object(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool key(string_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_object()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_array(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_array()"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool parse_error(std::size_t, const " + "std::string&, const exception&)"); +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END diff --git a/includes/nlohmann/detail/meta/std_fs.hpp b/includes/nlohmann/detail/meta/std_fs.hpp new file mode 100644 index 0000000..fd18039 --- /dev/null +++ b/includes/nlohmann/detail/meta/std_fs.hpp @@ -0,0 +1,29 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END +#elif JSON_HAS_FILESYSTEM +#include +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ +namespace std_fs = std::filesystem; +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END +#endif diff --git a/includes/nlohmann/detail/meta/type_traits.hpp b/includes/nlohmann/detail/meta/type_traits.hpp new file mode 100644 index 0000000..e1b000d --- /dev/null +++ b/includes/nlohmann/detail/meta/type_traits.hpp @@ -0,0 +1,795 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#pragma once + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple +#include // char_traits + +#include +#include +#include +#include +#include +#include +#include + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template