/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/rtp_rtcp/source/rtp_header_extensions.h" #include <string.h> #include <cmath> #include <cstddef> #include <cstdint> #include <limits> #include <string> #include <vector> #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/rtp_headers.h" #include "api/video/color_space.h" #include "api/video/hdr_metadata.h" #include "api/video/video_content_type.h" #include "api/video/video_rotation.h" #include "api/video/video_timing.h" #include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "rtc_base/checks.h" namespace webrtc { // Absolute send time in RTP streams. // // The absolute send time is signaled to the receiver in-band using the // general mechanism for RTP header extensions [RFC8285]. The payload // of this extension (the transmitted value) is a 24-bit unsigned integer // containing the sender's current time in seconds as a fixed point number // with 18 bits fractional part. // // The form of the absolute send time extension block: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | absolute send time | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits) { … } bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data, uint32_t time_24bits) { … } // Absolute Capture Time // // The Absolute Capture Time extension is used to stamp RTP packets with a NTP // timestamp showing when the first audio or video frame in a packet was // originally captured. The intent of this extension is to provide a way to // accomplish audio-to-video synchronization when RTCP-terminating intermediate // systems (e.g. mixers) are involved. // // Data layout of the shortened version of abs-capture-time: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=7 | absolute capture timestamp (bit 0-23) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | absolute capture timestamp (bit 24-55) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... (56-63) | // +-+-+-+-+-+-+-+-+ // // Data layout of the extended version of abs-capture-time: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=15| absolute capture timestamp (bit 0-23) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | absolute capture timestamp (bit 24-55) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... (56-63) | estimated capture clock offset (bit 0-23) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | estimated capture clock offset (bit 24-55) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... (56-63) | // +-+-+-+-+-+-+-+-+ bool AbsoluteCaptureTimeExtension::Parse(rtc::ArrayView<const uint8_t> data, AbsoluteCaptureTime* extension) { … } size_t AbsoluteCaptureTimeExtension::ValueSize( const AbsoluteCaptureTime& extension) { … } bool AbsoluteCaptureTimeExtension::Write(rtc::ArrayView<uint8_t> data, const AbsoluteCaptureTime& extension) { … } // An RTP Header Extension for Client-to-Mixer Audio Level Indication // // https://tools.ietf.org/html/rfc6464 // // The form of the audio level extension block: // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |V| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the One-Byte Header Format // // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=1 |V| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the Two-Byte Header Format bool AudioLevelExtension::Parse(rtc::ArrayView<const uint8_t> data, AudioLevel* extension) { … } bool AudioLevelExtension::Write(rtc::ArrayView<uint8_t> data, const AudioLevel& extension) { … } // An RTP Header Extension for Mixer-to-Client Audio Level Indication // // https://tools.ietf.org/html/rfc6465 // // The form of the audio level extension block: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 |0| level 1 |0| level 2 |0| level 3 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the One-Byte Header Format // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=3 |0| level 1 |0| level 2 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |0| level 3 | 0 (pad) | ... | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the Two-Byte Header Format bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data, std::vector<uint8_t>* csrc_audio_levels) { … } size_t CsrcAudioLevel::ValueSize( rtc::ArrayView<const uint8_t> csrc_audio_levels) { … } bool CsrcAudioLevel::Write(rtc::ArrayView<uint8_t> data, rtc::ArrayView<const uint8_t> csrc_audio_levels) { … } // From RFC 5450: Transmission Time Offsets in RTP Streams. // // The transmission time is signaled to the receiver in-band using the // general mechanism for RTP header extensions [RFC8285]. The payload // of this extension (the transmitted value) is a 24-bit signed integer. // When added to the RTP timestamp of the packet, it represents the // "effective" RTP transmission time of the packet, on the RTP // timescale. // // The form of the transmission offset extension block: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | transmission offset | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time) { … } bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) { … } // TransportSequenceNumber // // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=1 |transport-wide sequence number | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data, uint16_t* transport_sequence_number) { … } bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data, uint16_t transport_sequence_number) { … } // TransportSequenceNumberV2 // // In addition to the format used for TransportSequencNumber, V2 also supports // the following packet format where two extra bytes are used to specify that // the sender requests immediate feedback. // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=3 |transport-wide sequence number |T| seq count | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |seq count cont.| // +-+-+-+-+-+-+-+-+ // // The bit `T` determines whether the feedback should include timing information // or not and `seq_count` determines how many packets the feedback packet should // cover including the current packet. If `seq_count` is zero no feedback is // requested. bool TransportSequenceNumberV2::Parse( rtc::ArrayView<const uint8_t> data, uint16_t* transport_sequence_number, absl::optional<FeedbackRequest>* feedback_request) { … } bool TransportSequenceNumberV2::Write( rtc::ArrayView<uint8_t> data, uint16_t transport_sequence_number, const absl::optional<FeedbackRequest>& feedback_request) { … } // Coordination of Video Orientation in RTP streams. // // Coordination of Video Orientation consists in signaling of the current // orientation of the image captured on the sender side to the receiver for // appropriate rendering and displaying. // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |0 0 0 0 C F R R| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* rotation) { … } bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, VideoRotation rotation) { … } bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value) { … } bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) { … } // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | MIN delay | MAX delay | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data, VideoPlayoutDelay* playout_delay) { … } bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data, const VideoPlayoutDelay& playout_delay) { … } // Video Content Type. // // E.g. default video or screenshare. // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 | Content type | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data, VideoContentType* content_type) { … } bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data, VideoContentType content_type) { … } // Video Timing. // 6 timestamps in milliseconds counted from capture time stored in rtp header: // encode start/finish, packetization complete, pacer exit and reserved for // modification by the network modification. `flags` is a bitmask and has the // following allowed values: // 0 = Valid data, but no flags available (backwards compatibility) // 1 = Frame marked as timing frame due to cyclic timer. // 2 = Frame marked as timing frame due to size being outside limit. // 255 = Invalid. The whole timing frame extension should be ignored. // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=12| flags | encode start ms delta | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | encode finish ms delta | packetizer finish ms delta | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | pacer exit ms delta | network timestamp ms delta | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | network2 timestamp ms delta | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data, VideoSendTiming* timing) { … } bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data, const VideoSendTiming& timing) { … } bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data, uint16_t time_delta_ms, uint8_t offset) { … } // Color space including HDR metadata as an optional field. // // RTP header extension to carry color space information and optionally HDR // metadata. The float values in the HDR metadata struct are upscaled by a // static factor and transmitted as unsigned integers. // // Data layout of color space with HDR metadata (two-byte RTP header extension) // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | length=28 | primaries | transfer | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | matrix |range+chr.sit. | luminance_max | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | luminance_min | mastering_metadata.| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |primary_r.x and .y | mastering_metadata.| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |primary_g.x and .y | mastering_metadata.| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |primary_b.x and .y | mastering_metadata.| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |white.x and .y | max_content_light_level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | max_frame_average_light_level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Data layout of color space w/o HDR metadata (one-byte RTP header extension) // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L = 3 | primaries | transfer | matrix | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |range+chr.sit. | // +-+-+-+-+-+-+-+-+ bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data, ColorSpace* color_space) { … } bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data, const ColorSpace& color_space) { … } // Combines range and chroma siting into one byte with the following bit layout: // bits 0-1 Chroma siting vertical. // 2-3 Chroma siting horizontal. // 4-5 Range. // 6-7 Unused. uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting( ColorSpace::RangeID range, ColorSpace::ChromaSiting chroma_siting_horizontal, ColorSpace::ChromaSiting chroma_siting_vertical) { … } size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data, HdrMetadata* hdr_metadata) { … } size_t ColorSpaceExtension::ParseChromaticity( const uint8_t* data, HdrMasteringMetadata::Chromaticity* p) { … } size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data, float* f, int denominator) { … } size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data, const HdrMetadata& hdr_metadata) { … } size_t ColorSpaceExtension::WriteChromaticity( uint8_t* data, const HdrMasteringMetadata::Chromaticity& p) { … } size_t ColorSpaceExtension::WriteLuminance(uint8_t* data, float f, int denominator) { … } bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data, std::string* str) { … } bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data, absl::string_view str) { … } // An RTP Header Extension for Inband Comfort Noise // // The form of the audio level extension block: // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |N| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the One-Byte Header Format // // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=1 |N| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Sample Audio Level Encoding Using the Two-Byte Header Format bool InbandComfortNoiseExtension::Parse(rtc::ArrayView<const uint8_t> data, absl::optional<uint8_t>* level) { … } bool InbandComfortNoiseExtension::Write(rtc::ArrayView<uint8_t> data, absl::optional<uint8_t> level) { … } // VideoFrameTrackingIdExtension // // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=1 | video-frame-tracking-id | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ bool VideoFrameTrackingIdExtension::Parse(rtc::ArrayView<const uint8_t> data, uint16_t* video_frame_tracking_id) { … } bool VideoFrameTrackingIdExtension::Write(rtc::ArrayView<uint8_t> data, uint16_t video_frame_tracking_id) { … } } // namespace webrtc