blob: 1dd4f547597de86c73abea91d7c335c33a78f94b [file] [log] [blame]
danilchap1edb7ab2016-04-20 05:25:10 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
danilchap1edb7ab2016-04-20 05:25:10 -070012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Johannes Kronad1d9f02018-11-09 11:12:36 +010015#include <cmath>
Doudou Kisabakaae0d1172021-05-24 13:04:45 +020016#include <cstdint>
Johannes Kronc13f4be2018-12-12 09:52:53 +010017#include <limits>
Yves Gerey988cc082018-10-23 12:03:01 +020018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/rtp_rtcp/include/rtp_cvo.h"
20#include "modules/rtp_rtcp/source/byte_io.h"
Yves Gerey988cc082018-10-23 12:03:01 +020021// TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
22#include "modules/video_coding/codecs/interface/common_constants.h"
Niels Möller834a5542019-09-23 10:31:16 +020023#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070025
26namespace webrtc {
27// Absolute send time in RTP streams.
28//
29// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020030// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070031// of this extension (the transmitted value) is a 24-bit unsigned integer
32// containing the sender's current time in seconds as a fixed point number
33// with 18 bits fractional part.
34//
35// The form of the absolute send time extension block:
36//
37// 0 1 2 3
38// 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
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40// | ID | len=2 | absolute send time |
41// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070042constexpr RTPExtensionType AbsoluteSendTime::kId;
43constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070044constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070045
danilchap978504e2017-04-06 01:03:53 -070046bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
47 uint32_t* time_24bits) {
48 if (data.size() != 3)
49 return false;
50 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -070051 return true;
52}
53
Danil Chapovalov9bf31582018-06-18 13:48:20 +020054bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
55 uint32_t time_24bits) {
56 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020057 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020058 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070059 return true;
60}
61
Chen Xingcd8a6e22019-07-01 10:56:51 +020062// Absolute Capture Time
63//
64// The Absolute Capture Time extension is used to stamp RTP packets with a NTP
65// timestamp showing when the first audio or video frame in a packet was
66// originally captured. The intent of this extension is to provide a way to
67// accomplish audio-to-video synchronization when RTCP-terminating intermediate
68// systems (e.g. mixers) are involved.
69//
70// Data layout of the shortened version of abs-capture-time:
71//
72// 0 1 2 3
73// 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
74// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75// | ID | len=7 | absolute capture timestamp (bit 0-23) |
76// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77// | absolute capture timestamp (bit 24-55) |
78// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79// | ... (56-63) |
80// +-+-+-+-+-+-+-+-+
81//
82// Data layout of the extended version of abs-capture-time:
83//
84// 0 1 2 3
85// 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
86// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87// | ID | len=15| absolute capture timestamp (bit 0-23) |
88// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89// | absolute capture timestamp (bit 24-55) |
90// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91// | ... (56-63) | estimated capture clock offset (bit 0-23) |
92// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93// | estimated capture clock offset (bit 24-55) |
94// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95// | ... (56-63) |
96// +-+-+-+-+-+-+-+-+
97constexpr RTPExtensionType AbsoluteCaptureTimeExtension::kId;
98constexpr uint8_t AbsoluteCaptureTimeExtension::kValueSizeBytes;
99constexpr uint8_t AbsoluteCaptureTimeExtension::
100 kValueSizeBytesWithoutEstimatedCaptureClockOffset;
101constexpr const char AbsoluteCaptureTimeExtension::kUri[];
102
103bool AbsoluteCaptureTimeExtension::Parse(rtc::ArrayView<const uint8_t> data,
104 AbsoluteCaptureTime* extension) {
105 if (data.size() != kValueSizeBytes &&
106 data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
107 return false;
108 }
109
110 extension->absolute_capture_timestamp =
111 ByteReader<uint64_t>::ReadBigEndian(data.data());
112
113 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
114 extension->estimated_capture_clock_offset =
115 ByteReader<int64_t>::ReadBigEndian(data.data() + 8);
116 }
117
118 return true;
119}
120
121size_t AbsoluteCaptureTimeExtension::ValueSize(
122 const AbsoluteCaptureTime& extension) {
123 if (extension.estimated_capture_clock_offset != absl::nullopt) {
124 return kValueSizeBytes;
125 } else {
126 return kValueSizeBytesWithoutEstimatedCaptureClockOffset;
127 }
128}
129
130bool AbsoluteCaptureTimeExtension::Write(rtc::ArrayView<uint8_t> data,
131 const AbsoluteCaptureTime& extension) {
132 RTC_DCHECK_EQ(data.size(), ValueSize(extension));
133
134 ByteWriter<uint64_t>::WriteBigEndian(data.data(),
135 extension.absolute_capture_timestamp);
136
137 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
138 ByteWriter<int64_t>::WriteBigEndian(
139 data.data() + 8, extension.estimated_capture_clock_offset.value());
140 }
141
142 return true;
143}
144
danilchap1edb7ab2016-04-20 05:25:10 -0700145// An RTP Header Extension for Client-to-Mixer Audio Level Indication
146//
Minyue Lid1ea4c92019-10-31 10:59:18 +0100147// https://tools.ietf.org/html/rfc6464
danilchap1edb7ab2016-04-20 05:25:10 -0700148//
149// The form of the audio level extension block:
150//
Minyue Lid1ea4c92019-10-31 10:59:18 +0100151// 0 1
152// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
153// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154// | ID | len=0 |V| level |
155// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156// Sample Audio Level Encoding Using the One-Byte Header Format
danilchap1edb7ab2016-04-20 05:25:10 -0700157//
Minyue Lid1ea4c92019-10-31 10:59:18 +0100158// 0 1 2
159// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
160// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161// | ID | len=1 |V| level |
162// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163// Sample Audio Level Encoding Using the Two-Byte Header Format
164
danilchape2a01772016-10-28 07:08:58 -0700165constexpr RTPExtensionType AudioLevel::kId;
166constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700167constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700168
danilchap978504e2017-04-06 01:03:53 -0700169bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700170 bool* voice_activity,
171 uint8_t* audio_level) {
Minyue Lid1ea4c92019-10-31 10:59:18 +0100172 // One-byte and two-byte format share the same data definition.
danilchap978504e2017-04-06 01:03:53 -0700173 if (data.size() != 1)
174 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700175 *voice_activity = (data[0] & 0x80) != 0;
176 *audio_level = data[0] & 0x7F;
177 return true;
178}
179
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200180bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700181 bool voice_activity,
182 uint8_t audio_level) {
Minyue Lid1ea4c92019-10-31 10:59:18 +0100183 // One-byte and two-byte format share the same data definition.
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200184 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700185 RTC_CHECK_LE(audio_level, 0x7f);
186 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
187 return true;
188}
189
Doudou Kisabakaae0d1172021-05-24 13:04:45 +0200190// An RTP Header Extension for Mixer-to-Client Audio Level Indication
191//
192// https://tools.ietf.org/html/rfc6465
193//
194// The form of the audio level extension block:
195//
196// 0 1 2 3
197// 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
198// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
199// | ID | len=2 |0| level 1 |0| level 2 |0| level 3 |
200// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201// Sample Audio Level Encoding Using the One-Byte Header Format
202//
203// 0 1 2 3
204// 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
205// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206// | ID | len=3 |0| level 1 |0| level 2 |
207// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208// |0| level 3 | 0 (pad) | ... |
209// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210// Sample Audio Level Encoding Using the Two-Byte Header Format
211constexpr RTPExtensionType CsrcAudioLevel::kId;
212constexpr uint8_t CsrcAudioLevel::kMaxValueSizeBytes;
213constexpr const char CsrcAudioLevel::kUri[];
214
215bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
216 std::vector<uint8_t>* csrc_audio_levels) {
217 if (data.size() > kRtpCsrcSize) {
218 return false;
219 }
220 csrc_audio_levels->resize(data.size());
221 for (size_t i = 0; i < data.size(); i++) {
222 (*csrc_audio_levels)[i] = data[i] & 0x7F;
223 }
224 return true;
225}
226
227size_t CsrcAudioLevel::ValueSize(
228 rtc::ArrayView<const uint8_t> csrc_audio_levels) {
229 return csrc_audio_levels.size();
230}
231
232bool CsrcAudioLevel::Write(rtc::ArrayView<uint8_t> data,
233 rtc::ArrayView<const uint8_t> csrc_audio_levels) {
234 RTC_CHECK_LE(csrc_audio_levels.size(), kRtpCsrcSize);
235 if (csrc_audio_levels.size() != data.size()) {
236 return false;
237 }
238 for (size_t i = 0; i < csrc_audio_levels.size(); i++) {
239 data[i] = csrc_audio_levels[i] & 0x7F;
240 }
241 return true;
242}
243
danilchap1edb7ab2016-04-20 05:25:10 -0700244// From RFC 5450: Transmission Time Offsets in RTP Streams.
245//
246// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +0200247// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -0700248// of this extension (the transmitted value) is a 24-bit signed integer.
249// When added to the RTP timestamp of the packet, it represents the
250// "effective" RTP transmission time of the packet, on the RTP
251// timescale.
252//
253// The form of the transmission offset extension block:
254//
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 | len=2 | transmission offset |
259// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700260constexpr RTPExtensionType TransmissionOffset::kId;
261constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700262constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700263
danilchap978504e2017-04-06 01:03:53 -0700264bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
265 int32_t* rtp_time) {
266 if (data.size() != 3)
267 return false;
268 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700269 return true;
270}
271
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200272bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
273 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200274 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200275 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700276 return true;
277}
278
Johannes Kron54047be2019-02-21 14:09:20 +0000279// TransportSequenceNumber
280//
danilchap1edb7ab2016-04-20 05:25:10 -0700281// 0 1 2
282// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
283// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron54047be2019-02-21 14:09:20 +0000284// | ID | L=1 |transport-wide sequence number |
danilchap1edb7ab2016-04-20 05:25:10 -0700285// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700286constexpr RTPExtensionType TransportSequenceNumber::kId;
287constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700288constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700289
danilchap978504e2017-04-06 01:03:53 -0700290bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000291 uint16_t* transport_sequence_number) {
292 if (data.size() != kValueSizeBytes)
danilchap978504e2017-04-06 01:03:53 -0700293 return false;
Johannes Kron54047be2019-02-21 14:09:20 +0000294 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700295 return true;
296}
297
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200298bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000299 uint16_t transport_sequence_number) {
300 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
301 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
302 return true;
303}
304
305// TransportSequenceNumberV2
306//
307// In addition to the format used for TransportSequencNumber, V2 also supports
308// the following packet format where two extra bytes are used to specify that
309// the sender requests immediate feedback.
310// 0 1 2 3
311// 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
312// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
313// | ID | L=3 |transport-wide sequence number |T| seq count |
314// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
315// |seq count cont.|
316// +-+-+-+-+-+-+-+-+
317//
318// The bit |T| determines whether the feedback should include timing information
Johannes Kron0da25a12019-03-06 09:34:13 +0100319// or not and |seq_count| determines how many packets the feedback packet should
320// cover including the current packet. If |seq_count| is zero no feedback is
321// requested.
Johannes Kron54047be2019-02-21 14:09:20 +0000322constexpr RTPExtensionType TransportSequenceNumberV2::kId;
Johannes Kron0da25a12019-03-06 09:34:13 +0100323constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
324constexpr uint8_t
325 TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
Johannes Kron54047be2019-02-21 14:09:20 +0000326constexpr const char TransportSequenceNumberV2::kUri[];
327constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
328
329bool TransportSequenceNumberV2::Parse(
330 rtc::ArrayView<const uint8_t> data,
331 uint16_t* transport_sequence_number,
332 absl::optional<FeedbackRequest>* feedback_request) {
Johannes Kron0da25a12019-03-06 09:34:13 +0100333 if (data.size() != kValueSizeBytes &&
334 data.size() != kValueSizeBytesWithoutFeedbackRequest)
Johannes Kron54047be2019-02-21 14:09:20 +0000335 return false;
336
337 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
338
Johannes Kron0da25a12019-03-06 09:34:13 +0100339 *feedback_request = absl::nullopt;
340 if (data.size() == kValueSizeBytes) {
Johannes Kron54047be2019-02-21 14:09:20 +0000341 uint16_t feedback_request_raw =
342 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
343 bool include_timestamps =
344 (feedback_request_raw & kIncludeTimestampsBit) != 0;
345 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
Johannes Kron0da25a12019-03-06 09:34:13 +0100346
347 // If |sequence_count| is zero no feedback is requested.
348 if (sequence_count != 0) {
349 *feedback_request = {include_timestamps, sequence_count};
350 }
Johannes Kron54047be2019-02-21 14:09:20 +0000351 }
352 return true;
353}
354
355bool TransportSequenceNumberV2::Write(
356 rtc::ArrayView<uint8_t> data,
357 uint16_t transport_sequence_number,
358 const absl::optional<FeedbackRequest>& feedback_request) {
359 RTC_DCHECK_EQ(data.size(),
360 ValueSize(transport_sequence_number, feedback_request));
361
362 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
363
364 if (feedback_request) {
365 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
366 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
367 uint16_t feedback_request_raw =
368 feedback_request->sequence_count |
369 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
370 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
371 }
danilchap1edb7ab2016-04-20 05:25:10 -0700372 return true;
373}
374
375// Coordination of Video Orientation in RTP streams.
376//
377// Coordination of Video Orientation consists in signaling of the current
378// orientation of the image captured on the sender side to the receiver for
379// appropriate rendering and displaying.
380//
381// 0 1
382// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
383// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
384// | ID | len=0 |0 0 0 0 C F R R|
385// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700386constexpr RTPExtensionType VideoOrientation::kId;
387constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700388constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700389
danilchap978504e2017-04-06 01:03:53 -0700390bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
391 VideoRotation* rotation) {
392 if (data.size() != 1)
393 return false;
magjed71eb61c2016-09-08 03:24:58 -0700394 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700395 return true;
396}
397
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200398bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
399 VideoRotation rotation) {
400 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700401 data[0] = ConvertVideoRotationToCVOByte(rotation);
402 return true;
403}
404
danilchap978504e2017-04-06 01:03:53 -0700405bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
406 uint8_t* value) {
407 if (data.size() != 1)
408 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700409 *value = data[0];
410 return true;
411}
412
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200413bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
414 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700415 data[0] = value;
416 return true;
417}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200418
419// 0 1 2 3
420// 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
421// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422// | ID | len=2 | MIN delay | MAX delay |
423// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424constexpr RTPExtensionType PlayoutDelayLimits::kId;
425constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700426constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200427
danilchap978504e2017-04-06 01:03:53 -0700428bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Niels Möllerd381eed2020-09-02 15:34:40 +0200429 VideoPlayoutDelay* playout_delay) {
Danil Chapovalov08b03512016-09-07 15:08:13 +0200430 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700431 if (data.size() != 3)
432 return false;
433 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200434 uint16_t min_raw = (raw >> 12);
435 uint16_t max_raw = (raw & 0xfff);
436 if (min_raw > max_raw)
437 return false;
438 playout_delay->min_ms = min_raw * kGranularityMs;
439 playout_delay->max_ms = max_raw * kGranularityMs;
440 return true;
441}
442
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200443bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Niels Möllerd381eed2020-09-02 15:34:40 +0200444 const VideoPlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200445 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200446 RTC_DCHECK_LE(0, playout_delay.min_ms);
447 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
448 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
449 // Convert MS to value to be sent on extension header.
450 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
451 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200452 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
453 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200454 return true;
455}
456
ilnik00d802b2017-04-11 10:34:31 -0700457// Video Content Type.
458//
459// E.g. default video or screenshare.
460//
461// 0 1
462// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
463// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464// | ID | len=0 | Content type |
465// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466constexpr RTPExtensionType VideoContentTypeExtension::kId;
467constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700468constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700469
470bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
471 VideoContentType* content_type) {
472 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700473 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700474 *content_type = static_cast<VideoContentType>(data[0]);
475 return true;
476 }
477 return false;
478}
479
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200480bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700481 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200482 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700483 data[0] = static_cast<uint8_t>(content_type);
484 return true;
485}
486
ilnik04f4d122017-06-19 07:18:55 -0700487// Video Timing.
488// 6 timestamps in milliseconds counted from capture time stored in rtp header:
489// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700490// modification by the network modification. |flags| is a bitmask and has the
491// following allowed values:
492// 0 = Valid data, but no flags available (backwards compatibility)
493// 1 = Frame marked as timing frame due to cyclic timer.
494// 2 = Frame marked as timing frame due to size being outside limit.
495// 255 = Invalid. The whole timing frame extension should be ignored.
496//
ilnik04f4d122017-06-19 07:18:55 -0700497// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100498// 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
499// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
500// | ID | len=12| flags | encode start ms delta |
501// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
502// | encode finish ms delta | packetizer finish ms delta |
503// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504// | pacer exit ms delta | network timestamp ms delta |
505// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700506// | network2 timestamp ms delta |
507// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700508
509constexpr RTPExtensionType VideoTimingExtension::kId;
510constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700511constexpr const char VideoTimingExtension::kUri[];
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100512constexpr uint8_t VideoTimingExtension::kFlagsOffset;
513constexpr uint8_t VideoTimingExtension::kEncodeStartDeltaOffset;
514constexpr uint8_t VideoTimingExtension::kEncodeFinishDeltaOffset;
515constexpr uint8_t VideoTimingExtension::kPacketizationFinishDeltaOffset;
516constexpr uint8_t VideoTimingExtension::kPacerExitDeltaOffset;
517constexpr uint8_t VideoTimingExtension::kNetworkTimestampDeltaOffset;
518constexpr uint8_t VideoTimingExtension::kNetwork2TimestampDeltaOffset;
ilnik04f4d122017-06-19 07:18:55 -0700519
520bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700521 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700522 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700523 // TODO(sprang): Deprecate support for old wire format.
524 ptrdiff_t off = 0;
525 switch (data.size()) {
526 case kValueSizeBytes - 1:
527 timing->flags = 0;
528 off = 1; // Old wire format without the flags field.
529 break;
530 case kValueSizeBytes:
531 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
532 break;
533 default:
534 return false;
535 }
536
537 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100538 data.data() + kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700539 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100540 data.data() + kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700541 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100542 data.data() + kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700543 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100544 data.data() + kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100545 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100546 data.data() + kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100547 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100548 data.data() + kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700549 return true;
550}
551
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200552bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
553 const VideoSendTiming& timing) {
554 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100555 ByteWriter<uint8_t>::WriteBigEndian(data.data() + kFlagsOffset, timing.flags);
556 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeStartDeltaOffset,
557 timing.encode_start_delta_ms);
558 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeFinishDeltaOffset,
559 timing.encode_finish_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700560 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100561 data.data() + kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700562 timing.packetization_finish_delta_ms);
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100563 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kPacerExitDeltaOffset,
564 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700565 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100566 data.data() + kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100567 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700568 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 15:37:31 +0100569 data.data() + kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100570 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700571 return true;
572}
573
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200574bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700575 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700576 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200577 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100578 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200579 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700580 return true;
581}
582
Johannes Kron09d65882018-11-27 14:36:41 +0100583// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100584//
Johannes Krond0b69a82018-12-03 14:18:53 +0100585// RTP header extension to carry color space information and optionally HDR
586// metadata. The float values in the HDR metadata struct are upscaled by a
587// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100588//
Johannes Krond0b69a82018-12-03 14:18:53 +0100589// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100590// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100591// 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
592// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100593// | ID | length=28 | primaries | transfer |
Johannes Krond0b69a82018-12-03 14:18:53 +0100594// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100595// | matrix |range+chr.sit. | luminance_max |
Johannes Krond0b69a82018-12-03 14:18:53 +0100596// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100597// | luminance_min | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100598// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100599// |primary_r.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100600// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100601// |primary_g.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100602// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100603// |primary_b.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100604// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100605// |white.x and .y | max_content_light_level |
Johannes Krond0b69a82018-12-03 14:18:53 +0100606// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100607// | max_frame_average_light_level |
608// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 14:36:41 +0100609//
Johannes Krond0b69a82018-12-03 14:18:53 +0100610// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 14:36:41 +0100611// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100612// 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
613// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100614// | ID | L = 3 | primaries | transfer | matrix |
Johannes Krond0b69a82018-12-03 14:18:53 +0100615// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100616// |range+chr.sit. |
Johannes Krond0b69a82018-12-03 14:18:53 +0100617// +-+-+-+-+-+-+-+-+
Johannes Kronad1d9f02018-11-09 11:12:36 +0100618
Johannes Kron09d65882018-11-27 14:36:41 +0100619constexpr RTPExtensionType ColorSpaceExtension::kId;
620constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
621constexpr const char ColorSpaceExtension::kUri[];
622
623bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
624 ColorSpace* color_space) {
625 RTC_DCHECK(color_space);
626 if (data.size() != kValueSizeBytes &&
627 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100628 return false;
629
630 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100631 // Read color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100632 if (!color_space->set_primaries_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100633 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100634 if (!color_space->set_transfer_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100635 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100636 if (!color_space->set_matrix_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100637 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100638
639 uint8_t range_and_chroma_siting = data[offset++];
640 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
641 return false;
642 if (!color_space->set_chroma_siting_horizontal_from_uint8(
643 (range_and_chroma_siting >> 2) & 0x03))
644 return false;
645 if (!color_space->set_chroma_siting_vertical_from_uint8(
646 range_and_chroma_siting & 0x03))
Johannes Kron09d65882018-11-27 14:36:41 +0100647 return false;
648
649 // Read HDR metadata if it exists, otherwise clear it.
650 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
651 color_space->set_hdr_metadata(nullptr);
652 } else {
653 HdrMetadata hdr_metadata;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100654 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
655 if (!hdr_metadata.Validate())
656 return false;
Johannes Kron09d65882018-11-27 14:36:41 +0100657 color_space->set_hdr_metadata(&hdr_metadata);
658 }
659 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100660 return true;
661}
662
Johannes Kron09d65882018-11-27 14:36:41 +0100663bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
664 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 14:18:53 +0100665 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 11:12:36 +0100666 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100667 // Write color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100668 data[offset++] = static_cast<uint8_t>(color_space.primaries());
669 data[offset++] = static_cast<uint8_t>(color_space.transfer());
670 data[offset++] = static_cast<uint8_t>(color_space.matrix());
671 data[offset++] = CombineRangeAndChromaSiting(
672 color_space.range(), color_space.chroma_siting_horizontal(),
673 color_space.chroma_siting_vertical());
Johannes Kronad1d9f02018-11-09 11:12:36 +0100674
Johannes Kron09d65882018-11-27 14:36:41 +0100675 // Write HDR metadata if it exists.
676 if (color_space.hdr_metadata()) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100677 offset +=
678 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
Johannes Kron09d65882018-11-27 14:36:41 +0100679 }
680 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100681 return true;
682}
683
Johannes Kronc13f4be2018-12-12 09:52:53 +0100684// Combines range and chroma siting into one byte with the following bit layout:
685// bits 0-1 Chroma siting vertical.
686// 2-3 Chroma siting horizontal.
687// 4-5 Range.
688// 6-7 Unused.
689uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
690 ColorSpace::RangeID range,
691 ColorSpace::ChromaSiting chroma_siting_horizontal,
692 ColorSpace::ChromaSiting chroma_siting_vertical) {
693 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
694 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
695 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
696 return (static_cast<uint8_t>(range) << 4) |
697 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
698 static_cast<uint8_t>(chroma_siting_vertical);
699}
700
701size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
702 HdrMetadata* hdr_metadata) {
703 RTC_DCHECK_EQ(data.size(),
704 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
705 size_t offset = 0;
706 offset += ParseLuminance(data.data() + offset,
707 &hdr_metadata->mastering_metadata.luminance_max,
708 kLuminanceMaxDenominator);
709 offset += ParseLuminance(data.data() + offset,
710 &hdr_metadata->mastering_metadata.luminance_min,
711 kLuminanceMinDenominator);
712 offset += ParseChromaticity(data.data() + offset,
713 &hdr_metadata->mastering_metadata.primary_r);
714 offset += ParseChromaticity(data.data() + offset,
715 &hdr_metadata->mastering_metadata.primary_g);
716 offset += ParseChromaticity(data.data() + offset,
717 &hdr_metadata->mastering_metadata.primary_b);
718 offset += ParseChromaticity(data.data() + offset,
719 &hdr_metadata->mastering_metadata.white_point);
720 hdr_metadata->max_content_light_level =
721 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
722 offset += 2;
723 hdr_metadata->max_frame_average_light_level =
724 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
725 offset += 2;
726 return offset;
727}
728
Johannes Kron09d65882018-11-27 14:36:41 +0100729size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100730 const uint8_t* data,
731 HdrMasteringMetadata::Chromaticity* p) {
732 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
733 uint16_t chromaticity_y_scaled =
734 ByteReader<uint16_t>::ReadBigEndian(data + 2);
735 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
736 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
737 return 4; // Return number of bytes read.
738}
739
Johannes Kron09d65882018-11-27 14:36:41 +0100740size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
741 float* f,
742 int denominator) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100743 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100744 *f = static_cast<float>(luminance_scaled) / denominator;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100745 return 2; // Return number of bytes read.
746}
747
748size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
749 const HdrMetadata& hdr_metadata) {
750 RTC_DCHECK_EQ(data.size(),
751 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
752 RTC_DCHECK(hdr_metadata.Validate());
753 size_t offset = 0;
754 offset += WriteLuminance(data.data() + offset,
755 hdr_metadata.mastering_metadata.luminance_max,
756 kLuminanceMaxDenominator);
757 offset += WriteLuminance(data.data() + offset,
758 hdr_metadata.mastering_metadata.luminance_min,
759 kLuminanceMinDenominator);
760 offset += WriteChromaticity(data.data() + offset,
761 hdr_metadata.mastering_metadata.primary_r);
762 offset += WriteChromaticity(data.data() + offset,
763 hdr_metadata.mastering_metadata.primary_g);
764 offset += WriteChromaticity(data.data() + offset,
765 hdr_metadata.mastering_metadata.primary_b);
766 offset += WriteChromaticity(data.data() + offset,
767 hdr_metadata.mastering_metadata.white_point);
768
769 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
770 hdr_metadata.max_content_light_level);
771 offset += 2;
772 ByteWriter<uint16_t>::WriteBigEndian(
773 data.data() + offset, hdr_metadata.max_frame_average_light_level);
774 offset += 2;
775 return offset;
Johannes Kronad1d9f02018-11-09 11:12:36 +0100776}
777
Johannes Kron09d65882018-11-27 14:36:41 +0100778size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100779 uint8_t* data,
780 const HdrMasteringMetadata::Chromaticity& p) {
781 RTC_DCHECK_GE(p.x, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100782 RTC_DCHECK_LE(p.x, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100783 RTC_DCHECK_GE(p.y, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100784 RTC_DCHECK_LE(p.y, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100785 ByteWriter<uint16_t>::WriteBigEndian(
786 data, std::round(p.x * kChromaticityDenominator));
787 ByteWriter<uint16_t>::WriteBigEndian(
788 data + 2, std::round(p.y * kChromaticityDenominator));
789 return 4; // Return number of bytes written.
790}
791
Johannes Kron09d65882018-11-27 14:36:41 +0100792size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
793 float f,
794 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100795 RTC_DCHECK_GE(f, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100796 float upscaled_value = f * denominator;
797 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
798 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
799 return 2; // Return number of bytes written.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100800}
801
Steve Antona3251dd2017-07-21 09:58:31 -0700802bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700803 std::string* str) {
804 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
805 return false;
806 const char* cstr = reinterpret_cast<const char*>(data.data());
807 // If there is a \0 character in the middle of the |data|, treat it as end
808 // of the string. Well-formed string extensions shouldn't contain it.
809 str->assign(cstr, strnlen(cstr, data.size()));
810 RTC_DCHECK(!str->empty());
811 return true;
812}
813
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200814bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
815 const std::string& str) {
Niels Möllerd57efc12019-03-22 14:02:11 +0100816 if (str.size() > kMaxValueSizeBytes) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200817 return false;
818 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200819 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700820 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200821 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700822 return true;
823}
824
825// Constant declarations for string RTP header extension types.
826
danilchapef8d7732017-04-19 02:59:48 -0700827constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700828constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700829
danilchapef8d7732017-04-19 02:59:48 -0700830constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700831constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700832
Steve Antona3251dd2017-07-21 09:58:31 -0700833constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700834constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700835
Minyue Licae27792019-11-29 16:18:59 +0100836// An RTP Header Extension for Inband Comfort Noise
837//
838// The form of the audio level extension block:
839//
840// 0 1
841// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
842// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
843// | ID | len=0 |N| level |
844// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
845// Sample Audio Level Encoding Using the One-Byte Header Format
846//
847// 0 1 2
848// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
849// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
850// | ID | len=1 |N| level |
851// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
852// Sample Audio Level Encoding Using the Two-Byte Header Format
853
854constexpr RTPExtensionType InbandComfortNoiseExtension::kId;
855constexpr uint8_t InbandComfortNoiseExtension::kValueSizeBytes;
856constexpr const char InbandComfortNoiseExtension::kUri[];
857
858bool InbandComfortNoiseExtension::Parse(rtc::ArrayView<const uint8_t> data,
859 absl::optional<uint8_t>* level) {
860 if (data.size() != kValueSizeBytes)
861 return false;
862 *level = (data[0] & 0b1000'0000) != 0
863 ? absl::nullopt
864 : absl::make_optional(data[0] & 0b0111'1111);
865 return true;
866}
867
868bool InbandComfortNoiseExtension::Write(rtc::ArrayView<uint8_t> data,
869 absl::optional<uint8_t> level) {
870 RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
871 data[0] = 0b0000'0000;
872 if (level) {
873 if (*level > 127) {
874 return false;
875 }
876 data[0] = 0b1000'0000 | *level;
877 }
878 return true;
879}
880
Jeremy Leconte4f88a9d2021-03-17 17:01:31 +0100881// VideoFrameTrackingIdExtension
882//
883// 0 1 2
884// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
885// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
886// | ID | L=1 | video-frame-tracking-id |
887// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
888
889constexpr RTPExtensionType VideoFrameTrackingIdExtension::kId;
890constexpr uint8_t VideoFrameTrackingIdExtension::kValueSizeBytes;
891constexpr const char VideoFrameTrackingIdExtension::kUri[];
892
893bool VideoFrameTrackingIdExtension::Parse(rtc::ArrayView<const uint8_t> data,
894 uint16_t* video_frame_tracking_id) {
895 if (data.size() != kValueSizeBytes) {
896 return false;
897 }
898 *video_frame_tracking_id = ByteReader<uint16_t>::ReadBigEndian(data.data());
899 return true;
900}
901
902bool VideoFrameTrackingIdExtension::Write(rtc::ArrayView<uint8_t> data,
903 uint16_t video_frame_tracking_id) {
904 RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
905 ByteWriter<uint16_t>::WriteBigEndian(data.data(), video_frame_tracking_id);
906 return true;
907}
908
danilchap1edb7ab2016-04-20 05:25:10 -0700909} // namespace webrtc