blob: d9ba25827a5d2507a14b7c60ddb5abbf22a802c1 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070023
24namespace webrtc {
25// Absolute send time in RTP streams.
26//
27// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020028// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070029// of this extension (the transmitted value) is a 24-bit unsigned integer
30// containing the sender's current time in seconds as a fixed point number
31// with 18 bits fractional part.
32//
33// The form of the absolute send time extension block:
34//
35// 0 1 2 3
36// 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
37// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38// | ID | len=2 | absolute send time |
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070040constexpr RTPExtensionType AbsoluteSendTime::kId;
41constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070042constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070043
danilchap978504e2017-04-06 01:03:53 -070044bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
45 uint32_t* time_24bits) {
46 if (data.size() != 3)
47 return false;
48 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -070049 return true;
50}
51
Danil Chapovalov9bf31582018-06-18 13:48:20 +020052bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
53 uint32_t time_24bits) {
54 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020055 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020056 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070057 return true;
58}
59
Chen Xingcd8a6e22019-07-01 10:56:51 +020060// Absolute Capture Time
61//
62// The Absolute Capture Time extension is used to stamp RTP packets with a NTP
63// timestamp showing when the first audio or video frame in a packet was
64// originally captured. The intent of this extension is to provide a way to
65// accomplish audio-to-video synchronization when RTCP-terminating intermediate
66// systems (e.g. mixers) are involved.
67//
68// Data layout of the shortened version of abs-capture-time:
69//
70// 0 1 2 3
71// 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
72// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73// | ID | len=7 | absolute capture timestamp (bit 0-23) |
74// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75// | absolute capture timestamp (bit 24-55) |
76// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77// | ... (56-63) |
78// +-+-+-+-+-+-+-+-+
79//
80// Data layout of the extended version of abs-capture-time:
81//
82// 0 1 2 3
83// 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
84// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85// | ID | len=15| absolute capture timestamp (bit 0-23) |
86// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87// | absolute capture timestamp (bit 24-55) |
88// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89// | ... (56-63) | estimated capture clock offset (bit 0-23) |
90// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91// | estimated capture clock offset (bit 24-55) |
92// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93// | ... (56-63) |
94// +-+-+-+-+-+-+-+-+
95constexpr RTPExtensionType AbsoluteCaptureTimeExtension::kId;
96constexpr uint8_t AbsoluteCaptureTimeExtension::kValueSizeBytes;
97constexpr uint8_t AbsoluteCaptureTimeExtension::
98 kValueSizeBytesWithoutEstimatedCaptureClockOffset;
99constexpr const char AbsoluteCaptureTimeExtension::kUri[];
100
101bool AbsoluteCaptureTimeExtension::Parse(rtc::ArrayView<const uint8_t> data,
102 AbsoluteCaptureTime* extension) {
103 if (data.size() != kValueSizeBytes &&
104 data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
105 return false;
106 }
107
108 extension->absolute_capture_timestamp =
109 ByteReader<uint64_t>::ReadBigEndian(data.data());
110
111 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
112 extension->estimated_capture_clock_offset =
113 ByteReader<int64_t>::ReadBigEndian(data.data() + 8);
114 }
115
116 return true;
117}
118
119size_t AbsoluteCaptureTimeExtension::ValueSize(
120 const AbsoluteCaptureTime& extension) {
121 if (extension.estimated_capture_clock_offset != absl::nullopt) {
122 return kValueSizeBytes;
123 } else {
124 return kValueSizeBytesWithoutEstimatedCaptureClockOffset;
125 }
126}
127
128bool AbsoluteCaptureTimeExtension::Write(rtc::ArrayView<uint8_t> data,
129 const AbsoluteCaptureTime& extension) {
130 RTC_DCHECK_EQ(data.size(), ValueSize(extension));
131
132 ByteWriter<uint64_t>::WriteBigEndian(data.data(),
133 extension.absolute_capture_timestamp);
134
135 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
136 ByteWriter<int64_t>::WriteBigEndian(
137 data.data() + 8, extension.estimated_capture_clock_offset.value());
138 }
139
140 return true;
141}
142
danilchap1edb7ab2016-04-20 05:25:10 -0700143// An RTP Header Extension for Client-to-Mixer Audio Level Indication
144//
145// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
146//
147// The form of the audio level extension block:
148//
149// 0 1
150// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
151// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
152// | ID | len=0 |V| level |
153// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154//
danilchape2a01772016-10-28 07:08:58 -0700155constexpr RTPExtensionType AudioLevel::kId;
156constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700157constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700158
danilchap978504e2017-04-06 01:03:53 -0700159bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700160 bool* voice_activity,
161 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -0700162 if (data.size() != 1)
163 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700164 *voice_activity = (data[0] & 0x80) != 0;
165 *audio_level = data[0] & 0x7F;
166 return true;
167}
168
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200169bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700170 bool voice_activity,
171 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200172 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700173 RTC_CHECK_LE(audio_level, 0x7f);
174 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
175 return true;
176}
177
178// From RFC 5450: Transmission Time Offsets in RTP Streams.
179//
180// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +0200181// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -0700182// of this extension (the transmitted value) is a 24-bit signed integer.
183// When added to the RTP timestamp of the packet, it represents the
184// "effective" RTP transmission time of the packet, on the RTP
185// timescale.
186//
187// The form of the transmission offset extension block:
188//
189// 0 1 2 3
190// 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
191// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192// | ID | len=2 | transmission offset |
193// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700194constexpr RTPExtensionType TransmissionOffset::kId;
195constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700196constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700197
danilchap978504e2017-04-06 01:03:53 -0700198bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
199 int32_t* rtp_time) {
200 if (data.size() != 3)
201 return false;
202 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700203 return true;
204}
205
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200206bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
207 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200208 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200209 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700210 return true;
211}
212
Johannes Kron54047be2019-02-21 14:09:20 +0000213// TransportSequenceNumber
214//
danilchap1edb7ab2016-04-20 05:25:10 -0700215// 0 1 2
216// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
217// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron54047be2019-02-21 14:09:20 +0000218// | ID | L=1 |transport-wide sequence number |
danilchap1edb7ab2016-04-20 05:25:10 -0700219// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700220constexpr RTPExtensionType TransportSequenceNumber::kId;
221constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700222constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700223
danilchap978504e2017-04-06 01:03:53 -0700224bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000225 uint16_t* transport_sequence_number) {
226 if (data.size() != kValueSizeBytes)
danilchap978504e2017-04-06 01:03:53 -0700227 return false;
Johannes Kron54047be2019-02-21 14:09:20 +0000228 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700229 return true;
230}
231
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200232bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000233 uint16_t transport_sequence_number) {
234 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
235 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
236 return true;
237}
238
239// TransportSequenceNumberV2
240//
241// In addition to the format used for TransportSequencNumber, V2 also supports
242// the following packet format where two extra bytes are used to specify that
243// the sender requests immediate feedback.
244// 0 1 2 3
245// 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
246// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
247// | ID | L=3 |transport-wide sequence number |T| seq count |
248// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
249// |seq count cont.|
250// +-+-+-+-+-+-+-+-+
251//
252// The bit |T| determines whether the feedback should include timing information
Johannes Kron0da25a12019-03-06 09:34:13 +0100253// or not and |seq_count| determines how many packets the feedback packet should
254// cover including the current packet. If |seq_count| is zero no feedback is
255// requested.
Johannes Kron54047be2019-02-21 14:09:20 +0000256constexpr RTPExtensionType TransportSequenceNumberV2::kId;
Johannes Kron0da25a12019-03-06 09:34:13 +0100257constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
258constexpr uint8_t
259 TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
Johannes Kron54047be2019-02-21 14:09:20 +0000260constexpr const char TransportSequenceNumberV2::kUri[];
261constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
262
263bool TransportSequenceNumberV2::Parse(
264 rtc::ArrayView<const uint8_t> data,
265 uint16_t* transport_sequence_number,
266 absl::optional<FeedbackRequest>* feedback_request) {
Johannes Kron0da25a12019-03-06 09:34:13 +0100267 if (data.size() != kValueSizeBytes &&
268 data.size() != kValueSizeBytesWithoutFeedbackRequest)
Johannes Kron54047be2019-02-21 14:09:20 +0000269 return false;
270
271 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
272
Johannes Kron0da25a12019-03-06 09:34:13 +0100273 *feedback_request = absl::nullopt;
274 if (data.size() == kValueSizeBytes) {
Johannes Kron54047be2019-02-21 14:09:20 +0000275 uint16_t feedback_request_raw =
276 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
277 bool include_timestamps =
278 (feedback_request_raw & kIncludeTimestampsBit) != 0;
279 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
Johannes Kron0da25a12019-03-06 09:34:13 +0100280
281 // If |sequence_count| is zero no feedback is requested.
282 if (sequence_count != 0) {
283 *feedback_request = {include_timestamps, sequence_count};
284 }
Johannes Kron54047be2019-02-21 14:09:20 +0000285 }
286 return true;
287}
288
289bool TransportSequenceNumberV2::Write(
290 rtc::ArrayView<uint8_t> data,
291 uint16_t transport_sequence_number,
292 const absl::optional<FeedbackRequest>& feedback_request) {
293 RTC_DCHECK_EQ(data.size(),
294 ValueSize(transport_sequence_number, feedback_request));
295
296 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
297
298 if (feedback_request) {
299 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
300 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
301 uint16_t feedback_request_raw =
302 feedback_request->sequence_count |
303 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
304 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
305 }
danilchap1edb7ab2016-04-20 05:25:10 -0700306 return true;
307}
308
309// Coordination of Video Orientation in RTP streams.
310//
311// Coordination of Video Orientation consists in signaling of the current
312// orientation of the image captured on the sender side to the receiver for
313// appropriate rendering and displaying.
314//
315// 0 1
316// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
317// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318// | ID | len=0 |0 0 0 0 C F R R|
319// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700320constexpr RTPExtensionType VideoOrientation::kId;
321constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700322constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700323
danilchap978504e2017-04-06 01:03:53 -0700324bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
325 VideoRotation* rotation) {
326 if (data.size() != 1)
327 return false;
magjed71eb61c2016-09-08 03:24:58 -0700328 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700329 return true;
330}
331
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200332bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
333 VideoRotation rotation) {
334 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700335 data[0] = ConvertVideoRotationToCVOByte(rotation);
336 return true;
337}
338
danilchap978504e2017-04-06 01:03:53 -0700339bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
340 uint8_t* value) {
341 if (data.size() != 1)
342 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700343 *value = data[0];
344 return true;
345}
346
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200347bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
348 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700349 data[0] = value;
350 return true;
351}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200352
353// 0 1 2 3
354// 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
355// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
356// | ID | len=2 | MIN delay | MAX delay |
357// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358constexpr RTPExtensionType PlayoutDelayLimits::kId;
359constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700360constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200361
danilchap978504e2017-04-06 01:03:53 -0700362bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200363 PlayoutDelay* playout_delay) {
364 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700365 if (data.size() != 3)
366 return false;
367 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200368 uint16_t min_raw = (raw >> 12);
369 uint16_t max_raw = (raw & 0xfff);
370 if (min_raw > max_raw)
371 return false;
372 playout_delay->min_ms = min_raw * kGranularityMs;
373 playout_delay->max_ms = max_raw * kGranularityMs;
374 return true;
375}
376
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200377bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200378 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200379 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200380 RTC_DCHECK_LE(0, playout_delay.min_ms);
381 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
382 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
383 // Convert MS to value to be sent on extension header.
384 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
385 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200386 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
387 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200388 return true;
389}
390
ilnik00d802b2017-04-11 10:34:31 -0700391// Video Content Type.
392//
393// E.g. default video or screenshare.
394//
395// 0 1
396// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
397// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
398// | ID | len=0 | Content type |
399// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
400constexpr RTPExtensionType VideoContentTypeExtension::kId;
401constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700402constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700403
404bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
405 VideoContentType* content_type) {
406 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700407 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700408 *content_type = static_cast<VideoContentType>(data[0]);
409 return true;
410 }
411 return false;
412}
413
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200414bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700415 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200416 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700417 data[0] = static_cast<uint8_t>(content_type);
418 return true;
419}
420
ilnik04f4d122017-06-19 07:18:55 -0700421// Video Timing.
422// 6 timestamps in milliseconds counted from capture time stored in rtp header:
423// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700424// modification by the network modification. |flags| is a bitmask and has the
425// following allowed values:
426// 0 = Valid data, but no flags available (backwards compatibility)
427// 1 = Frame marked as timing frame due to cyclic timer.
428// 2 = Frame marked as timing frame due to size being outside limit.
429// 255 = Invalid. The whole timing frame extension should be ignored.
430//
ilnik04f4d122017-06-19 07:18:55 -0700431// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100432// 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
433// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
434// | ID | len=12| flags | encode start ms delta |
435// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
436// | encode finish ms delta | packetizer finish ms delta |
437// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
438// | pacer exit ms delta | network timestamp ms delta |
439// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700440// | network2 timestamp ms delta |
441// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700442
443constexpr RTPExtensionType VideoTimingExtension::kId;
444constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700445constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700446
447bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700448 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700449 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700450 // TODO(sprang): Deprecate support for old wire format.
451 ptrdiff_t off = 0;
452 switch (data.size()) {
453 case kValueSizeBytes - 1:
454 timing->flags = 0;
455 off = 1; // Old wire format without the flags field.
456 break;
457 case kValueSizeBytes:
458 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
459 break;
460 default:
461 return false;
462 }
463
464 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
465 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700466 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700467 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700468 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700469 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700470 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700471 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100472 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700473 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100474 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700475 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700476 return true;
477}
478
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200479bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
480 const VideoSendTiming& timing) {
481 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
482 ByteWriter<uint8_t>::WriteBigEndian(
483 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700484 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200485 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700486 timing.encode_start_delta_ms);
487 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200488 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700489 timing.encode_finish_delta_ms);
490 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200491 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700492 timing.packetization_finish_delta_ms);
493 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200494 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700495 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700496 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200497 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100498 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700499 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200500 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100501 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700502 return true;
503}
504
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200505bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700506 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700507 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200508 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100509 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200510 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700511 return true;
512}
513
Johnny Leee0c8b232018-09-11 16:50:49 -0400514// Frame Marking.
515//
516// Meta-information about an RTP stream outside the encrypted media payload,
517// useful for an RTP switch to do codec-agnostic selective forwarding
518// without decrypting the payload.
519//
520// For non-scalable streams:
521// 0 1
522// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
523// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
524// | ID | L = 0 |S|E|I|D|0 0 0 0|
525// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
526//
527// For scalable streams:
528// 0 1 2 3
529// 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
530// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531// | ID | L = 2 |S|E|I|D|B| TID | LID | TL0PICIDX |
532// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533
534constexpr RTPExtensionType FrameMarkingExtension::kId;
535constexpr const char FrameMarkingExtension::kUri[];
536
537bool FrameMarkingExtension::IsScalable(uint8_t temporal_id, uint8_t layer_id) {
538 return temporal_id != kNoTemporalIdx || layer_id != kNoSpatialIdx;
539}
540
541bool FrameMarkingExtension::Parse(rtc::ArrayView<const uint8_t> data,
542 FrameMarking* frame_marking) {
543 RTC_DCHECK(frame_marking);
544
545 if (data.size() != 1 && data.size() != 3)
546 return false;
547
548 frame_marking->start_of_frame = (data[0] & 0x80) != 0;
549 frame_marking->end_of_frame = (data[0] & 0x40) != 0;
550 frame_marking->independent_frame = (data[0] & 0x20) != 0;
551 frame_marking->discardable_frame = (data[0] & 0x10) != 0;
552
553 if (data.size() == 3) {
554 frame_marking->base_layer_sync = (data[0] & 0x08) != 0;
555 frame_marking->temporal_id = data[0] & 0x7;
556 frame_marking->layer_id = data[1];
557 frame_marking->tl0_pic_idx = data[2];
558 } else {
559 // non-scalable
560 frame_marking->base_layer_sync = false;
561 frame_marking->temporal_id = kNoTemporalIdx;
562 frame_marking->layer_id = kNoSpatialIdx;
563 frame_marking->tl0_pic_idx = 0;
564 }
565 return true;
566}
567
568size_t FrameMarkingExtension::ValueSize(const FrameMarking& frame_marking) {
569 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id))
570 return 3;
571 else
572 return 1;
573}
574
575bool FrameMarkingExtension::Write(rtc::ArrayView<uint8_t> data,
576 const FrameMarking& frame_marking) {
577 RTC_DCHECK_GE(data.size(), 1);
578 RTC_CHECK_LE(frame_marking.temporal_id, 0x07);
579 data[0] = frame_marking.start_of_frame ? 0x80 : 0x00;
580 data[0] |= frame_marking.end_of_frame ? 0x40 : 0x00;
581 data[0] |= frame_marking.independent_frame ? 0x20 : 0x00;
582 data[0] |= frame_marking.discardable_frame ? 0x10 : 0x00;
583
584 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id)) {
585 RTC_DCHECK_EQ(data.size(), 3);
586 data[0] |= frame_marking.base_layer_sync ? 0x08 : 0x00;
587 data[0] |= frame_marking.temporal_id & 0x07;
588 data[1] = frame_marking.layer_id;
589 data[2] = frame_marking.tl0_pic_idx;
590 }
591 return true;
592}
593
Johannes Kron09d65882018-11-27 14:36:41 +0100594// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100595//
Johannes Krond0b69a82018-12-03 14:18:53 +0100596// RTP header extension to carry color space information and optionally HDR
597// metadata. The float values in the HDR metadata struct are upscaled by a
598// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100599//
Johannes Krond0b69a82018-12-03 14:18:53 +0100600// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100601// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100602// 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
603// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100604// | ID | length=28 | primaries | transfer |
Johannes Krond0b69a82018-12-03 14:18:53 +0100605// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100606// | matrix |range+chr.sit. | luminance_max |
Johannes Krond0b69a82018-12-03 14:18:53 +0100607// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100608// | luminance_min | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100609// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100610// |primary_r.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100611// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100612// |primary_g.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100613// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100614// |primary_b.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100615// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100616// |white.x and .y | max_content_light_level |
Johannes Krond0b69a82018-12-03 14:18:53 +0100617// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100618// | max_frame_average_light_level |
619// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 14:36:41 +0100620//
Johannes Krond0b69a82018-12-03 14:18:53 +0100621// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 14:36:41 +0100622// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100623// 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
624// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100625// | ID | L = 3 | primaries | transfer | matrix |
Johannes Krond0b69a82018-12-03 14:18:53 +0100626// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100627// |range+chr.sit. |
Johannes Krond0b69a82018-12-03 14:18:53 +0100628// +-+-+-+-+-+-+-+-+
Johannes Kronad1d9f02018-11-09 11:12:36 +0100629
Johannes Kron09d65882018-11-27 14:36:41 +0100630constexpr RTPExtensionType ColorSpaceExtension::kId;
631constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
632constexpr const char ColorSpaceExtension::kUri[];
633
634bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
635 ColorSpace* color_space) {
636 RTC_DCHECK(color_space);
637 if (data.size() != kValueSizeBytes &&
638 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100639 return false;
640
641 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100642 // Read color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100643 if (!color_space->set_primaries_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100644 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100645 if (!color_space->set_transfer_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100646 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100647 if (!color_space->set_matrix_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100648 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100649
650 uint8_t range_and_chroma_siting = data[offset++];
651 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
652 return false;
653 if (!color_space->set_chroma_siting_horizontal_from_uint8(
654 (range_and_chroma_siting >> 2) & 0x03))
655 return false;
656 if (!color_space->set_chroma_siting_vertical_from_uint8(
657 range_and_chroma_siting & 0x03))
Johannes Kron09d65882018-11-27 14:36:41 +0100658 return false;
659
660 // Read HDR metadata if it exists, otherwise clear it.
661 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
662 color_space->set_hdr_metadata(nullptr);
663 } else {
664 HdrMetadata hdr_metadata;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100665 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
666 if (!hdr_metadata.Validate())
667 return false;
Johannes Kron09d65882018-11-27 14:36:41 +0100668 color_space->set_hdr_metadata(&hdr_metadata);
669 }
670 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100671 return true;
672}
673
Johannes Kron09d65882018-11-27 14:36:41 +0100674bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
675 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 14:18:53 +0100676 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 11:12:36 +0100677 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100678 // Write color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100679 data[offset++] = static_cast<uint8_t>(color_space.primaries());
680 data[offset++] = static_cast<uint8_t>(color_space.transfer());
681 data[offset++] = static_cast<uint8_t>(color_space.matrix());
682 data[offset++] = CombineRangeAndChromaSiting(
683 color_space.range(), color_space.chroma_siting_horizontal(),
684 color_space.chroma_siting_vertical());
Johannes Kronad1d9f02018-11-09 11:12:36 +0100685
Johannes Kron09d65882018-11-27 14:36:41 +0100686 // Write HDR metadata if it exists.
687 if (color_space.hdr_metadata()) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100688 offset +=
689 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
Johannes Kron09d65882018-11-27 14:36:41 +0100690 }
691 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100692 return true;
693}
694
Johannes Kronc13f4be2018-12-12 09:52:53 +0100695// Combines range and chroma siting into one byte with the following bit layout:
696// bits 0-1 Chroma siting vertical.
697// 2-3 Chroma siting horizontal.
698// 4-5 Range.
699// 6-7 Unused.
700uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
701 ColorSpace::RangeID range,
702 ColorSpace::ChromaSiting chroma_siting_horizontal,
703 ColorSpace::ChromaSiting chroma_siting_vertical) {
704 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
705 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
706 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
707 return (static_cast<uint8_t>(range) << 4) |
708 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
709 static_cast<uint8_t>(chroma_siting_vertical);
710}
711
712size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
713 HdrMetadata* hdr_metadata) {
714 RTC_DCHECK_EQ(data.size(),
715 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
716 size_t offset = 0;
717 offset += ParseLuminance(data.data() + offset,
718 &hdr_metadata->mastering_metadata.luminance_max,
719 kLuminanceMaxDenominator);
720 offset += ParseLuminance(data.data() + offset,
721 &hdr_metadata->mastering_metadata.luminance_min,
722 kLuminanceMinDenominator);
723 offset += ParseChromaticity(data.data() + offset,
724 &hdr_metadata->mastering_metadata.primary_r);
725 offset += ParseChromaticity(data.data() + offset,
726 &hdr_metadata->mastering_metadata.primary_g);
727 offset += ParseChromaticity(data.data() + offset,
728 &hdr_metadata->mastering_metadata.primary_b);
729 offset += ParseChromaticity(data.data() + offset,
730 &hdr_metadata->mastering_metadata.white_point);
731 hdr_metadata->max_content_light_level =
732 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
733 offset += 2;
734 hdr_metadata->max_frame_average_light_level =
735 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
736 offset += 2;
737 return offset;
738}
739
Johannes Kron09d65882018-11-27 14:36:41 +0100740size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100741 const uint8_t* data,
742 HdrMasteringMetadata::Chromaticity* p) {
743 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
744 uint16_t chromaticity_y_scaled =
745 ByteReader<uint16_t>::ReadBigEndian(data + 2);
746 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
747 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
748 return 4; // Return number of bytes read.
749}
750
Johannes Kron09d65882018-11-27 14:36:41 +0100751size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
752 float* f,
753 int denominator) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100754 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100755 *f = static_cast<float>(luminance_scaled) / denominator;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100756 return 2; // Return number of bytes read.
757}
758
759size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
760 const HdrMetadata& hdr_metadata) {
761 RTC_DCHECK_EQ(data.size(),
762 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
763 RTC_DCHECK(hdr_metadata.Validate());
764 size_t offset = 0;
765 offset += WriteLuminance(data.data() + offset,
766 hdr_metadata.mastering_metadata.luminance_max,
767 kLuminanceMaxDenominator);
768 offset += WriteLuminance(data.data() + offset,
769 hdr_metadata.mastering_metadata.luminance_min,
770 kLuminanceMinDenominator);
771 offset += WriteChromaticity(data.data() + offset,
772 hdr_metadata.mastering_metadata.primary_r);
773 offset += WriteChromaticity(data.data() + offset,
774 hdr_metadata.mastering_metadata.primary_g);
775 offset += WriteChromaticity(data.data() + offset,
776 hdr_metadata.mastering_metadata.primary_b);
777 offset += WriteChromaticity(data.data() + offset,
778 hdr_metadata.mastering_metadata.white_point);
779
780 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
781 hdr_metadata.max_content_light_level);
782 offset += 2;
783 ByteWriter<uint16_t>::WriteBigEndian(
784 data.data() + offset, hdr_metadata.max_frame_average_light_level);
785 offset += 2;
786 return offset;
Johannes Kronad1d9f02018-11-09 11:12:36 +0100787}
788
Johannes Kron09d65882018-11-27 14:36:41 +0100789size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100790 uint8_t* data,
791 const HdrMasteringMetadata::Chromaticity& p) {
792 RTC_DCHECK_GE(p.x, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100793 RTC_DCHECK_LE(p.x, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100794 RTC_DCHECK_GE(p.y, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100795 RTC_DCHECK_LE(p.y, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100796 ByteWriter<uint16_t>::WriteBigEndian(
797 data, std::round(p.x * kChromaticityDenominator));
798 ByteWriter<uint16_t>::WriteBigEndian(
799 data + 2, std::round(p.y * kChromaticityDenominator));
800 return 4; // Return number of bytes written.
801}
802
Johannes Kron09d65882018-11-27 14:36:41 +0100803size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
804 float f,
805 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100806 RTC_DCHECK_GE(f, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100807 float upscaled_value = f * denominator;
808 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
809 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
810 return 2; // Return number of bytes written.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100811}
812
Steve Antona3251dd2017-07-21 09:58:31 -0700813bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700814 std::string* str) {
815 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
816 return false;
817 const char* cstr = reinterpret_cast<const char*>(data.data());
818 // If there is a \0 character in the middle of the |data|, treat it as end
819 // of the string. Well-formed string extensions shouldn't contain it.
820 str->assign(cstr, strnlen(cstr, data.size()));
821 RTC_DCHECK(!str->empty());
822 return true;
823}
824
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200825bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
826 const std::string& str) {
Niels Möllerd57efc12019-03-22 14:02:11 +0100827 if (str.size() > kMaxValueSizeBytes) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200828 return false;
829 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200830 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700831 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200832 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700833 return true;
834}
835
836// Constant declarations for string RTP header extension types.
837
danilchapef8d7732017-04-19 02:59:48 -0700838constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700839constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700840
danilchapef8d7732017-04-19 02:59:48 -0700841constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700842constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700843
Steve Antona3251dd2017-07-21 09:58:31 -0700844constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700845constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700846
danilchap1edb7ab2016-04-20 05:25:10 -0700847} // namespace webrtc