blob: e42a84bd06c70e8b75ef66bf4f4b254a3a924cc9 [file] [log] [blame]
danilchap1edb7ab2016-04-20 12:25:101/*
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 04:47:3111#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
danilchap1edb7ab2016-04-20 12:25:1012
Yves Gerey988cc082018-10-23 10:03:0113#include <string.h>
Jonas Olssona4d87372019-07-05 17:08:3314
Johannes Kronad1d9f02018-11-09 10:12:3615#include <cmath>
Danil Chapovalov093a9392023-08-23 11:49:5716#include <cstddef>
Doudou Kisabakaae0d1172021-05-24 11:04:4517#include <cstdint>
Johannes Kronc13f4be2018-12-12 08:52:5318#include <limits>
Danil Chapovalov093a9392023-08-23 11:49:5719#include <string>
20#include <vector>
Yves Gerey988cc082018-10-23 10:03:0121
Ali Tofighd14e8892022-05-13 09:42:1622#include "absl/strings/string_view.h"
Danil Chapovalov093a9392023-08-23 11:49:5723#include "absl/types/optional.h"
24#include "api/array_view.h"
25#include "api/rtp_headers.h"
26#include "api/video/color_space.h"
27#include "api/video/hdr_metadata.h"
28#include "api/video/video_content_type.h"
29#include "api/video/video_rotation.h"
30#include "api/video/video_timing.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3131#include "modules/rtp_rtcp/include/rtp_cvo.h"
32#include "modules/rtp_rtcp/source/byte_io.h"
33#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 12:25:1034
35namespace webrtc {
36// Absolute send time in RTP streams.
37//
38// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 11:33:3539// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 12:25:1040// of this extension (the transmitted value) is a 24-bit unsigned integer
41// containing the sender's current time in seconds as a fixed point number
42// with 18 bits fractional part.
43//
44// The form of the absolute send time extension block:
45//
46// 0 1 2 3
47// 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
48// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49// | ID | len=2 | absolute send time |
50// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap978504e2017-04-06 08:03:5351bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
52 uint32_t* time_24bits) {
53 if (data.size() != 3)
54 return false;
55 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 12:25:1056 return true;
57}
58
Danil Chapovalov9bf31582018-06-18 11:48:2059bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
60 uint32_t time_24bits) {
61 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 13:43:5562 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 11:48:2063 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 12:25:1064 return true;
65}
66
Chen Xingcd8a6e22019-07-01 08:56:5167// Absolute Capture Time
68//
69// The Absolute Capture Time extension is used to stamp RTP packets with a NTP
70// timestamp showing when the first audio or video frame in a packet was
71// originally captured. The intent of this extension is to provide a way to
72// accomplish audio-to-video synchronization when RTCP-terminating intermediate
73// systems (e.g. mixers) are involved.
74//
75// Data layout of the shortened version of abs-capture-time:
76//
77// 0 1 2 3
78// 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
79// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80// | ID | len=7 | absolute capture timestamp (bit 0-23) |
81// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82// | absolute capture timestamp (bit 24-55) |
83// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84// | ... (56-63) |
85// +-+-+-+-+-+-+-+-+
86//
87// Data layout of the extended version of abs-capture-time:
88//
89// 0 1 2 3
90// 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
91// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92// | ID | len=15| absolute capture timestamp (bit 0-23) |
93// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94// | absolute capture timestamp (bit 24-55) |
95// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96// | ... (56-63) | estimated capture clock offset (bit 0-23) |
97// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98// | estimated capture clock offset (bit 24-55) |
99// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100// | ... (56-63) |
101// +-+-+-+-+-+-+-+-+
Chen Xingcd8a6e22019-07-01 08:56:51102bool 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 12:25:10144// An RTP Header Extension for Client-to-Mixer Audio Level Indication
145//
Minyue Lid1ea4c92019-10-31 09:59:18146// https://tools.ietf.org/html/rfc6464
danilchap1edb7ab2016-04-20 12:25:10147//
148// The form of the audio level extension block:
149//
Minyue Lid1ea4c92019-10-31 09:59:18150// 0 1
151// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
152// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153// | ID | len=0 |V| level |
154// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155// Sample Audio Level Encoding Using the One-Byte Header Format
danilchap1edb7ab2016-04-20 12:25:10156//
Minyue Lid1ea4c92019-10-31 09:59:18157// 0 1 2
158// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
159// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160// | ID | len=1 |V| level |
161// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162// Sample Audio Level Encoding Using the Two-Byte Header Format
danilchap978504e2017-04-06 08:03:53163bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 12:25:10164 bool* voice_activity,
165 uint8_t* audio_level) {
Minyue Lid1ea4c92019-10-31 09:59:18166 // One-byte and two-byte format share the same data definition.
danilchap978504e2017-04-06 08:03:53167 if (data.size() != 1)
168 return false;
danilchap1edb7ab2016-04-20 12:25:10169 *voice_activity = (data[0] & 0x80) != 0;
170 *audio_level = data[0] & 0x7F;
171 return true;
172}
173
Danil Chapovalov9bf31582018-06-18 11:48:20174bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 12:25:10175 bool voice_activity,
176 uint8_t audio_level) {
Minyue Lid1ea4c92019-10-31 09:59:18177 // One-byte and two-byte format share the same data definition.
Danil Chapovalov9bf31582018-06-18 11:48:20178 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 12:25:10179 RTC_CHECK_LE(audio_level, 0x7f);
180 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
181 return true;
182}
183
Doudou Kisabakaae0d1172021-05-24 11:04:45184// An RTP Header Extension for Mixer-to-Client Audio Level Indication
185//
186// https://tools.ietf.org/html/rfc6465
187//
188// The form of the audio level 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 |0| level 1 |0| level 2 |0| level 3 |
194// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195// Sample Audio Level Encoding Using the One-Byte Header Format
196//
197// 0 1 2 3
198// 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
199// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200// | ID | len=3 |0| level 1 |0| level 2 |
201// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202// |0| level 3 | 0 (pad) | ... |
203// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204// Sample Audio Level Encoding Using the Two-Byte Header Format
Doudou Kisabakaae0d1172021-05-24 11:04:45205bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
206 std::vector<uint8_t>* csrc_audio_levels) {
207 if (data.size() > kRtpCsrcSize) {
208 return false;
209 }
210 csrc_audio_levels->resize(data.size());
211 for (size_t i = 0; i < data.size(); i++) {
212 (*csrc_audio_levels)[i] = data[i] & 0x7F;
213 }
214 return true;
215}
216
217size_t CsrcAudioLevel::ValueSize(
218 rtc::ArrayView<const uint8_t> csrc_audio_levels) {
219 return csrc_audio_levels.size();
220}
221
222bool CsrcAudioLevel::Write(rtc::ArrayView<uint8_t> data,
223 rtc::ArrayView<const uint8_t> csrc_audio_levels) {
224 RTC_CHECK_LE(csrc_audio_levels.size(), kRtpCsrcSize);
225 if (csrc_audio_levels.size() != data.size()) {
226 return false;
227 }
228 for (size_t i = 0; i < csrc_audio_levels.size(); i++) {
229 data[i] = csrc_audio_levels[i] & 0x7F;
230 }
231 return true;
232}
233
danilchap1edb7ab2016-04-20 12:25:10234// From RFC 5450: Transmission Time Offsets in RTP Streams.
235//
236// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 11:33:35237// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 12:25:10238// of this extension (the transmitted value) is a 24-bit signed integer.
239// When added to the RTP timestamp of the packet, it represents the
240// "effective" RTP transmission time of the packet, on the RTP
241// timescale.
242//
243// The form of the transmission offset extension block:
244//
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 | len=2 | transmission offset |
249// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap978504e2017-04-06 08:03:53250bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
251 int32_t* rtp_time) {
252 if (data.size() != 3)
253 return false;
254 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 12:25:10255 return true;
256}
257
Danil Chapovalov9bf31582018-06-18 11:48:20258bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
259 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 16:27:40260 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 11:48:20261 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 12:25:10262 return true;
263}
264
Johannes Kron54047be2019-02-21 14:09:20265// TransportSequenceNumber
266//
danilchap1edb7ab2016-04-20 12:25:10267// 0 1 2
268// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
269// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron54047be2019-02-21 14:09:20270// | ID | L=1 |transport-wide sequence number |
danilchap1edb7ab2016-04-20 12:25:10271// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap978504e2017-04-06 08:03:53272bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20273 uint16_t* transport_sequence_number) {
274 if (data.size() != kValueSizeBytes)
danilchap978504e2017-04-06 08:03:53275 return false;
Johannes Kron54047be2019-02-21 14:09:20276 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 12:25:10277 return true;
278}
279
Danil Chapovalov9bf31582018-06-18 11:48:20280bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
Johannes Kron54047be2019-02-21 14:09:20281 uint16_t transport_sequence_number) {
282 RTC_DCHECK_EQ(data.size(), ValueSize(transport_sequence_number));
283 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
284 return true;
285}
286
287// TransportSequenceNumberV2
288//
289// In addition to the format used for TransportSequencNumber, V2 also supports
290// the following packet format where two extra bytes are used to specify that
291// the sender requests immediate feedback.
292// 0 1 2 3
293// 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
294// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
295// | ID | L=3 |transport-wide sequence number |T| seq count |
296// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
297// |seq count cont.|
298// +-+-+-+-+-+-+-+-+
299//
Artem Titov913cfa72021-07-28 21:57:33300// The bit `T` determines whether the feedback should include timing information
301// or not and `seq_count` determines how many packets the feedback packet should
302// cover including the current packet. If `seq_count` is zero no feedback is
Johannes Kron0da25a12019-03-06 08:34:13303// requested.
Johannes Kron54047be2019-02-21 14:09:20304bool TransportSequenceNumberV2::Parse(
305 rtc::ArrayView<const uint8_t> data,
306 uint16_t* transport_sequence_number,
307 absl::optional<FeedbackRequest>* feedback_request) {
Johannes Kron0da25a12019-03-06 08:34:13308 if (data.size() != kValueSizeBytes &&
309 data.size() != kValueSizeBytesWithoutFeedbackRequest)
Johannes Kron54047be2019-02-21 14:09:20310 return false;
311
312 *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data.data());
313
Johannes Kron0da25a12019-03-06 08:34:13314 *feedback_request = absl::nullopt;
315 if (data.size() == kValueSizeBytes) {
Johannes Kron54047be2019-02-21 14:09:20316 uint16_t feedback_request_raw =
317 ByteReader<uint16_t>::ReadBigEndian(data.data() + 2);
318 bool include_timestamps =
319 (feedback_request_raw & kIncludeTimestampsBit) != 0;
320 uint16_t sequence_count = feedback_request_raw & ~kIncludeTimestampsBit;
Johannes Kron0da25a12019-03-06 08:34:13321
Artem Titov913cfa72021-07-28 21:57:33322 // If `sequence_count` is zero no feedback is requested.
Johannes Kron0da25a12019-03-06 08:34:13323 if (sequence_count != 0) {
324 *feedback_request = {include_timestamps, sequence_count};
325 }
Johannes Kron54047be2019-02-21 14:09:20326 }
327 return true;
328}
329
330bool TransportSequenceNumberV2::Write(
331 rtc::ArrayView<uint8_t> data,
332 uint16_t transport_sequence_number,
333 const absl::optional<FeedbackRequest>& feedback_request) {
334 RTC_DCHECK_EQ(data.size(),
335 ValueSize(transport_sequence_number, feedback_request));
336
337 ByteWriter<uint16_t>::WriteBigEndian(data.data(), transport_sequence_number);
338
339 if (feedback_request) {
340 RTC_DCHECK_GE(feedback_request->sequence_count, 0);
341 RTC_DCHECK_LT(feedback_request->sequence_count, kIncludeTimestampsBit);
342 uint16_t feedback_request_raw =
343 feedback_request->sequence_count |
344 (feedback_request->include_timestamps ? kIncludeTimestampsBit : 0);
345 ByteWriter<uint16_t>::WriteBigEndian(data.data() + 2, feedback_request_raw);
346 }
danilchap1edb7ab2016-04-20 12:25:10347 return true;
348}
349
350// Coordination of Video Orientation in RTP streams.
351//
352// Coordination of Video Orientation consists in signaling of the current
353// orientation of the image captured on the sender side to the receiver for
354// appropriate rendering and displaying.
355//
356// 0 1
357// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
358// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359// | ID | len=0 |0 0 0 0 C F R R|
360// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap978504e2017-04-06 08:03:53361bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
362 VideoRotation* rotation) {
363 if (data.size() != 1)
364 return false;
magjed71eb61c2016-09-08 10:24:58365 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 12:25:10366 return true;
367}
368
Danil Chapovalov9bf31582018-06-18 11:48:20369bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
370 VideoRotation rotation) {
371 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 12:25:10372 data[0] = ConvertVideoRotationToCVOByte(rotation);
373 return true;
374}
375
danilchap978504e2017-04-06 08:03:53376bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
377 uint8_t* value) {
378 if (data.size() != 1)
379 return false;
danilchap1edb7ab2016-04-20 12:25:10380 *value = data[0];
381 return true;
382}
383
Danil Chapovalov9bf31582018-06-18 11:48:20384bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
385 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 12:25:10386 data[0] = value;
387 return true;
388}
Danil Chapovalov08b03512016-09-07 13:08:13389
390// 0 1 2 3
391// 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
392// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393// | ID | len=2 | MIN delay | MAX delay |
394// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap978504e2017-04-06 08:03:53395bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Niels Möllerd381eed2020-09-02 13:34:40396 VideoPlayoutDelay* playout_delay) {
Danil Chapovalov08b03512016-09-07 13:08:13397 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 08:03:53398 if (data.size() != 3)
399 return false;
400 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 13:08:13401 uint16_t min_raw = (raw >> 12);
402 uint16_t max_raw = (raw & 0xfff);
Danil Chapovalov7084e1b2023-08-23 11:16:22403 return playout_delay->Set(min_raw * kGranularity, max_raw * kGranularity);
Danil Chapovalov08b03512016-09-07 13:08:13404}
405
Danil Chapovalov9bf31582018-06-18 11:48:20406bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Niels Möllerd381eed2020-09-02 13:34:40407 const VideoPlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 11:48:20408 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov7084e1b2023-08-23 11:16:22409
410 // Convert TimeDelta to value to be sent on extension header.
411 auto idiv = [](TimeDelta num, TimeDelta den) { return num.us() / den.us(); };
412 int64_t min_delay = idiv(playout_delay.min(), kGranularity);
413 int64_t max_delay = idiv(playout_delay.max(), kGranularity);
414
415 // Double check min/max boundaries guaranteed by the `VideoPlayouDelay` type.
416 RTC_DCHECK_GE(min_delay, 0);
417 RTC_DCHECK_LT(min_delay, 1 << 12);
418 RTC_DCHECK_GE(max_delay, 0);
419 RTC_DCHECK_LT(max_delay, 1 << 12);
420
Danil Chapovalov9bf31582018-06-18 11:48:20421 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
422 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 13:08:13423 return true;
424}
425
ilnik00d802b2017-04-11 17:34:31426// Video Content Type.
427//
428// E.g. default video or screenshare.
429//
430// 0 1
431// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
432// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433// | ID | len=0 | Content type |
434// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik00d802b2017-04-11 17:34:31435bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
436 VideoContentType* content_type) {
437 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 10:32:14438 videocontenttypehelpers::IsValidContentType(data[0])) {
Harald Alvestrand00f11222023-07-21 07:23:01439 // Only the lowest bit of ContentType has a defined meaning.
440 // Due to previous, now removed, usage of 5 more bits, values with
441 // those bits set are accepted as valid, but we mask them out before
442 // converting to a VideoContentType.
443 *content_type = static_cast<VideoContentType>(data[0] & 0x1);
ilnik00d802b2017-04-11 17:34:31444 return true;
445 }
446 return false;
447}
448
Danil Chapovalov9bf31582018-06-18 11:48:20449bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 17:34:31450 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 11:48:20451 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 17:34:31452 data[0] = static_cast<uint8_t>(content_type);
453 return true;
454}
455
ilnik04f4d122017-06-19 14:18:55456// Video Timing.
457// 6 timestamps in milliseconds counted from capture time stored in rtp header:
458// encode start/finish, packetization complete, pacer exit and reserved for
Artem Titov913cfa72021-07-28 21:57:33459// modification by the network modification. `flags` is a bitmask and has the
sprangba050a62017-08-18 09:51:12460// following allowed values:
461// 0 = Valid data, but no flags available (backwards compatibility)
462// 1 = Frame marked as timing frame due to cyclic timer.
463// 2 = Frame marked as timing frame due to size being outside limit.
464// 255 = Invalid. The whole timing frame extension should be ignored.
465//
ilnik04f4d122017-06-19 14:18:55466// 0 1 2 3
Johannes Krond0b69a82018-12-03 13:18:53467// 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
468// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
469// | ID | len=12| flags | encode start ms delta |
470// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
471// | encode finish ms delta | packetizer finish ms delta |
472// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
473// | pacer exit ms delta | network timestamp ms delta |
474// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 09:51:12475// | network2 timestamp ms delta |
476// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 14:18:55477bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 10:06:50478 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 14:18:55479 RTC_DCHECK(timing);
sprangba050a62017-08-18 09:51:12480 // TODO(sprang): Deprecate support for old wire format.
481 ptrdiff_t off = 0;
482 switch (data.size()) {
483 case kValueSizeBytes - 1:
484 timing->flags = 0;
485 off = 1; // Old wire format without the flags field.
486 break;
487 case kValueSizeBytes:
488 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
489 break;
490 default:
491 return false;
492 }
493
494 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31495 data.data() + kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 14:18:55496 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31497 data.data() + kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 14:18:55498 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31499 data.data() + kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 14:18:55500 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31501 data.data() + kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 16:14:41502 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31503 data.data() + kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 16:14:41504 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31505 data.data() + kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 14:18:55506 return true;
507}
508
Danil Chapovalov9bf31582018-06-18 11:48:20509bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
510 const VideoSendTiming& timing) {
511 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
Danil Chapovalovdf2c6012020-01-17 14:37:31512 ByteWriter<uint8_t>::WriteBigEndian(data.data() + kFlagsOffset, timing.flags);
513 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeStartDeltaOffset,
514 timing.encode_start_delta_ms);
515 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kEncodeFinishDeltaOffset,
516 timing.encode_finish_delta_ms);
ilnik04f4d122017-06-19 14:18:55517 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31518 data.data() + kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 14:18:55519 timing.packetization_finish_delta_ms);
Danil Chapovalovdf2c6012020-01-17 14:37:31520 ByteWriter<uint16_t>::WriteBigEndian(data.data() + kPacerExitDeltaOffset,
521 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 14:18:55522 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31523 data.data() + kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc81432017-10-31 16:59:39524 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 14:18:55525 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalovdf2c6012020-01-17 14:37:31526 data.data() + kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc81432017-10-31 16:59:39527 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 14:18:55528 return true;
529}
530
Danil Chapovalov9bf31582018-06-18 11:48:20531bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 14:18:55532 uint16_t time_delta_ms,
sprangba050a62017-08-18 09:51:12533 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 11:48:20534 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc81432017-10-31 16:59:39535 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 11:48:20536 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 14:18:55537 return true;
538}
539
Johannes Kron09d65882018-11-27 13:36:41540// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 10:12:36541//
Johannes Krond0b69a82018-12-03 13:18:53542// RTP header extension to carry color space information and optionally HDR
543// metadata. The float values in the HDR metadata struct are upscaled by a
544// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 10:12:36545//
Johannes Krond0b69a82018-12-03 13:18:53546// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 10:12:36547// 0 1 2 3
Johannes Krond0b69a82018-12-03 13:18:53548// 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
549// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53550// | ID | length=28 | primaries | transfer |
Johannes Krond0b69a82018-12-03 13:18:53551// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53552// | matrix |range+chr.sit. | luminance_max |
Johannes Krond0b69a82018-12-03 13:18:53553// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53554// | luminance_min | mastering_metadata.|
Johannes Krond0b69a82018-12-03 13:18:53555// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53556// |primary_r.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 13:18:53557// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53558// |primary_g.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 13:18:53559// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53560// |primary_b.x and .y | mastering_metadata.|
Johannes Krond0b69a82018-12-03 13:18:53561// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53562// |white.x and .y | max_content_light_level |
Johannes Krond0b69a82018-12-03 13:18:53563// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53564// | max_frame_average_light_level |
565// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 13:36:41566//
Johannes Krond0b69a82018-12-03 13:18:53567// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 13:36:41568// 0 1 2 3
Johannes Krond0b69a82018-12-03 13:18:53569// 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
570// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53571// | ID | L = 3 | primaries | transfer | matrix |
Johannes Krond0b69a82018-12-03 13:18:53572// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kronc13f4be2018-12-12 08:52:53573// |range+chr.sit. |
Johannes Krond0b69a82018-12-03 13:18:53574// +-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 13:36:41575bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
576 ColorSpace* color_space) {
577 RTC_DCHECK(color_space);
578 if (data.size() != kValueSizeBytes &&
579 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 10:12:36580 return false;
581
582 size_t offset = 0;
Johannes Kron09d65882018-11-27 13:36:41583 // Read color space information.
Johannes Kronc13f4be2018-12-12 08:52:53584 if (!color_space->set_primaries_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 13:36:41585 return false;
Johannes Kronc13f4be2018-12-12 08:52:53586 if (!color_space->set_transfer_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 13:36:41587 return false;
Johannes Kronc13f4be2018-12-12 08:52:53588 if (!color_space->set_matrix_from_uint8(data[offset++]))
Johannes Kron09d65882018-11-27 13:36:41589 return false;
Johannes Kronc13f4be2018-12-12 08:52:53590
591 uint8_t range_and_chroma_siting = data[offset++];
592 if (!color_space->set_range_from_uint8((range_and_chroma_siting >> 4) & 0x03))
593 return false;
594 if (!color_space->set_chroma_siting_horizontal_from_uint8(
595 (range_and_chroma_siting >> 2) & 0x03))
596 return false;
597 if (!color_space->set_chroma_siting_vertical_from_uint8(
598 range_and_chroma_siting & 0x03))
Johannes Kron09d65882018-11-27 13:36:41599 return false;
600
601 // Read HDR metadata if it exists, otherwise clear it.
602 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
603 color_space->set_hdr_metadata(nullptr);
604 } else {
605 HdrMetadata hdr_metadata;
Johannes Kronc13f4be2018-12-12 08:52:53606 offset += ParseHdrMetadata(data.subview(offset), &hdr_metadata);
607 if (!hdr_metadata.Validate())
608 return false;
Johannes Kron09d65882018-11-27 13:36:41609 color_space->set_hdr_metadata(&hdr_metadata);
610 }
611 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 10:12:36612 return true;
613}
614
Johannes Kron09d65882018-11-27 13:36:41615bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
616 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 13:18:53617 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 10:12:36618 size_t offset = 0;
Johannes Kron09d65882018-11-27 13:36:41619 // Write color space information.
Johannes Kronc13f4be2018-12-12 08:52:53620 data[offset++] = static_cast<uint8_t>(color_space.primaries());
621 data[offset++] = static_cast<uint8_t>(color_space.transfer());
622 data[offset++] = static_cast<uint8_t>(color_space.matrix());
623 data[offset++] = CombineRangeAndChromaSiting(
624 color_space.range(), color_space.chroma_siting_horizontal(),
625 color_space.chroma_siting_vertical());
Johannes Kronad1d9f02018-11-09 10:12:36626
Johannes Kron09d65882018-11-27 13:36:41627 // Write HDR metadata if it exists.
628 if (color_space.hdr_metadata()) {
Johannes Kronc13f4be2018-12-12 08:52:53629 offset +=
630 WriteHdrMetadata(data.subview(offset), *color_space.hdr_metadata());
Johannes Kron09d65882018-11-27 13:36:41631 }
632 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 10:12:36633 return true;
634}
635
Johannes Kronc13f4be2018-12-12 08:52:53636// Combines range and chroma siting into one byte with the following bit layout:
637// bits 0-1 Chroma siting vertical.
638// 2-3 Chroma siting horizontal.
639// 4-5 Range.
640// 6-7 Unused.
641uint8_t ColorSpaceExtension::CombineRangeAndChromaSiting(
642 ColorSpace::RangeID range,
643 ColorSpace::ChromaSiting chroma_siting_horizontal,
644 ColorSpace::ChromaSiting chroma_siting_vertical) {
645 RTC_DCHECK_LE(static_cast<uint8_t>(range), 3);
646 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_horizontal), 3);
647 RTC_DCHECK_LE(static_cast<uint8_t>(chroma_siting_vertical), 3);
648 return (static_cast<uint8_t>(range) << 4) |
649 (static_cast<uint8_t>(chroma_siting_horizontal) << 2) |
650 static_cast<uint8_t>(chroma_siting_vertical);
651}
652
653size_t ColorSpaceExtension::ParseHdrMetadata(rtc::ArrayView<const uint8_t> data,
654 HdrMetadata* hdr_metadata) {
655 RTC_DCHECK_EQ(data.size(),
656 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
657 size_t offset = 0;
658 offset += ParseLuminance(data.data() + offset,
659 &hdr_metadata->mastering_metadata.luminance_max,
660 kLuminanceMaxDenominator);
661 offset += ParseLuminance(data.data() + offset,
662 &hdr_metadata->mastering_metadata.luminance_min,
663 kLuminanceMinDenominator);
664 offset += ParseChromaticity(data.data() + offset,
665 &hdr_metadata->mastering_metadata.primary_r);
666 offset += ParseChromaticity(data.data() + offset,
667 &hdr_metadata->mastering_metadata.primary_g);
668 offset += ParseChromaticity(data.data() + offset,
669 &hdr_metadata->mastering_metadata.primary_b);
670 offset += ParseChromaticity(data.data() + offset,
671 &hdr_metadata->mastering_metadata.white_point);
672 hdr_metadata->max_content_light_level =
673 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
674 offset += 2;
675 hdr_metadata->max_frame_average_light_level =
676 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
677 offset += 2;
678 return offset;
679}
680
Johannes Kron09d65882018-11-27 13:36:41681size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 10:12:36682 const uint8_t* data,
683 HdrMasteringMetadata::Chromaticity* p) {
684 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
685 uint16_t chromaticity_y_scaled =
686 ByteReader<uint16_t>::ReadBigEndian(data + 2);
687 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
688 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
689 return 4; // Return number of bytes read.
690}
691
Johannes Kron09d65882018-11-27 13:36:41692size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
693 float* f,
694 int denominator) {
Johannes Kronc13f4be2018-12-12 08:52:53695 uint16_t luminance_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
Johannes Kronad1d9f02018-11-09 10:12:36696 *f = static_cast<float>(luminance_scaled) / denominator;
Johannes Kronc13f4be2018-12-12 08:52:53697 return 2; // Return number of bytes read.
698}
699
700size_t ColorSpaceExtension::WriteHdrMetadata(rtc::ArrayView<uint8_t> data,
701 const HdrMetadata& hdr_metadata) {
702 RTC_DCHECK_EQ(data.size(),
703 kValueSizeBytes - kValueSizeBytesWithoutHdrMetadata);
704 RTC_DCHECK(hdr_metadata.Validate());
705 size_t offset = 0;
706 offset += WriteLuminance(data.data() + offset,
707 hdr_metadata.mastering_metadata.luminance_max,
708 kLuminanceMaxDenominator);
709 offset += WriteLuminance(data.data() + offset,
710 hdr_metadata.mastering_metadata.luminance_min,
711 kLuminanceMinDenominator);
712 offset += WriteChromaticity(data.data() + offset,
713 hdr_metadata.mastering_metadata.primary_r);
714 offset += WriteChromaticity(data.data() + offset,
715 hdr_metadata.mastering_metadata.primary_g);
716 offset += WriteChromaticity(data.data() + offset,
717 hdr_metadata.mastering_metadata.primary_b);
718 offset += WriteChromaticity(data.data() + offset,
719 hdr_metadata.mastering_metadata.white_point);
720
721 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
722 hdr_metadata.max_content_light_level);
723 offset += 2;
724 ByteWriter<uint16_t>::WriteBigEndian(
725 data.data() + offset, hdr_metadata.max_frame_average_light_level);
726 offset += 2;
727 return offset;
Johannes Kronad1d9f02018-11-09 10:12:36728}
729
Johannes Kron09d65882018-11-27 13:36:41730size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 10:12:36731 uint8_t* data,
732 const HdrMasteringMetadata::Chromaticity& p) {
733 RTC_DCHECK_GE(p.x, 0.0f);
Johannes Kronc13f4be2018-12-12 08:52:53734 RTC_DCHECK_LE(p.x, 1.0f);
Johannes Kronad1d9f02018-11-09 10:12:36735 RTC_DCHECK_GE(p.y, 0.0f);
Johannes Kronc13f4be2018-12-12 08:52:53736 RTC_DCHECK_LE(p.y, 1.0f);
Johannes Kronad1d9f02018-11-09 10:12:36737 ByteWriter<uint16_t>::WriteBigEndian(
738 data, std::round(p.x * kChromaticityDenominator));
739 ByteWriter<uint16_t>::WriteBigEndian(
740 data + 2, std::round(p.y * kChromaticityDenominator));
741 return 4; // Return number of bytes written.
742}
743
Johannes Kron09d65882018-11-27 13:36:41744size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
745 float f,
746 int denominator) {
Johannes Kronad1d9f02018-11-09 10:12:36747 RTC_DCHECK_GE(f, 0.0f);
Johannes Kronc13f4be2018-12-12 08:52:53748 float upscaled_value = f * denominator;
749 RTC_DCHECK_LE(upscaled_value, std::numeric_limits<uint16_t>::max());
750 ByteWriter<uint16_t>::WriteBigEndian(data, std::round(upscaled_value));
751 return 2; // Return number of bytes written.
Johannes Kronad1d9f02018-11-09 10:12:36752}
753
Steve Antona3251dd2017-07-21 16:58:31754bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
Steve Antona3251dd2017-07-21 16:58:31755 std::string* str) {
756 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
757 return false;
758 const char* cstr = reinterpret_cast<const char*>(data.data());
Artem Titov913cfa72021-07-28 21:57:33759 // If there is a \0 character in the middle of the `data`, treat it as end
Steve Antona3251dd2017-07-21 16:58:31760 // of the string. Well-formed string extensions shouldn't contain it.
761 str->assign(cstr, strnlen(cstr, data.size()));
762 RTC_DCHECK(!str->empty());
763 return true;
764}
765
Danil Chapovalov9bf31582018-06-18 11:48:20766bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
Ali Tofighd14e8892022-05-13 09:42:16767 absl::string_view str) {
Niels Möllerd57efc12019-03-22 13:02:11768 if (str.size() > kMaxValueSizeBytes) {
Johannes Kron78cdde32018-10-05 08:00:46769 return false;
770 }
Danil Chapovalov9bf31582018-06-18 11:48:20771 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 16:58:31772 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 11:48:20773 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 16:58:31774 return true;
775}
776
Minyue Licae27792019-11-29 15:18:59777// An RTP Header Extension for Inband Comfort Noise
778//
779// The form of the audio level extension block:
780//
781// 0 1
782// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
783// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
784// | ID | len=0 |N| level |
785// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
786// Sample Audio Level Encoding Using the One-Byte Header Format
787//
788// 0 1 2
789// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
790// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
791// | ID | len=1 |N| level |
792// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
793// Sample Audio Level Encoding Using the Two-Byte Header Format
Minyue Licae27792019-11-29 15:18:59794bool InbandComfortNoiseExtension::Parse(rtc::ArrayView<const uint8_t> data,
795 absl::optional<uint8_t>* level) {
796 if (data.size() != kValueSizeBytes)
797 return false;
798 *level = (data[0] & 0b1000'0000) != 0
799 ? absl::nullopt
800 : absl::make_optional(data[0] & 0b0111'1111);
801 return true;
802}
803
804bool InbandComfortNoiseExtension::Write(rtc::ArrayView<uint8_t> data,
805 absl::optional<uint8_t> level) {
806 RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
807 data[0] = 0b0000'0000;
808 if (level) {
809 if (*level > 127) {
810 return false;
811 }
812 data[0] = 0b1000'0000 | *level;
813 }
814 return true;
815}
816
Jeremy Leconte4f88a9d2021-03-17 16:01:31817// VideoFrameTrackingIdExtension
818//
819// 0 1 2
820// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
821// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
822// | ID | L=1 | video-frame-tracking-id |
823// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Jeremy Leconte4f88a9d2021-03-17 16:01:31824bool VideoFrameTrackingIdExtension::Parse(rtc::ArrayView<const uint8_t> data,
825 uint16_t* video_frame_tracking_id) {
826 if (data.size() != kValueSizeBytes) {
827 return false;
828 }
829 *video_frame_tracking_id = ByteReader<uint16_t>::ReadBigEndian(data.data());
830 return true;
831}
832
833bool VideoFrameTrackingIdExtension::Write(rtc::ArrayView<uint8_t> data,
834 uint16_t video_frame_tracking_id) {
835 RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
836 ByteWriter<uint16_t>::WriteBigEndian(data.data(), video_frame_tracking_id);
837 return true;
838}
839
danilchap1edb7ab2016-04-20 12:25:10840} // namespace webrtc