blob: 834a063c62f97b749e9a598f25ec425ec0ef8845 [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>
Johannes Kronad1d9f02018-11-09 11:12:36 +010014#include <cmath>
Johannes Kronc13f4be2018-12-12 09:52:53 +010015#include <limits>
Yves Gerey988cc082018-10-23 12:03:01 +020016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/rtp_rtcp/include/rtp_cvo.h"
18#include "modules/rtp_rtcp/source/byte_io.h"
Yves Gerey988cc082018-10-23 12:03:01 +020019// TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
20#include "modules/video_coding/codecs/interface/common_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070022
23namespace webrtc {
24// Absolute send time in RTP streams.
25//
26// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020027// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070028// of this extension (the transmitted value) is a 24-bit unsigned integer
29// containing the sender's current time in seconds as a fixed point number
30// with 18 bits fractional part.
31//
32// The form of the absolute send time extension block:
33//
34// 0 1 2 3
35// 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
36// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37// | ID | len=2 | absolute send time |
38// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070039constexpr RTPExtensionType AbsoluteSendTime::kId;
40constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070041constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070042
danilchap978504e2017-04-06 01:03:53 -070043bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
44 uint32_t* time_24bits) {
45 if (data.size() != 3)
46 return false;
47 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -070048 return true;
49}
50
Danil Chapovalov9bf31582018-06-18 13:48:20 +020051bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
52 uint32_t time_24bits) {
53 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020054 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020055 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070056 return true;
57}
58
Chen Xingcd8a6e22019-07-01 10:56:51 +020059// Absolute Capture Time
60//
61// The Absolute Capture Time extension is used to stamp RTP packets with a NTP
62// timestamp showing when the first audio or video frame in a packet was
63// originally captured. The intent of this extension is to provide a way to
64// accomplish audio-to-video synchronization when RTCP-terminating intermediate
65// systems (e.g. mixers) are involved.
66//
67// Data layout of the shortened version of abs-capture-time:
68//
69// 0 1 2 3
70// 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
71// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72// | ID | len=7 | absolute capture timestamp (bit 0-23) |
73// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74// | absolute capture timestamp (bit 24-55) |
75// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76// | ... (56-63) |
77// +-+-+-+-+-+-+-+-+
78//
79// Data layout of the extended version of abs-capture-time:
80//
81// 0 1 2 3
82// 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
83// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84// | ID | len=15| absolute capture timestamp (bit 0-23) |
85// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86// | absolute capture timestamp (bit 24-55) |
87// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88// | ... (56-63) | estimated capture clock offset (bit 0-23) |
89// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90// | estimated capture clock offset (bit 24-55) |
91// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92// | ... (56-63) |
93// +-+-+-+-+-+-+-+-+
94constexpr RTPExtensionType AbsoluteCaptureTimeExtension::kId;
95constexpr uint8_t AbsoluteCaptureTimeExtension::kValueSizeBytes;
96constexpr uint8_t AbsoluteCaptureTimeExtension::
97 kValueSizeBytesWithoutEstimatedCaptureClockOffset;
98constexpr const char AbsoluteCaptureTimeExtension::kUri[];
99
100bool AbsoluteCaptureTimeExtension::Parse(rtc::ArrayView<const uint8_t> data,
101 AbsoluteCaptureTime* extension) {
102 if (data.size() != kValueSizeBytes &&
103 data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
104 return false;
105 }
106
107 extension->absolute_capture_timestamp =
108 ByteReader<uint64_t>::ReadBigEndian(data.data());
109
110 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
111 extension->estimated_capture_clock_offset =
112 ByteReader<int64_t>::ReadBigEndian(data.data() + 8);
113 }
114
115 return true;
116}
117
118size_t AbsoluteCaptureTimeExtension::ValueSize(
119 const AbsoluteCaptureTime& extension) {
120 if (extension.estimated_capture_clock_offset != absl::nullopt) {
121 return kValueSizeBytes;
122 } else {
123 return kValueSizeBytesWithoutEstimatedCaptureClockOffset;
124 }
125}
126
127bool AbsoluteCaptureTimeExtension::Write(rtc::ArrayView<uint8_t> data,
128 const AbsoluteCaptureTime& extension) {
129 RTC_DCHECK_EQ(data.size(), ValueSize(extension));
130
131 ByteWriter<uint64_t>::WriteBigEndian(data.data(),
132 extension.absolute_capture_timestamp);
133
134 if (data.size() != kValueSizeBytesWithoutEstimatedCaptureClockOffset) {
135 ByteWriter<int64_t>::WriteBigEndian(
136 data.data() + 8, extension.estimated_capture_clock_offset.value());
137 }
138
139 return true;
140}
141
danilchap1edb7ab2016-04-20 05:25:10 -0700142// An RTP Header Extension for Client-to-Mixer Audio Level Indication
143//
144// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
145//
146// The form of the audio level extension block:
147//
148// 0 1
149// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
150// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151// | ID | len=0 |V| level |
152// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153//
danilchape2a01772016-10-28 07:08:58 -0700154constexpr RTPExtensionType AudioLevel::kId;
155constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700156constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700157
danilchap978504e2017-04-06 01:03:53 -0700158bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700159 bool* voice_activity,
160 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -0700161 if (data.size() != 1)
162 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700163 *voice_activity = (data[0] & 0x80) != 0;
164 *audio_level = data[0] & 0x7F;
165 return true;
166}
167
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200168bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -0700169 bool voice_activity,
170 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200171 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700172 RTC_CHECK_LE(audio_level, 0x7f);
173 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
174 return true;
175}
176
177// From RFC 5450: Transmission Time Offsets in RTP Streams.
178//
179// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +0200180// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -0700181// of this extension (the transmitted value) is a 24-bit signed integer.
182// When added to the RTP timestamp of the packet, it represents the
183// "effective" RTP transmission time of the packet, on the RTP
184// timescale.
185//
186// The form of the transmission offset extension block:
187//
188// 0 1 2 3
189// 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
190// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191// | ID | len=2 | transmission offset |
192// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700193constexpr RTPExtensionType TransmissionOffset::kId;
194constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700195constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700196
danilchap978504e2017-04-06 01:03:53 -0700197bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
198 int32_t* rtp_time) {
199 if (data.size() != 3)
200 return false;
201 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700202 return true;
203}
204
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200205bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
206 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200207 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200208 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700209 return true;
210}
211
Johannes Kron54047be2019-02-21 14:09:20 +0000212// TransportSequenceNumber
213//
danilchap1edb7ab2016-04-20 05:25:10 -0700214// 0 1 2
215// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
216// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron54047be2019-02-21 14:09:20 +0000217// | ID | L=1 |transport-wide sequence number |
danilchap1edb7ab2016-04-20 05:25:10 -0700218// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700219constexpr RTPExtensionType TransportSequenceNumber::kId;
220constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700221constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700222
danilchap978504e2017-04-06 01:03:53 -0700223bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000224 uint16_t* transport_sequence_number) {
225 if (data.size() != kValueSizeBytes)
danilchap978504e2017-04-06 01:03:53 -0700226 return false;
Johannes Kron54047be2019-02-21 14:09:20 +0000227 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700228 return true;
229}
230
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200231bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20 +0000232 uint16_t transport_sequence_number) {
233 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
234 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
235 return true;
236}
237
238// TransportSequenceNumberV2
239//
240// In addition to the format used for TransportSequencNumber, V2 also supports
241// the following packet format where two extra bytes are used to specify that
242// the sender requests immediate feedback.
243// 0 1 2 3
244// 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
245// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
246// | ID | L=3 |transport-wide sequence number |T| seq count |
247// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248// |seq count cont.|
249// +-+-+-+-+-+-+-+-+
250//
251// The bit |T| determines whether the feedback should include timing information
Johannes Kron0da25a12019-03-06 09:34:13 +0100252// or not and |seq_count| determines how many packets the feedback packet should
253// cover including the current packet. If |seq_count| is zero no feedback is
254// requested.
Johannes Kron54047be2019-02-21 14:09:20 +0000255constexpr RTPExtensionType TransportSequenceNumberV2::kId;
Johannes Kron0da25a12019-03-06 09:34:13 +0100256constexpr uint8_t TransportSequenceNumberV2::kValueSizeBytes;
257constexpr uint8_t
258 TransportSequenceNumberV2::kValueSizeBytesWithoutFeedbackRequest;
Johannes Kron54047be2019-02-21 14:09:20 +0000259constexpr const char TransportSequenceNumberV2::kUri[];
260constexpr uint16_t TransportSequenceNumberV2::kIncludeTimestampsBit;
261
262bool TransportSequenceNumberV2::Parse(
263 rtc::ArrayView<const uint8_t> data,
264 uint16_t* transport_sequence_number,
265 absl::optional<FeedbackRequest>* feedback_request) {
Johannes Kron0da25a12019-03-06 09:34:13 +0100266 if (data.size() != kValueSizeBytes &&
267 data.size() != kValueSizeBytesWithoutFeedbackRequest)
Johannes Kron54047be2019-02-21 14:09:20 +0000268 return false;
269
270 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
271
Johannes Kron0da25a12019-03-06 09:34:13 +0100272 *feedback_request = absl::nullopt;
273 if (data.size() == kValueSizeBytes) {
Johannes Kron54047be2019-02-21 14:09:20 +0000274 uint16_t feedback_request_raw =
275 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
276 bool include_timestamps =
277 (feedback_request_raw & kIncludeTimestampsBit) != 0;
278 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
Johannes Kron0da25a12019-03-06 09:34:13 +0100279
280 // If |sequence_count| is zero no feedback is requested.
281 if (sequence_count != 0) {
282 *feedback_request = {include_timestamps, sequence_count};
283 }
Johannes Kron54047be2019-02-21 14:09:20 +0000284 }
285 return true;
286}
287
288bool TransportSequenceNumberV2::Write(
289 rtc::ArrayView<uint8_t> data,
290 uint16_t transport_sequence_number,
291 const absl::optional<FeedbackRequest>& feedback_request) {
292 RTC_DCHECK_EQ(data.size(),
293 ValueSize(transport_sequence_number, feedback_request));
294
295 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
296
297 if (feedback_request) {
298 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
299 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
300 uint16_t feedback_request_raw =
301 feedback_request->sequence_count |
302 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
303 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
304 }
danilchap1edb7ab2016-04-20 05:25:10 -0700305 return true;
306}
307
308// Coordination of Video Orientation in RTP streams.
309//
310// Coordination of Video Orientation consists in signaling of the current
311// orientation of the image captured on the sender side to the receiver for
312// appropriate rendering and displaying.
313//
314// 0 1
315// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
316// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317// | ID | len=0 |0 0 0 0 C F R R|
318// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700319constexpr RTPExtensionType VideoOrientation::kId;
320constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700321constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700322
danilchap978504e2017-04-06 01:03:53 -0700323bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
324 VideoRotation* rotation) {
325 if (data.size() != 1)
326 return false;
magjed71eb61c2016-09-08 03:24:58 -0700327 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700328 return true;
329}
330
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200331bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
332 VideoRotation rotation) {
333 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700334 data[0] = ConvertVideoRotationToCVOByte(rotation);
335 return true;
336}
337
danilchap978504e2017-04-06 01:03:53 -0700338bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
339 uint8_t* value) {
340 if (data.size() != 1)
341 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700342 *value = data[0];
343 return true;
344}
345
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200346bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
347 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700348 data[0] = value;
349 return true;
350}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200351
352// 0 1 2 3
353// 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
354// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355// | ID | len=2 | MIN delay | MAX delay |
356// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357constexpr RTPExtensionType PlayoutDelayLimits::kId;
358constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700359constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200360
danilchap978504e2017-04-06 01:03:53 -0700361bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200362 PlayoutDelay* playout_delay) {
363 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700364 if (data.size() != 3)
365 return false;
366 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200367 uint16_t min_raw = (raw >> 12);
368 uint16_t max_raw = (raw & 0xfff);
369 if (min_raw > max_raw)
370 return false;
371 playout_delay->min_ms = min_raw * kGranularityMs;
372 playout_delay->max_ms = max_raw * kGranularityMs;
373 return true;
374}
375
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200376bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200377 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200378 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200379 RTC_DCHECK_LE(0, playout_delay.min_ms);
380 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
381 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
382 // Convert MS to value to be sent on extension header.
383 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
384 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200385 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
386 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200387 return true;
388}
389
ilnik00d802b2017-04-11 10:34:31 -0700390// Video Content Type.
391//
392// E.g. default video or screenshare.
393//
394// 0 1
395// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
396// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397// | ID | len=0 | Content type |
398// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399constexpr RTPExtensionType VideoContentTypeExtension::kId;
400constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700401constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700402
403bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
404 VideoContentType* content_type) {
405 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700406 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700407 *content_type = static_cast<VideoContentType>(data[0]);
408 return true;
409 }
410 return false;
411}
412
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200413bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700414 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200415 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700416 data[0] = static_cast<uint8_t>(content_type);
417 return true;
418}
419
ilnik04f4d122017-06-19 07:18:55 -0700420// Video Timing.
421// 6 timestamps in milliseconds counted from capture time stored in rtp header:
422// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700423// modification by the network modification. |flags| is a bitmask and has the
424// following allowed values:
425// 0 = Valid data, but no flags available (backwards compatibility)
426// 1 = Frame marked as timing frame due to cyclic timer.
427// 2 = Frame marked as timing frame due to size being outside limit.
428// 255 = Invalid. The whole timing frame extension should be ignored.
429//
ilnik04f4d122017-06-19 07:18:55 -0700430// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100431// 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
432// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433// | ID | len=12| flags | encode start ms delta |
434// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435// | encode finish ms delta | packetizer finish ms delta |
436// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437// | pacer exit ms delta | network timestamp ms delta |
438// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700439// | network2 timestamp ms delta |
440// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700441
442constexpr RTPExtensionType VideoTimingExtension::kId;
443constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700444constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700445
446bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700447 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700448 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700449 // TODO(sprang): Deprecate support for old wire format.
450 ptrdiff_t off = 0;
451 switch (data.size()) {
452 case kValueSizeBytes - 1:
453 timing->flags = 0;
454 off = 1; // Old wire format without the flags field.
455 break;
456 case kValueSizeBytes:
457 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
458 break;
459 default:
460 return false;
461 }
462
463 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
464 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700465 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700466 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700467 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700468 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700469 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700470 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100471 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700472 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100473 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700474 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700475 return true;
476}
477
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200478bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
479 const VideoSendTiming& timing) {
480 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
481 ByteWriter<uint8_t>::WriteBigEndian(
482 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700483 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200484 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700485 timing.encode_start_delta_ms);
486 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200487 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700488 timing.encode_finish_delta_ms);
489 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200490 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700491 timing.packetization_finish_delta_ms);
492 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200493 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700494 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700495 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200496 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100497 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700498 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200499 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100500 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700501 return true;
502}
503
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200504bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700505 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700506 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200507 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100508 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200509 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700510 return true;
511}
512
Johnny Leee0c8b232018-09-11 16:50:49 -0400513// Frame Marking.
514//
515// Meta-information about an RTP stream outside the encrypted media payload,
516// useful for an RTP switch to do codec-agnostic selective forwarding
517// without decrypting the payload.
518//
519// For non-scalable streams:
520// 0 1
521// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
522// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523// | ID | L = 0 |S|E|I|D|0 0 0 0|
524// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525//
526// For scalable streams:
527// 0 1 2 3
528// 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
529// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
530// | ID | L = 2 |S|E|I|D|B| TID | LID | TL0PICIDX |
531// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532
533constexpr RTPExtensionType FrameMarkingExtension::kId;
534constexpr const char FrameMarkingExtension::kUri[];
535
536bool FrameMarkingExtension::IsScalable(uint8_t temporal_id, uint8_t layer_id) {
537 return temporal_id != kNoTemporalIdx || layer_id != kNoSpatialIdx;
538}
539
540bool FrameMarkingExtension::Parse(rtc::ArrayView<const uint8_t> data,
541 FrameMarking* frame_marking) {
542 RTC_DCHECK(frame_marking);
543
544 if (data.size() != 1 && data.size() != 3)
545 return false;
546
547 frame_marking->start_of_frame = (data[0] & 0x80) != 0;
548 frame_marking->end_of_frame = (data[0] & 0x40) != 0;
549 frame_marking->independent_frame = (data[0] & 0x20) != 0;
550 frame_marking->discardable_frame = (data[0] & 0x10) != 0;
551
552 if (data.size() == 3) {
553 frame_marking->base_layer_sync = (data[0] & 0x08) != 0;
554 frame_marking->temporal_id = data[0] & 0x7;
555 frame_marking->layer_id = data[1];
556 frame_marking->tl0_pic_idx = data[2];
557 } else {
558 // non-scalable
559 frame_marking->base_layer_sync = false;
560 frame_marking->temporal_id = kNoTemporalIdx;
561 frame_marking->layer_id = kNoSpatialIdx;
562 frame_marking->tl0_pic_idx = 0;
563 }
564 return true;
565}
566
567size_t FrameMarkingExtension::ValueSize(const FrameMarking& frame_marking) {
568 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id))
569 return 3;
570 else
571 return 1;
572}
573
574bool FrameMarkingExtension::Write(rtc::ArrayView<uint8_t> data,
575 const FrameMarking& frame_marking) {
576 RTC_DCHECK_GE(data.size(), 1);
577 RTC_CHECK_LE(frame_marking.temporal_id, 0x07);
578 data[0] = frame_marking.start_of_frame ? 0x80 : 0x00;
579 data[0] |= frame_marking.end_of_frame ? 0x40 : 0x00;
580 data[0] |= frame_marking.independent_frame ? 0x20 : 0x00;
581 data[0] |= frame_marking.discardable_frame ? 0x10 : 0x00;
582
583 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id)) {
584 RTC_DCHECK_EQ(data.size(), 3);
585 data[0] |= frame_marking.base_layer_sync ? 0x08 : 0x00;
586 data[0] |= frame_marking.temporal_id & 0x07;
587 data[1] = frame_marking.layer_id;
588 data[2] = frame_marking.tl0_pic_idx;
589 }
590 return true;
591}
592
Johannes Kron09d65882018-11-27 14:36:41 +0100593// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100594//
Johannes Krond0b69a82018-12-03 14:18:53 +0100595// RTP header extension to carry color space information and optionally HDR
596// metadata. The float values in the HDR metadata struct are upscaled by a
597// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100598//
Johannes Krond0b69a82018-12-03 14:18:53 +0100599// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100600// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100601// 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
602// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100603// | ID | length=28 | primaries | transfer |
Johannes Krond0b69a82018-12-03 14:18:53 +0100604// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100605// | matrix |range+chr.sit. | luminance_max |
Johannes Krond0b69a82018-12-03 14:18:53 +0100606// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100607// | luminance_min | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100608// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100609// |primary_r.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100610// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100611// |primary_g.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100612// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100613// |primary_b.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 14:18:53 +0100614// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100615// |white.x and .y | max_content_light_level |
Johannes Krond0b69a82018-12-03 14:18:53 +0100616// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100617// | max_frame_average_light_level |
618// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 14:36:41 +0100619//
Johannes Krond0b69a82018-12-03 14:18:53 +0100620// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 14:36:41 +0100621// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100622// 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
623// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100624// | ID | L = 3 | primaries | transfer | matrix |
Johannes Krond0b69a82018-12-03 14:18:53 +0100625// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 09:52:53 +0100626// |range+chr.sit. |
Johannes Krond0b69a82018-12-03 14:18:53 +0100627// +-+-+-+-+-+-+-+-+
Johannes Kronad1d9f02018-11-09 11:12:36 +0100628
Johannes Kron09d65882018-11-27 14:36:41 +0100629constexpr RTPExtensionType ColorSpaceExtension::kId;
630constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
631constexpr const char ColorSpaceExtension::kUri[];
632
633bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
634 ColorSpace* color_space) {
635 RTC_DCHECK(color_space);
636 if (data.size() != kValueSizeBytes &&
637 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100638 return false;
639
640 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100641 // Read color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100642 if (!color_space->set_primaries_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100643 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100644 if (!color_space->set_transfer_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_matrix_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 14:36:41 +0100647 return false;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100648
649 uint8_t range_and_chroma_siting = data[offset++];
650 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
651 return false;
652 if (!color_space->set_chroma_siting_horizontal_from_uint8(
653 (range_and_chroma_siting >> 2) & 0x03))
654 return false;
655 if (!color_space->set_chroma_siting_vertical_from_uint8(
656 range_and_chroma_siting & 0x03))
Johannes Kron09d65882018-11-27 14:36:41 +0100657 return false;
658
659 // Read HDR metadata if it exists, otherwise clear it.
660 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
661 color_space->set_hdr_metadata(nullptr);
662 } else {
663 HdrMetadata hdr_metadata;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100664 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
665 if (!hdr_metadata.Validate())
666 return false;
Johannes Kron09d65882018-11-27 14:36:41 +0100667 color_space->set_hdr_metadata(&hdr_metadata);
668 }
669 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100670 return true;
671}
672
Johannes Kron09d65882018-11-27 14:36:41 +0100673bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
674 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 14:18:53 +0100675 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 11:12:36 +0100676 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100677 // Write color space information.
Johannes Kronc13f4be2018-12-12 09:52:53 +0100678 data[offset++] = static_cast<uint8_t>(color_space.primaries());
679 data[offset++] = static_cast<uint8_t>(color_space.transfer());
680 data[offset++] = static_cast<uint8_t>(color_space.matrix());
681 data[offset++] = CombineRangeAndChromaSiting(
682 color_space.range(), color_space.chroma_siting_horizontal(),
683 color_space.chroma_siting_vertical());
Johannes Kronad1d9f02018-11-09 11:12:36 +0100684
Johannes Kron09d65882018-11-27 14:36:41 +0100685 // Write HDR metadata if it exists.
686 if (color_space.hdr_metadata()) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100687 offset +=
688 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
Johannes Kron09d65882018-11-27 14:36:41 +0100689 }
690 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100691 return true;
692}
693
Johannes Kronc13f4be2018-12-12 09:52:53 +0100694// Combines range and chroma siting into one byte with the following bit layout:
695// bits 0-1 Chroma siting vertical.
696// 2-3 Chroma siting horizontal.
697// 4-5 Range.
698// 6-7 Unused.
699uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
700 ColorSpace::RangeID range,
701 ColorSpace::ChromaSiting chroma_siting_horizontal,
702 ColorSpace::ChromaSiting chroma_siting_vertical) {
703 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
704 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
705 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
706 return (static_cast<uint8_t>(range) << 4) |
707 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
708 static_cast<uint8_t>(chroma_siting_vertical);
709}
710
711size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
712 HdrMetadata* hdr_metadata) {
713 RTC_DCHECK_EQ(data.size(),
714 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
715 size_t offset = 0;
716 offset += ParseLuminance(data.data() + offset,
717 &hdr_metadata->mastering_metadata.luminance_max,
718 kLuminanceMaxDenominator);
719 offset += ParseLuminance(data.data() + offset,
720 &hdr_metadata->mastering_metadata.luminance_min,
721 kLuminanceMinDenominator);
722 offset += ParseChromaticity(data.data() + offset,
723 &hdr_metadata->mastering_metadata.primary_r);
724 offset += ParseChromaticity(data.data() + offset,
725 &hdr_metadata->mastering_metadata.primary_g);
726 offset += ParseChromaticity(data.data() + offset,
727 &hdr_metadata->mastering_metadata.primary_b);
728 offset += ParseChromaticity(data.data() + offset,
729 &hdr_metadata->mastering_metadata.white_point);
730 hdr_metadata->max_content_light_level =
731 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
732 offset += 2;
733 hdr_metadata->max_frame_average_light_level =
734 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
735 offset += 2;
736 return offset;
737}
738
Johannes Kron09d65882018-11-27 14:36:41 +0100739size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100740 const uint8_t* data,
741 HdrMasteringMetadata::Chromaticity* p) {
742 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
743 uint16_t chromaticity_y_scaled =
744 ByteReader<uint16_t>::ReadBigEndian(data + 2);
745 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
746 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
747 return 4; // Return number of bytes read.
748}
749
Johannes Kron09d65882018-11-27 14:36:41 +0100750size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
751 float* f,
752 int denominator) {
Johannes Kronc13f4be2018-12-12 09:52:53 +0100753 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100754 *f = static_cast<float>(luminance_scaled) / denominator;
Johannes Kronc13f4be2018-12-12 09:52:53 +0100755 return 2; // Return number of bytes read.
756}
757
758size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
759 const HdrMetadata& hdr_metadata) {
760 RTC_DCHECK_EQ(data.size(),
761 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
762 RTC_DCHECK(hdr_metadata.Validate());
763 size_t offset = 0;
764 offset += WriteLuminance(data.data() + offset,
765 hdr_metadata.mastering_metadata.luminance_max,
766 kLuminanceMaxDenominator);
767 offset += WriteLuminance(data.data() + offset,
768 hdr_metadata.mastering_metadata.luminance_min,
769 kLuminanceMinDenominator);
770 offset += WriteChromaticity(data.data() + offset,
771 hdr_metadata.mastering_metadata.primary_r);
772 offset += WriteChromaticity(data.data() + offset,
773 hdr_metadata.mastering_metadata.primary_g);
774 offset += WriteChromaticity(data.data() + offset,
775 hdr_metadata.mastering_metadata.primary_b);
776 offset += WriteChromaticity(data.data() + offset,
777 hdr_metadata.mastering_metadata.white_point);
778
779 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
780 hdr_metadata.max_content_light_level);
781 offset += 2;
782 ByteWriter<uint16_t>::WriteBigEndian(
783 data.data() + offset, hdr_metadata.max_frame_average_light_level);
784 offset += 2;
785 return offset;
Johannes Kronad1d9f02018-11-09 11:12:36 +0100786}
787
Johannes Kron09d65882018-11-27 14:36:41 +0100788size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100789 uint8_t* data,
790 const HdrMasteringMetadata::Chromaticity& p) {
791 RTC_DCHECK_GE(p.x, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100792 RTC_DCHECK_LE(p.x, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100793 RTC_DCHECK_GE(p.y, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100794 RTC_DCHECK_LE(p.y, 1.0f);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100795 ByteWriter<uint16_t>::WriteBigEndian(
796 data, std::round(p.x * kChromaticityDenominator));
797 ByteWriter<uint16_t>::WriteBigEndian(
798 data + 2, std::round(p.y * kChromaticityDenominator));
799 return 4; // Return number of bytes written.
800}
801
Johannes Kron09d65882018-11-27 14:36:41 +0100802size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
803 float f,
804 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100805 RTC_DCHECK_GE(f, 0.0f);
Johannes Kronc13f4be2018-12-12 09:52:53 +0100806 float upscaled_value = f * denominator;
807 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
808 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
809 return 2; // Return number of bytes written.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100810}
811
Steve Antona3251dd2017-07-21 09:58:31 -0700812bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700813 std::string* str) {
814 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
815 return false;
816 const char* cstr = reinterpret_cast<const char*>(data.data());
817 // If there is a \0 character in the middle of the |data|, treat it as end
818 // of the string. Well-formed string extensions shouldn't contain it.
819 str->assign(cstr, strnlen(cstr, data.size()));
820 RTC_DCHECK(!str->empty());
821 return true;
822}
823
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200824bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
825 const std::string& str) {
Niels Möllerd57efc12019-03-22 14:02:11 +0100826 if (str.size() > kMaxValueSizeBytes) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200827 return false;
828 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200829 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700830 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200831 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700832 return true;
833}
834
835// Constant declarations for string RTP header extension types.
836
danilchapef8d7732017-04-19 02:59:48 -0700837constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700838constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700839
danilchapef8d7732017-04-19 02:59:48 -0700840constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700841constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700842
Steve Antona3251dd2017-07-21 09:58:31 -0700843constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700844constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700845
danilchap1edb7ab2016-04-20 05:25:10 -0700846} // namespace webrtc