blob: 6a0d5513bd50e782f42c876c473368b21cbe585f [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>
Johannes Kronc13f4be2018-12-12 09:52:53 +010016#include <limits>
Yves Gerey988cc082018-10-23 12:03:01 +020017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/include/rtp_cvo.h"
19#include "modules/rtp_rtcp/source/byte_io.h"
Yves Gerey988cc082018-10-23 12:03:01 +020020// TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
21#include "modules/video_coding/codecs/interface/common_constants.h"
Niels Möller834a5542019-09-23 10:31:16 +020022#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070024
25namespace webrtc {
26// Absolute send time in RTP streams.
27//
28// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020029// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070030// 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// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070041constexpr RTPExtensionType AbsoluteSendTime::kId;
42constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070043constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070044
danilchap978504e2017-04-06 01:03:53 -070045bool 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());
danilchap1edb7ab2016-04-20 05:25:10 -070050 return true;
51}
52
Danil Chapovalov9bf31582018-06-18 13:48:20 +020053bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
54 uint32_t time_24bits) {
55 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020056 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020057 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070058 return true;
59}
60
Chen Xingcd8a6e22019-07-01 10:56:51 +020061// 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// +-+-+-+-+-+-+-+-+
96constexpr RTPExtensionType AbsoluteCaptureTimeExtension::kId;
97constexpr uint8_t AbsoluteCaptureTimeExtension::kValueSizeBytes;
98constexpr uint8_t AbsoluteCaptureTimeExtension::
99 kValueSizeBytesWithoutEstimatedCaptureClockOffset;
100constexpr const char AbsoluteCaptureTimeExtension::kUri[];
101
102bool 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
120size_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
129bool 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
danilchap1edb7ab2016-04-20 05:25:10 -0700144// An RTP Header Extension for Client-to-Mixer Audio Level Indication
145//
146// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
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//
danilchape2a01772016-10-28 07:08:58 -0700156constexpr RTPExtensionType AudioLevel::kId;
157constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700158constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700159
danilchap978504e2017-04-06 01:03:53 -0700160bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700161 bool* voice_activity,
162 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -0700163 if (data.size() != 1)
164 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700165 *voice_activity = (data[0] & 0x80) != 0;
166 *audio_level = data[0] & 0x7F;
167 return true;
168}
169
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200170bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700171 bool voice_activity,
172 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200173 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700174 RTC_CHECK_LE(audio_level, 0x7f);
175 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
176 return true;
177}
178
179// From RFC 5450: Transmission Time Offsets in RTP Streams.
180//
181// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +0200182// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -0700183// of this extension (the transmitted value) is a 24-bit signed integer.
184// When added to the RTP timestamp of the packet, it represents the
185// "effective" RTP transmission time of the packet, on the RTP
186// timescale.
187//
188// The form of the transmission offset extension block:
189//
190// 0 1 2 3
191// 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
192// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193// | ID | len=2 | transmission offset |
194// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700195constexpr RTPExtensionType TransmissionOffset::kId;
196constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700197constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700198
danilchap978504e2017-04-06 01:03:53 -0700199bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
200 int32_t* rtp_time) {
201 if (data.size() != 3)
202 return false;
203 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700204 return true;
205}
206
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200207bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
208 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200209 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200210 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700211 return true;
212}
213
Johannes Kron54047be2019-02-21 14:09:20 +0000214// TransportSequenceNumber
215//
danilchap1edb7ab2016-04-20 05:25:10 -0700216// 0 1 2
217// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
218// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron54047be2019-02-21 14:09:20 +0000219// | ID | L=1 |transport-wide sequence number |
danilchap1edb7ab2016-04-20 05:25:10 -0700220// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700221constexpr RTPExtensionType TransportSequenceNumber::kId;
222constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700223constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700224
danilchap978504e2017-04-06 01:03:53 -0700225bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000226 uint16_t* transport_sequence_number) {
227 if (data.size() != kValueSizeBytes)
danilchap978504e2017-04-06 01:03:53 -0700228 return false;
Johannes Kron54047be2019-02-21 14:09:20 +0000229 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700230 return true;
231}
232
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200233bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000234 uint16_t transport_sequence_number) {
235 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
236 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
237 return true;
238}
239
240// TransportSequenceNumberV2
241//
242// In addition to the format used for TransportSequencNumber, V2 also supports
243// the following packet format where two extra bytes are used to specify that
244// the sender requests immediate feedback.
245// 0 1 2 3
246// 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
247// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248// | ID | L=3 |transport-wide sequence number |T| seq count |
249// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250// |seq count cont.|
251// +-+-+-+-+-+-+-+-+
252//
253// The bit |T| determines whether the feedback should include timing information
Johannes Kron0da25a12019-03-06 09:34:13 +0100254// or not and |seq_count| determines how many packets the feedback packet should
255// cover including the current packet. If |seq_count| is zero no feedback is
256// requested.
Johannes Kron54047be2019-02-21 14:09:20 +0000257constexpr RTPExtensionType TransportSequenceNumberV2::kId;
Johannes Kron0da25a12019-03-06 09:34:13 +0100258constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
259constexpr uint8_t
260 TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
Johannes Kron54047be2019-02-21 14:09:20 +0000261constexpr const char TransportSequenceNumberV2::kUri[];
262constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
263
264bool TransportSequenceNumberV2::Parse(
265 rtc::ArrayView<const uint8_t> data,
266 uint16_t* transport_sequence_number,
267 absl::optional<FeedbackRequest>* feedback_request) {
Johannes Kron0da25a12019-03-06 09:34:13 +0100268 if (data.size() != kValueSizeBytes &&
269 data.size() != kValueSizeBytesWithoutFeedbackRequest)
Johannes Kron54047be2019-02-21 14:09:20 +0000270 return false;
271
272 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
273
Johannes Kron0da25a12019-03-06 09:34:13 +0100274 *feedback_request = absl::nullopt;
275 if (data.size() == kValueSizeBytes) {
Johannes Kron54047be2019-02-21 14:09:20 +0000276 uint16_t feedback_request_raw =
277 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
278 bool include_timestamps =
279 (feedback_request_raw & kIncludeTimestampsBit) != 0;
280 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
Johannes Kron0da25a12019-03-06 09:34:13 +0100281
282 // If |sequence_count| is zero no feedback is requested.
283 if (sequence_count != 0) {
284 *feedback_request = {include_timestamps, sequence_count};
285 }
Johannes Kron54047be2019-02-21 14:09:20 +0000286 }
287 return true;
288}
289
290bool TransportSequenceNumberV2::Write(
291 rtc::ArrayView<uint8_t> data,
292 uint16_t transport_sequence_number,
293 const absl::optional<FeedbackRequest>& feedback_request) {
294 RTC_DCHECK_EQ(data.size(),
295 ValueSize(transport_sequence_number, feedback_request));
296
297 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
298
299 if (feedback_request) {
300 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
301 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
302 uint16_t feedback_request_raw =
303 feedback_request->sequence_count |
304 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
305 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
306 }
danilchap1edb7ab2016-04-20 05:25:10 -0700307 return true;
308}
309
310// Coordination of Video Orientation in RTP streams.
311//
312// Coordination of Video Orientation consists in signaling of the current
313// orientation of the image captured on the sender side to the receiver for
314// appropriate rendering and displaying.
315//
316// 0 1
317// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
318// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319// | ID | len=0 |0 0 0 0 C F R R|
320// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700321constexpr RTPExtensionType VideoOrientation::kId;
322constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700323constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700324
danilchap978504e2017-04-06 01:03:53 -0700325bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
326 VideoRotation* rotation) {
327 if (data.size() != 1)
328 return false;
magjed71eb61c2016-09-08 03:24:58 -0700329 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700330 return true;
331}
332
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200333bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
334 VideoRotation rotation) {
335 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700336 data[0] = ConvertVideoRotationToCVOByte(rotation);
337 return true;
338}
339
danilchap978504e2017-04-06 01:03:53 -0700340bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
341 uint8_t* value) {
342 if (data.size() != 1)
343 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700344 *value = data[0];
345 return true;
346}
347
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200348bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
349 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700350 data[0] = value;
351 return true;
352}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200353
354// 0 1 2 3
355// 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
356// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357// | ID | len=2 | MIN delay | MAX delay |
358// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359constexpr RTPExtensionType PlayoutDelayLimits::kId;
360constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700361constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200362
danilchap978504e2017-04-06 01:03:53 -0700363bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200364 PlayoutDelay* playout_delay) {
365 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700366 if (data.size() != 3)
367 return false;
368 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200369 uint16_t min_raw = (raw >> 12);
370 uint16_t max_raw = (raw & 0xfff);
371 if (min_raw > max_raw)
372 return false;
373 playout_delay->min_ms = min_raw * kGranularityMs;
374 playout_delay->max_ms = max_raw * kGranularityMs;
375 return true;
376}
377
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200378bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200379 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200380 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200381 RTC_DCHECK_LE(0, playout_delay.min_ms);
382 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
383 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
384 // Convert MS to value to be sent on extension header.
385 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
386 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200387 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
388 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200389 return true;
390}
391
ilnik00d802b2017-04-11 10:34:31 -0700392// Video Content Type.
393//
394// E.g. default video or screenshare.
395//
396// 0 1
397// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
398// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399// | ID | len=0 | Content type |
400// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401constexpr RTPExtensionType VideoContentTypeExtension::kId;
402constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700403constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700404
405bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
406 VideoContentType* content_type) {
407 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700408 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700409 *content_type = static_cast<VideoContentType>(data[0]);
410 return true;
411 }
412 return false;
413}
414
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200415bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700416 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200417 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700418 data[0] = static_cast<uint8_t>(content_type);
419 return true;
420}
421
ilnik04f4d122017-06-19 07:18:55 -0700422// Video Timing.
423// 6 timestamps in milliseconds counted from capture time stored in rtp header:
424// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700425// modification by the network modification. |flags| is a bitmask and has the
426// following allowed values:
427// 0 = Valid data, but no flags available (backwards compatibility)
428// 1 = Frame marked as timing frame due to cyclic timer.
429// 2 = Frame marked as timing frame due to size being outside limit.
430// 255 = Invalid. The whole timing frame extension should be ignored.
431//
ilnik04f4d122017-06-19 07:18:55 -0700432// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100433// 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
434// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435// | ID | len=12| flags | encode start ms delta |
436// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437// | encode finish ms delta | packetizer finish ms delta |
438// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439// | pacer exit ms delta | network timestamp ms delta |
440// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700441// | network2 timestamp ms delta |
442// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700443
444constexpr RTPExtensionType VideoTimingExtension::kId;
445constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700446constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700447
448bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700449 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700450 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700451 // TODO(sprang): Deprecate support for old wire format.
452 ptrdiff_t off = 0;
453 switch (data.size()) {
454 case kValueSizeBytes - 1:
455 timing->flags = 0;
456 off = 1; // Old wire format without the flags field.
457 break;
458 case kValueSizeBytes:
459 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
460 break;
461 default:
462 return false;
463 }
464
465 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
466 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700467 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700468 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700469 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700470 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700471 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700472 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100473 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700474 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100475 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700476 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700477 return true;
478}
479
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200480bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
481 const VideoSendTiming& timing) {
482 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
483 ByteWriter<uint8_t>::WriteBigEndian(
484 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700485 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200486 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700487 timing.encode_start_delta_ms);
488 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200489 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700490 timing.encode_finish_delta_ms);
491 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200492 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700493 timing.packetization_finish_delta_ms);
494 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200495 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700496 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700497 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200498 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100499 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700500 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200501 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100502 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700503 return true;
504}
505
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200506bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700507 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700508 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200509 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100510 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200511 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700512 return true;
513}
514
Johnny Leee0c8b232018-09-11 16:50:49 -0400515// Frame Marking.
516//
517// Meta-information about an RTP stream outside the encrypted media payload,
518// useful for an RTP switch to do codec-agnostic selective forwarding
519// without decrypting the payload.
520//
521// For non-scalable streams:
522// 0 1
523// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
524// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525// | ID | L = 0 |S|E|I|D|0 0 0 0|
526// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
527//
528// For scalable streams:
529// 0 1 2 3
530// 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
531// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532// | ID | L = 2 |S|E|I|D|B| TID | LID | TL0PICIDX |
533// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534
535constexpr RTPExtensionType FrameMarkingExtension::kId;
536constexpr const char FrameMarkingExtension::kUri[];
537
538bool FrameMarkingExtension::IsScalable(uint8_t temporal_id, uint8_t layer_id) {
539 return temporal_id != kNoTemporalIdx || layer_id != kNoSpatialIdx;
540}
541
542bool FrameMarkingExtension::Parse(rtc::ArrayView<const uint8_t> data,
543 FrameMarking* frame_marking) {
544 RTC_DCHECK(frame_marking);
545
546 if (data.size() != 1 && data.size() != 3)
547 return false;
548
549 frame_marking->start_of_frame = (data[0] & 0x80) != 0;
550 frame_marking->end_of_frame = (data[0] & 0x40) != 0;
551 frame_marking->independent_frame = (data[0] & 0x20) != 0;
552 frame_marking->discardable_frame = (data[0] & 0x10) != 0;
553
554 if (data.size() == 3) {
555 frame_marking->base_layer_sync = (data[0] & 0x08) != 0;
556 frame_marking->temporal_id = data[0] & 0x7;
557 frame_marking->layer_id = data[1];
558 frame_marking->tl0_pic_idx = data[2];
559 } else {
560 // non-scalable
561 frame_marking->base_layer_sync = false;
562 frame_marking->temporal_id = kNoTemporalIdx;
563 frame_marking->layer_id = kNoSpatialIdx;
564 frame_marking->tl0_pic_idx = 0;
565 }
566 return true;
567}
568
569size_t FrameMarkingExtension::ValueSize(const FrameMarking& frame_marking) {
570 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id))
571 return 3;
572 else
573 return 1;
574}
575
576bool FrameMarkingExtension::Write(rtc::ArrayView<uint8_t> data,
577 const FrameMarking& frame_marking) {
578 RTC_DCHECK_GE(data.size(), 1);
579 RTC_CHECK_LE(frame_marking.temporal_id, 0x07);
580 data[0] = frame_marking.start_of_frame ? 0x80 : 0x00;
581 data[0] |= frame_marking.end_of_frame ? 0x40 : 0x00;
582 data[0] |= frame_marking.independent_frame ? 0x20 : 0x00;
583 data[0] |= frame_marking.discardable_frame ? 0x10 : 0x00;
584
585 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id)) {
586 RTC_DCHECK_EQ(data.size(), 3);
587 data[0] |= frame_marking.base_layer_sync ? 0x08 : 0x00;
588 data[0] |= frame_marking.temporal_id & 0x07;
589 data[1] = frame_marking.layer_id;
590 data[2] = frame_marking.tl0_pic_idx;
591 }
592 return true;
593}
594
Johannes Kron09d65882018-11-27 14:36:41 +0100595// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100596//
Johannes Krond0b69a82018-12-03 14:18:53 +0100597// RTP header extension to carry color space information and optionally HDR
598// metadata. The float values in the HDR metadata struct are upscaled by a
599// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100600//
Johannes Krond0b69a82018-12-03 14:18:53 +0100601// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100602// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100603// 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
604// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100605// | ID | length=28 | primaries | transfer |
Johannes Krond0b69a82018-12-03 14:18:53 +0100606// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100607// | matrix |range+chr.sit. | luminance_max |
Johannes Krond0b69a82018-12-03 14:18:53 +0100608// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100609// | luminance_min | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100610// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100611// |primary_r.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100612// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100613// |primary_g.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100614// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100615// |primary_b.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100616// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100617// |white.x and .y | max_content_light_level |
Johannes Krond0b69a82018-12-03 14:18:53 +0100618// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100619// | max_frame_average_light_level |
620// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 14:36:41 +0100621//
Johannes Krond0b69a82018-12-03 14:18:53 +0100622// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 14:36:41 +0100623// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100624// 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
625// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100626// | ID | L = 3 | primaries | transfer | matrix |
Johannes Krond0b69a82018-12-03 14:18:53 +0100627// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100628// |range+chr.sit. |
Johannes Krond0b69a82018-12-03 14:18:53 +0100629// +-+-+-+-+-+-+-+-+
Johannes Kronad1d9f02018-11-09 11:12:36 +0100630
Johannes Kron09d65882018-11-27 14:36:41 +0100631constexpr RTPExtensionType ColorSpaceExtension::kId;
632constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
633constexpr const char ColorSpaceExtension::kUri[];
634
635bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
636 ColorSpace* color_space) {
637 RTC_DCHECK(color_space);
638 if (data.size() != kValueSizeBytes &&
639 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100640 return false;
641
642 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100643 // Read color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100644 if (!color_space->set_primaries_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100645 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100646 if (!color_space->set_transfer_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100647 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100648 if (!color_space->set_matrix_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100649 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100650
651 uint8_t range_and_chroma_siting = data[offset++];
652 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
653 return false;
654 if (!color_space->set_chroma_siting_horizontal_from_uint8(
655 (range_and_chroma_siting >> 2) & 0x03))
656 return false;
657 if (!color_space->set_chroma_siting_vertical_from_uint8(
658 range_and_chroma_siting & 0x03))
Johannes Kron09d65882018-11-27 14:36:41 +0100659 return false;
660
661 // Read HDR metadata if it exists, otherwise clear it.
662 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
663 color_space->set_hdr_metadata(nullptr);
664 } else {
665 HdrMetadata hdr_metadata;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100666 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
667 if (!hdr_metadata.Validate())
668 return false;
Johannes Kron09d65882018-11-27 14:36:41 +0100669 color_space->set_hdr_metadata(&hdr_metadata);
670 }
671 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100672 return true;
673}
674
Johannes Kron09d65882018-11-27 14:36:41 +0100675bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
676 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 14:18:53 +0100677 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 11:12:36 +0100678 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100679 // Write color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100680 data[offset++] = static_cast<uint8_t>(color_space.primaries());
681 data[offset++] = static_cast<uint8_t>(color_space.transfer());
682 data[offset++] = static_cast<uint8_t>(color_space.matrix());
683 data[offset++] = CombineRangeAndChromaSiting(
684 color_space.range(), color_space.chroma_siting_horizontal(),
685 color_space.chroma_siting_vertical());
Johannes Kronad1d9f02018-11-09 11:12:36 +0100686
Johannes Kron09d65882018-11-27 14:36:41 +0100687 // Write HDR metadata if it exists.
688 if (color_space.hdr_metadata()) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100689 offset +=
690 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
Johannes Kron09d65882018-11-27 14:36:41 +0100691 }
692 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100693 return true;
694}
695
Johannes Kronc13f4be2018-12-12 09:52:53 +0100696// Combines range and chroma siting into one byte with the following bit layout:
697// bits 0-1 Chroma siting vertical.
698// 2-3 Chroma siting horizontal.
699// 4-5 Range.
700// 6-7 Unused.
701uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
702 ColorSpace::RangeID range,
703 ColorSpace::ChromaSiting chroma_siting_horizontal,
704 ColorSpace::ChromaSiting chroma_siting_vertical) {
705 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
706 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
707 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
708 return (static_cast<uint8_t>(range) << 4) |
709 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
710 static_cast<uint8_t>(chroma_siting_vertical);
711}
712
713size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
714 HdrMetadata* hdr_metadata) {
715 RTC_DCHECK_EQ(data.size(),
716 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
717 size_t offset = 0;
718 offset += ParseLuminance(data.data() + offset,
719 &hdr_metadata->mastering_metadata.luminance_max,
720 kLuminanceMaxDenominator);
721 offset += ParseLuminance(data.data() + offset,
722 &hdr_metadata->mastering_metadata.luminance_min,
723 kLuminanceMinDenominator);
724 offset += ParseChromaticity(data.data() + offset,
725 &hdr_metadata->mastering_metadata.primary_r);
726 offset += ParseChromaticity(data.data() + offset,
727 &hdr_metadata->mastering_metadata.primary_g);
728 offset += ParseChromaticity(data.data() + offset,
729 &hdr_metadata->mastering_metadata.primary_b);
730 offset += ParseChromaticity(data.data() + offset,
731 &hdr_metadata->mastering_metadata.white_point);
732 hdr_metadata->max_content_light_level =
733 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
734 offset += 2;
735 hdr_metadata->max_frame_average_light_level =
736 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
737 offset += 2;
738 return offset;
739}
740
Johannes Kron09d65882018-11-27 14:36:41 +0100741size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100742 const uint8_t* data,
743 HdrMasteringMetadata::Chromaticity* p) {
744 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
745 uint16_t chromaticity_y_scaled =
746 ByteReader<uint16_t>::ReadBigEndian(data + 2);
747 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
748 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
749 return 4; // Return number of bytes read.
750}
751
Johannes Kron09d65882018-11-27 14:36:41 +0100752size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
753 float* f,
754 int denominator) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100755 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100756 *f = static_cast<float>(luminance_scaled) / denominator;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100757 return 2; // Return number of bytes read.
758}
759
760size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
761 const HdrMetadata& hdr_metadata) {
762 RTC_DCHECK_EQ(data.size(),
763 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
764 RTC_DCHECK(hdr_metadata.Validate());
765 size_t offset = 0;
766 offset += WriteLuminance(data.data() + offset,
767 hdr_metadata.mastering_metadata.luminance_max,
768 kLuminanceMaxDenominator);
769 offset += WriteLuminance(data.data() + offset,
770 hdr_metadata.mastering_metadata.luminance_min,
771 kLuminanceMinDenominator);
772 offset += WriteChromaticity(data.data() + offset,
773 hdr_metadata.mastering_metadata.primary_r);
774 offset += WriteChromaticity(data.data() + offset,
775 hdr_metadata.mastering_metadata.primary_g);
776 offset += WriteChromaticity(data.data() + offset,
777 hdr_metadata.mastering_metadata.primary_b);
778 offset += WriteChromaticity(data.data() + offset,
779 hdr_metadata.mastering_metadata.white_point);
780
781 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
782 hdr_metadata.max_content_light_level);
783 offset += 2;
784 ByteWriter<uint16_t>::WriteBigEndian(
785 data.data() + offset, hdr_metadata.max_frame_average_light_level);
786 offset += 2;
787 return offset;
Johannes Kronad1d9f02018-11-09 11:12:36 +0100788}
789
Johannes Kron09d65882018-11-27 14:36:41 +0100790size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100791 uint8_t* data,
792 const HdrMasteringMetadata::Chromaticity& p) {
793 RTC_DCHECK_GE(p.x, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100794 RTC_DCHECK_LE(p.x, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100795 RTC_DCHECK_GE(p.y, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100796 RTC_DCHECK_LE(p.y, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100797 ByteWriter<uint16_t>::WriteBigEndian(
798 data, std::round(p.x * kChromaticityDenominator));
799 ByteWriter<uint16_t>::WriteBigEndian(
800 data + 2, std::round(p.y * kChromaticityDenominator));
801 return 4; // Return number of bytes written.
802}
803
Johannes Kron09d65882018-11-27 14:36:41 +0100804size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
805 float f,
806 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100807 RTC_DCHECK_GE(f, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100808 float upscaled_value = f * denominator;
809 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
810 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
811 return 2; // Return number of bytes written.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100812}
813
Steve Antona3251dd2017-07-21 09:58:31 -0700814bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700815 std::string* str) {
816 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
817 return false;
818 const char* cstr = reinterpret_cast<const char*>(data.data());
819 // If there is a \0 character in the middle of the |data|, treat it as end
820 // of the string. Well-formed string extensions shouldn't contain it.
821 str->assign(cstr, strnlen(cstr, data.size()));
822 RTC_DCHECK(!str->empty());
823 return true;
824}
825
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200826bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
827 const std::string& str) {
Niels Möllerd57efc12019-03-22 14:02:11 +0100828 if (str.size() > kMaxValueSizeBytes) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200829 return false;
830 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200831 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700832 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200833 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700834 return true;
835}
836
837// Constant declarations for string RTP header extension types.
838
danilchapef8d7732017-04-19 02:59:48 -0700839constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700840constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700841
danilchapef8d7732017-04-19 02:59:48 -0700842constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700843constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700844
Steve Antona3251dd2017-07-21 09:58:31 -0700845constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700846constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700847
danilchap1edb7ab2016-04-20 05:25:10 -0700848} // namespace webrtc