1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
12
13 #include <string.h>
14
15 #include <cmath>
16 #include <limits>
17
18 #include "modules/rtp_rtcp/include/rtp_cvo.h"
19 #include "modules/rtp_rtcp/source/byte_io.h"
20 // TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
21 #include "modules/video_coding/codecs/interface/common_constants.h"
22 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
23 #include "rtc_base/checks.h"
24
25 namespace webrtc {
26 // Absolute send time in RTP streams.
27 //
28 // The absolute send time is signaled to the receiver in-band using the
29 // general mechanism for RTP header extensions [RFC8285]. The payload
30 // of this extension (the transmitted value) is a 24-bit unsigned integer
31 // containing the sender's current time in seconds as a fixed point number
32 // with 18 bits fractional part.
33 //
34 // The form of the absolute send time extension block:
35 //
36 // 0 1 2 3
37 // 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
38 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 // | ID | len=2 | absolute send time |
40 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 constexpr RTPExtensionType AbsoluteSendTime::kId;
42 constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
43 constexpr const char AbsoluteSendTime::kUri[];
44
Parse(rtc::ArrayView<const uint8_t> data,uint32_t * time_24bits)45 bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
46 uint32_t* time_24bits) {
47 if (data.size() != 3)
48 return false;
49 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
50 return true;
51 }
52
Write(rtc::ArrayView<uint8_t> data,uint32_t time_24bits)53 bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
54 uint32_t time_24bits) {
55 RTC_DCHECK_EQ(data.size(), 3);
56 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
57 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
58 return true;
59 }
60
61 // Absolute Capture Time
62 //
63 // The Absolute Capture Time extension is used to stamp RTP packets with a NTP
64 // timestamp showing when the first audio or video frame in a packet was
65 // originally captured. The intent of this extension is to provide a way to
66 // accomplish audio-to-video synchronization when RTCP-terminating intermediate
67 // systems (e.g. mixers) are involved.
68 //
69 // Data layout of the shortened version of abs-capture-time:
70 //
71 // 0 1 2 3
72 // 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
73 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 // | ID | len=7 | absolute capture timestamp (bit 0-23) |
75 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 // | absolute capture timestamp (bit 24-55) |
77 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 // | ... (56-63) |
79 // +-+-+-+-+-+-+-+-+
80 //
81 // Data layout of the extended version of abs-capture-time:
82 //
83 // 0 1 2 3
84 // 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
85 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86 // | ID | len=15| absolute capture timestamp (bit 0-23) |
87 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 // | absolute capture timestamp (bit 24-55) |
89 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 // | ... (56-63) | estimated capture clock offset (bit 0-23) |
91 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92 // | estimated capture clock offset (bit 24-55) |
93 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 // | ... (56-63) |
95 // +-+-+-+-+-+-+-+-+
96 constexpr RTPExtensionType AbsoluteCaptureTimeExtension::kId;
97 constexpr uint8_t AbsoluteCaptureTimeExtension::kValueSizeBytes;
98 constexpr uint8_t AbsoluteCaptureTimeExtension::
99 kValueSizeBytesWithoutEstimatedCaptureClockOffset;
100 constexpr const char AbsoluteCaptureTimeExtension::kUri[];
101
Parse(rtc::ArrayView<const uint8_t> data,AbsoluteCaptureTime * extension)102 bool AbsoluteCaptureTimeExtension::Parse(rtc::ArrayView<const uint8_t> data,
103 AbsoluteCaptureTime* extension) {
104 if (data.size() != kValueSizeBytes &&
105 data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
106 return false;
107 }
108
109 extension->absolute_capture_timestamp =
110 ByteReader<uint64_t>::ReadBigEndian(data.data());
111
112 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
113 extension->estimated_capture_clock_offset =
114 ByteReader<int64_t>::ReadBigEndian(data.data() + 8);
115 }
116
117 return true;
118 }
119
ValueSize(const AbsoluteCaptureTime & extension)120 size_t AbsoluteCaptureTimeExtension::ValueSize(
121 const AbsoluteCaptureTime& extension) {
122 if (extension.estimated_capture_clock_offset != absl::nullopt) {
123 return kValueSizeBytes;
124 } else {
125 return kValueSizeBytesWithoutEstimatedCaptureClockOffset;
126 }
127 }
128
Write(rtc::ArrayView<uint8_t> data,const AbsoluteCaptureTime & extension)129 bool AbsoluteCaptureTimeExtension::Write(rtc::ArrayView<uint8_t> data,
130 const AbsoluteCaptureTime& extension) {
131 RTC_DCHECK_EQ(data.size(), ValueSize(extension));
132
133 ByteWriter<uint64_t>::WriteBigEndian(data.data(),
134 extension.absolute_capture_timestamp);
135
136 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
137 ByteWriter<int64_t>::WriteBigEndian(
138 data.data() + 8, extension.estimated_capture_clock_offset.value());
139 }
140
141 return true;
142 }
143
144 // An RTP Header Extension for Client-to-Mixer Audio Level Indication
145 //
146 // https://tools.ietf.org/html/rfc6464
147 //
148 // The form of the audio level extension block:
149 //
150 // 0 1
151 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
152 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 // | ID | len=0 |V| level |
154 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155 // Sample Audio Level Encoding Using the One-Byte Header Format
156 //
157 // 0 1 2
158 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
159 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160 // | ID | len=1 |V| level |
161 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 // Sample Audio Level Encoding Using the Two-Byte Header Format
163
164 constexpr RTPExtensionType AudioLevel::kId;
165 constexpr uint8_t AudioLevel::kValueSizeBytes;
166 constexpr const char AudioLevel::kUri[];
167
Parse(rtc::ArrayView<const uint8_t> data,bool * voice_activity,uint8_t * audio_level)168 bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
169 bool* voice_activity,
170 uint8_t* audio_level) {
171 // One-byte and two-byte format share the same data definition.
172 if (data.size() != 1)
173 return false;
174 *voice_activity = (data[0] & 0x80) != 0;
175 *audio_level = data[0] & 0x7F;
176 return true;
177 }
178
Write(rtc::ArrayView<uint8_t> data,bool voice_activity,uint8_t audio_level)179 bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
180 bool voice_activity,
181 uint8_t audio_level) {
182 // One-byte and two-byte format share the same data definition.
183 RTC_DCHECK_EQ(data.size(), 1);
184 RTC_CHECK_LE(audio_level, 0x7f);
185 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
186 return true;
187 }
188
189 // From RFC 5450: Transmission Time Offsets in RTP Streams.
190 //
191 // The transmission time is signaled to the receiver in-band using the
192 // general mechanism for RTP header extensions [RFC8285]. The payload
193 // of this extension (the transmitted value) is a 24-bit signed integer.
194 // When added to the RTP timestamp of the packet, it represents the
195 // "effective" RTP transmission time of the packet, on the RTP
196 // timescale.
197 //
198 // The form of the transmission offset extension block:
199 //
200 // 0 1 2 3
201 // 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
202 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
203 // | ID | len=2 | transmission offset |
204 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
205 constexpr RTPExtensionType TransmissionOffset::kId;
206 constexpr uint8_t TransmissionOffset::kValueSizeBytes;
207 constexpr const char TransmissionOffset::kUri[];
208
Parse(rtc::ArrayView<const uint8_t> data,int32_t * rtp_time)209 bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
210 int32_t* rtp_time) {
211 if (data.size() != 3)
212 return false;
213 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
214 return true;
215 }
216
Write(rtc::ArrayView<uint8_t> data,int32_t rtp_time)217 bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
218 RTC_DCHECK_EQ(data.size(), 3);
219 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
220 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
221 return true;
222 }
223
224 // TransportSequenceNumber
225 //
226 // 0 1 2
227 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
228 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
229 // | ID | L=1 |transport-wide sequence number |
230 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
231 constexpr RTPExtensionType TransportSequenceNumber::kId;
232 constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
233 constexpr const char TransportSequenceNumber::kUri[];
234
Parse(rtc::ArrayView<const uint8_t> data,uint16_t * transport_sequence_number)235 bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
236 uint16_t* transport_sequence_number) {
237 if (data.size() != kValueSizeBytes)
238 return false;
239 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
240 return true;
241 }
242
Write(rtc::ArrayView<uint8_t> data,uint16_t transport_sequence_number)243 bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
244 uint16_t transport_sequence_number) {
245 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
246 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
247 return true;
248 }
249
250 // TransportSequenceNumberV2
251 //
252 // In addition to the format used for TransportSequencNumber, V2 also supports
253 // the following packet format where two extra bytes are used to specify that
254 // the sender requests immediate feedback.
255 // 0 1 2 3
256 // 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
257 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258 // | ID | L=3 |transport-wide sequence number |T| seq count |
259 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
260 // |seq count cont.|
261 // +-+-+-+-+-+-+-+-+
262 //
263 // The bit |T| determines whether the feedback should include timing information
264 // or not and |seq_count| determines how many packets the feedback packet should
265 // cover including the current packet. If |seq_count| is zero no feedback is
266 // requested.
267 constexpr RTPExtensionType TransportSequenceNumberV2::kId;
268 constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
269 constexpr uint8_t
270 TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
271 constexpr const char TransportSequenceNumberV2::kUri[];
272 constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
273
Parse(rtc::ArrayView<const uint8_t> data,uint16_t * transport_sequence_number,absl::optional<FeedbackRequest> * feedback_request)274 bool TransportSequenceNumberV2::Parse(
275 rtc::ArrayView<const uint8_t> data,
276 uint16_t* transport_sequence_number,
277 absl::optional<FeedbackRequest>* feedback_request) {
278 if (data.size() != kValueSizeBytes &&
279 data.size() != kValueSizeBytesWithoutFeedbackRequest)
280 return false;
281
282 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
283
284 *feedback_request = absl::nullopt;
285 if (data.size() == kValueSizeBytes) {
286 uint16_t feedback_request_raw =
287 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
288 bool include_timestamps =
289 (feedback_request_raw & kIncludeTimestampsBit) != 0;
290 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
291
292 // If |sequence_count| is zero no feedback is requested.
293 if (sequence_count != 0) {
294 *feedback_request = {include_timestamps, sequence_count};
295 }
296 }
297 return true;
298 }
299
Write(rtc::ArrayView<uint8_t> data,uint16_t transport_sequence_number,const absl::optional<FeedbackRequest> & feedback_request)300 bool TransportSequenceNumberV2::Write(
301 rtc::ArrayView<uint8_t> data,
302 uint16_t transport_sequence_number,
303 const absl::optional<FeedbackRequest>& feedback_request) {
304 RTC_DCHECK_EQ(data.size(),
305 ValueSize(transport_sequence_number, feedback_request));
306
307 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
308
309 if (feedback_request) {
310 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
311 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
312 uint16_t feedback_request_raw =
313 feedback_request->sequence_count |
314 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
315 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
316 }
317 return true;
318 }
319
320 // Coordination of Video Orientation in RTP streams.
321 //
322 // Coordination of Video Orientation consists in signaling of the current
323 // orientation of the image captured on the sender side to the receiver for
324 // appropriate rendering and displaying.
325 //
326 // 0 1
327 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
328 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329 // | ID | len=0 |0 0 0 0 C F R R|
330 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 constexpr RTPExtensionType VideoOrientation::kId;
332 constexpr uint8_t VideoOrientation::kValueSizeBytes;
333 constexpr const char VideoOrientation::kUri[];
334
Parse(rtc::ArrayView<const uint8_t> data,VideoRotation * rotation)335 bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
336 VideoRotation* rotation) {
337 if (data.size() != 1)
338 return false;
339 *rotation = ConvertCVOByteToVideoRotation(data[0]);
340 return true;
341 }
342
Write(rtc::ArrayView<uint8_t> data,VideoRotation rotation)343 bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
344 VideoRotation rotation) {
345 RTC_DCHECK_EQ(data.size(), 1);
346 data[0] = ConvertVideoRotationToCVOByte(rotation);
347 return true;
348 }
349
Parse(rtc::ArrayView<const uint8_t> data,uint8_t * value)350 bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
351 uint8_t* value) {
352 if (data.size() != 1)
353 return false;
354 *value = data[0];
355 return true;
356 }
357
Write(rtc::ArrayView<uint8_t> data,uint8_t value)358 bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
359 RTC_DCHECK_EQ(data.size(), 1);
360 data[0] = value;
361 return true;
362 }
363
364 // 0 1 2 3
365 // 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
366 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367 // | ID | len=2 | MIN delay | MAX delay |
368 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
369 constexpr RTPExtensionType PlayoutDelayLimits::kId;
370 constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
371 constexpr const char PlayoutDelayLimits::kUri[];
372
Parse(rtc::ArrayView<const uint8_t> data,PlayoutDelay * playout_delay)373 bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
374 PlayoutDelay* playout_delay) {
375 RTC_DCHECK(playout_delay);
376 if (data.size() != 3)
377 return false;
378 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
379 uint16_t min_raw = (raw >> 12);
380 uint16_t max_raw = (raw & 0xfff);
381 if (min_raw > max_raw)
382 return false;
383 playout_delay->min_ms = min_raw * kGranularityMs;
384 playout_delay->max_ms = max_raw * kGranularityMs;
385 return true;
386 }
387
Write(rtc::ArrayView<uint8_t> data,const PlayoutDelay & playout_delay)388 bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
389 const PlayoutDelay& playout_delay) {
390 RTC_DCHECK_EQ(data.size(), 3);
391 RTC_DCHECK_LE(0, playout_delay.min_ms);
392 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
393 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
394 // Convert MS to value to be sent on extension header.
395 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
396 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
397 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
398 (min_delay << 12) | max_delay);
399 return true;
400 }
401
402 // Video Content Type.
403 //
404 // E.g. default video or screenshare.
405 //
406 // 0 1
407 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
408 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 // | ID | len=0 | Content type |
410 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 constexpr RTPExtensionType VideoContentTypeExtension::kId;
412 constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
413 constexpr const char VideoContentTypeExtension::kUri[];
414
Parse(rtc::ArrayView<const uint8_t> data,VideoContentType * content_type)415 bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
416 VideoContentType* content_type) {
417 if (data.size() == 1 &&
418 videocontenttypehelpers::IsValidContentType(data[0])) {
419 *content_type = static_cast<VideoContentType>(data[0]);
420 return true;
421 }
422 return false;
423 }
424
Write(rtc::ArrayView<uint8_t> data,VideoContentType content_type)425 bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
426 VideoContentType content_type) {
427 RTC_DCHECK_EQ(data.size(), 1);
428 data[0] = static_cast<uint8_t>(content_type);
429 return true;
430 }
431
432 // Video Timing.
433 // 6 timestamps in milliseconds counted from capture time stored in rtp header:
434 // encode start/finish, packetization complete, pacer exit and reserved for
435 // modification by the network modification. |flags| is a bitmask and has the
436 // following allowed values:
437 // 0 = Valid data, but no flags available (backwards compatibility)
438 // 1 = Frame marked as timing frame due to cyclic timer.
439 // 2 = Frame marked as timing frame due to size being outside limit.
440 // 255 = Invalid. The whole timing frame extension should be ignored.
441 //
442 // 0 1 2 3
443 // 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
444 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
445 // | ID | len=12| flags | encode start ms delta |
446 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
447 // | encode finish ms delta | packetizer finish ms delta |
448 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
449 // | pacer exit ms delta | network timestamp ms delta |
450 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
451 // | network2 timestamp ms delta |
452 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453
454 constexpr RTPExtensionType VideoTimingExtension::kId;
455 constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
456 constexpr const char VideoTimingExtension::kUri[];
457 constexpr uint8_t VideoTimingExtension::kFlagsOffset;
458 constexpr uint8_t VideoTimingExtension::kEncodeStartDeltaOffset;
459 constexpr uint8_t VideoTimingExtension::kEncodeFinishDeltaOffset;
460 constexpr uint8_t VideoTimingExtension::kPacketizationFinishDeltaOffset;
461 constexpr uint8_t VideoTimingExtension::kPacerExitDeltaOffset;
462 constexpr uint8_t VideoTimingExtension::kNetworkTimestampDeltaOffset;
463 constexpr uint8_t VideoTimingExtension::kNetwork2TimestampDeltaOffset;
464
Parse(rtc::ArrayView<const uint8_t> data,VideoSendTiming * timing)465 bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
466 VideoSendTiming* timing) {
467 RTC_DCHECK(timing);
468 // TODO(sprang): Deprecate support for old wire format.
469 ptrdiff_t off = 0;
470 switch (data.size()) {
471 case kValueSizeBytes - 1:
472 timing->flags = 0;
473 off = 1; // Old wire format without the flags field.
474 break;
475 case kValueSizeBytes:
476 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
477 break;
478 default:
479 return false;
480 }
481
482 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
483 data.data() + kEncodeStartDeltaOffset - off);
484 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
485 data.data() + kEncodeFinishDeltaOffset - off);
486 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
487 data.data() + kPacketizationFinishDeltaOffset - off);
488 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
489 data.data() + kPacerExitDeltaOffset - off);
490 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
491 data.data() + kNetworkTimestampDeltaOffset - off);
492 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
493 data.data() + kNetwork2TimestampDeltaOffset - off);
494 return true;
495 }
496
Write(rtc::ArrayView<uint8_t> data,const VideoSendTiming & timing)497 bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
498 const VideoSendTiming& timing) {
499 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
500 ByteWriter<uint8_t>::WriteBigEndian(data.data() + kFlagsOffset, timing.flags);
501 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeStartDeltaOffset,
502 timing.encode_start_delta_ms);
503 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeFinishDeltaOffset,
504 timing.encode_finish_delta_ms);
505 ByteWriter<uint16_t>::WriteBigEndian(
506 data.data() + kPacketizationFinishDeltaOffset,
507 timing.packetization_finish_delta_ms);
508 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kPacerExitDeltaOffset,
509 timing.pacer_exit_delta_ms);
510 ByteWriter<uint16_t>::WriteBigEndian(
511 data.data() + kNetworkTimestampDeltaOffset,
512 timing.network_timestamp_delta_ms);
513 ByteWriter<uint16_t>::WriteBigEndian(
514 data.data() + kNetwork2TimestampDeltaOffset,
515 timing.network2_timestamp_delta_ms);
516 return true;
517 }
518
Write(rtc::ArrayView<uint8_t> data,uint16_t time_delta_ms,uint8_t offset)519 bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
520 uint16_t time_delta_ms,
521 uint8_t offset) {
522 RTC_DCHECK_GE(data.size(), offset + 2);
523 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
524 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
525 return true;
526 }
527
528 // Color space including HDR metadata as an optional field.
529 //
530 // RTP header extension to carry color space information and optionally HDR
531 // metadata. The float values in the HDR metadata struct are upscaled by a
532 // static factor and transmitted as unsigned integers.
533 //
534 // Data layout of color space with HDR metadata (two-byte RTP header extension)
535 // 0 1 2 3
536 // 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
537 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 // | ID | length=28 | primaries | transfer |
539 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540 // | matrix |range+chr.sit. | luminance_max |
541 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 // | luminance_min | mastering_metadata.|
543 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544 // |primary_r.x and .y | mastering_metadata.|
545 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546 // |primary_g.x and .y | mastering_metadata.|
547 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548 // |primary_b.x and .y | mastering_metadata.|
549 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550 // |white.x and .y | max_content_light_level |
551 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 // | max_frame_average_light_level |
553 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
554 //
555 // Data layout of color space w/o HDR metadata (one-byte RTP header extension)
556 // 0 1 2 3
557 // 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
558 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
559 // | ID | L = 3 | primaries | transfer | matrix |
560 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
561 // |range+chr.sit. |
562 // +-+-+-+-+-+-+-+-+
563
564 constexpr RTPExtensionType ColorSpaceExtension::kId;
565 constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
566 constexpr const char ColorSpaceExtension::kUri[];
567
Parse(rtc::ArrayView<const uint8_t> data,ColorSpace * color_space)568 bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
569 ColorSpace* color_space) {
570 RTC_DCHECK(color_space);
571 if (data.size() != kValueSizeBytes &&
572 data.size() != kValueSizeBytesWithoutHdrMetadata)
573 return false;
574
575 size_t offset = 0;
576 // Read color space information.
577 if (!color_space->set_primaries_from_uint8(data[offset++]))
578 return false;
579 if (!color_space->set_transfer_from_uint8(data[offset++]))
580 return false;
581 if (!color_space->set_matrix_from_uint8(data[offset++]))
582 return false;
583
584 uint8_t range_and_chroma_siting = data[offset++];
585 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
586 return false;
587 if (!color_space->set_chroma_siting_horizontal_from_uint8(
588 (range_and_chroma_siting >> 2) & 0x03))
589 return false;
590 if (!color_space->set_chroma_siting_vertical_from_uint8(
591 range_and_chroma_siting & 0x03))
592 return false;
593
594 // Read HDR metadata if it exists, otherwise clear it.
595 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
596 color_space->set_hdr_metadata(nullptr);
597 } else {
598 HdrMetadata hdr_metadata;
599 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
600 if (!hdr_metadata.Validate())
601 return false;
602 color_space->set_hdr_metadata(&hdr_metadata);
603 }
604 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
605 return true;
606 }
607
Write(rtc::ArrayView<uint8_t> data,const ColorSpace & color_space)608 bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
609 const ColorSpace& color_space) {
610 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
611 size_t offset = 0;
612 // Write color space information.
613 data[offset++] = static_cast<uint8_t>(color_space.primaries());
614 data[offset++] = static_cast<uint8_t>(color_space.transfer());
615 data[offset++] = static_cast<uint8_t>(color_space.matrix());
616 data[offset++] = CombineRangeAndChromaSiting(
617 color_space.range(), color_space.chroma_siting_horizontal(),
618 color_space.chroma_siting_vertical());
619
620 // Write HDR metadata if it exists.
621 if (color_space.hdr_metadata()) {
622 offset +=
623 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
624 }
625 RTC_DCHECK_EQ(ValueSize(color_space), offset);
626 return true;
627 }
628
629 // Combines range and chroma siting into one byte with the following bit layout:
630 // bits 0-1 Chroma siting vertical.
631 // 2-3 Chroma siting horizontal.
632 // 4-5 Range.
633 // 6-7 Unused.
CombineRangeAndChromaSiting(ColorSpace::RangeID range,ColorSpace::ChromaSiting chroma_siting_horizontal,ColorSpace::ChromaSiting chroma_siting_vertical)634 uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
635 ColorSpace::RangeID range,
636 ColorSpace::ChromaSiting chroma_siting_horizontal,
637 ColorSpace::ChromaSiting chroma_siting_vertical) {
638 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
639 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
640 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
641 return (static_cast<uint8_t>(range) << 4) |
642 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
643 static_cast<uint8_t>(chroma_siting_vertical);
644 }
645
ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,HdrMetadata * hdr_metadata)646 size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
647 HdrMetadata* hdr_metadata) {
648 RTC_DCHECK_EQ(data.size(),
649 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
650 size_t offset = 0;
651 offset += ParseLuminance(data.data() + offset,
652 &hdr_metadata->mastering_metadata.luminance_max,
653 kLuminanceMaxDenominator);
654 offset += ParseLuminance(data.data() + offset,
655 &hdr_metadata->mastering_metadata.luminance_min,
656 kLuminanceMinDenominator);
657 offset += ParseChromaticity(data.data() + offset,
658 &hdr_metadata->mastering_metadata.primary_r);
659 offset += ParseChromaticity(data.data() + offset,
660 &hdr_metadata->mastering_metadata.primary_g);
661 offset += ParseChromaticity(data.data() + offset,
662 &hdr_metadata->mastering_metadata.primary_b);
663 offset += ParseChromaticity(data.data() + offset,
664 &hdr_metadata->mastering_metadata.white_point);
665 hdr_metadata->max_content_light_level =
666 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
667 offset += 2;
668 hdr_metadata->max_frame_average_light_level =
669 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
670 offset += 2;
671 return offset;
672 }
673
ParseChromaticity(const uint8_t * data,HdrMasteringMetadata::Chromaticity * p)674 size_t ColorSpaceExtension::ParseChromaticity(
675 const uint8_t* data,
676 HdrMasteringMetadata::Chromaticity* p) {
677 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
678 uint16_t chromaticity_y_scaled =
679 ByteReader<uint16_t>::ReadBigEndian(data + 2);
680 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
681 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
682 return 4; // Return number of bytes read.
683 }
684
ParseLuminance(const uint8_t * data,float * f,int denominator)685 size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
686 float* f,
687 int denominator) {
688 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
689 *f = static_cast<float>(luminance_scaled) / denominator;
690 return 2; // Return number of bytes read.
691 }
692
WriteHdrMetadata(rtc::ArrayView<uint8_t> data,const HdrMetadata & hdr_metadata)693 size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
694 const HdrMetadata& hdr_metadata) {
695 RTC_DCHECK_EQ(data.size(),
696 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
697 RTC_DCHECK(hdr_metadata.Validate());
698 size_t offset = 0;
699 offset += WriteLuminance(data.data() + offset,
700 hdr_metadata.mastering_metadata.luminance_max,
701 kLuminanceMaxDenominator);
702 offset += WriteLuminance(data.data() + offset,
703 hdr_metadata.mastering_metadata.luminance_min,
704 kLuminanceMinDenominator);
705 offset += WriteChromaticity(data.data() + offset,
706 hdr_metadata.mastering_metadata.primary_r);
707 offset += WriteChromaticity(data.data() + offset,
708 hdr_metadata.mastering_metadata.primary_g);
709 offset += WriteChromaticity(data.data() + offset,
710 hdr_metadata.mastering_metadata.primary_b);
711 offset += WriteChromaticity(data.data() + offset,
712 hdr_metadata.mastering_metadata.white_point);
713
714 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
715 hdr_metadata.max_content_light_level);
716 offset += 2;
717 ByteWriter<uint16_t>::WriteBigEndian(
718 data.data() + offset, hdr_metadata.max_frame_average_light_level);
719 offset += 2;
720 return offset;
721 }
722
WriteChromaticity(uint8_t * data,const HdrMasteringMetadata::Chromaticity & p)723 size_t ColorSpaceExtension::WriteChromaticity(
724 uint8_t* data,
725 const HdrMasteringMetadata::Chromaticity& p) {
726 RTC_DCHECK_GE(p.x, 0.0f);
727 RTC_DCHECK_LE(p.x, 1.0f);
728 RTC_DCHECK_GE(p.y, 0.0f);
729 RTC_DCHECK_LE(p.y, 1.0f);
730 ByteWriter<uint16_t>::WriteBigEndian(
731 data, std::round(p.x * kChromaticityDenominator));
732 ByteWriter<uint16_t>::WriteBigEndian(
733 data + 2, std::round(p.y * kChromaticityDenominator));
734 return 4; // Return number of bytes written.
735 }
736
WriteLuminance(uint8_t * data,float f,int denominator)737 size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
738 float f,
739 int denominator) {
740 RTC_DCHECK_GE(f, 0.0f);
741 float upscaled_value = f * denominator;
742 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
743 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
744 return 2; // Return number of bytes written.
745 }
746
Parse(rtc::ArrayView<const uint8_t> data,std::string * str)747 bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
748 std::string* str) {
749 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
750 return false;
751 const char* cstr = reinterpret_cast<const char*>(data.data());
752 // If there is a \0 character in the middle of the |data|, treat it as end
753 // of the string. Well-formed string extensions shouldn't contain it.
754 str->assign(cstr, strnlen(cstr, data.size()));
755 RTC_DCHECK(!str->empty());
756 return true;
757 }
758
Write(rtc::ArrayView<uint8_t> data,const std::string & str)759 bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
760 const std::string& str) {
761 if (str.size() > kMaxValueSizeBytes) {
762 return false;
763 }
764 RTC_DCHECK_EQ(data.size(), str.size());
765 RTC_DCHECK_GE(str.size(), 1);
766 memcpy(data.data(), str.data(), str.size());
767 return true;
768 }
769
770 // Constant declarations for string RTP header extension types.
771
772 constexpr RTPExtensionType RtpStreamId::kId;
773 constexpr const char RtpStreamId::kUri[];
774
775 constexpr RTPExtensionType RepairedRtpStreamId::kId;
776 constexpr const char RepairedRtpStreamId::kUri[];
777
778 constexpr RTPExtensionType RtpMid::kId;
779 constexpr const char RtpMid::kUri[];
780
781 // An RTP Header Extension for Inband Comfort Noise
782 //
783 // The form of the audio level extension block:
784 //
785 // 0 1
786 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
787 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
788 // | ID | len=0 |N| level |
789 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
790 // Sample Audio Level Encoding Using the One-Byte Header Format
791 //
792 // 0 1 2
793 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
794 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
795 // | ID | len=1 |N| level |
796 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
797 // Sample Audio Level Encoding Using the Two-Byte Header Format
798
799 constexpr RTPExtensionType InbandComfortNoiseExtension::kId;
800 constexpr uint8_t InbandComfortNoiseExtension::kValueSizeBytes;
801 constexpr const char InbandComfortNoiseExtension::kUri[];
802
Parse(rtc::ArrayView<const uint8_t> data,absl::optional<uint8_t> * level)803 bool InbandComfortNoiseExtension::Parse(rtc::ArrayView<const uint8_t> data,
804 absl::optional<uint8_t>* level) {
805 if (data.size() != kValueSizeBytes)
806 return false;
807 *level = (data[0] & 0b1000'0000) != 0
808 ? absl::nullopt
809 : absl::make_optional(data[0] & 0b0111'1111);
810 return true;
811 }
812
Write(rtc::ArrayView<uint8_t> data,absl::optional<uint8_t> level)813 bool InbandComfortNoiseExtension::Write(rtc::ArrayView<uint8_t> data,
814 absl::optional<uint8_t> level) {
815 RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
816 data[0] = 0b0000'0000;
817 if (level) {
818 if (*level > 127) {
819 return false;
820 }
821 data[0] = 0b1000'0000 | *level;
822 }
823 return true;
824 }
825
826 } // namespace webrtc
827