blob: 171109237b2c2635cfb60e41e47dbd1d07b8f14d [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>
Yves Gerey988cc082018-10-23 12:03:01 +020015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/rtp_rtcp/include/rtp_cvo.h"
17#include "modules/rtp_rtcp/source/byte_io.h"
Yves Gerey988cc082018-10-23 12:03:01 +020018// TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
19#include "modules/video_coding/codecs/interface/common_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070021
22namespace webrtc {
23// Absolute send time in RTP streams.
24//
25// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020026// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070027// of this extension (the transmitted value) is a 24-bit unsigned integer
28// containing the sender's current time in seconds as a fixed point number
29// with 18 bits fractional part.
30//
31// The form of the absolute send time extension block:
32//
33// 0 1 2 3
34// 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
35// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36// | ID | len=2 | absolute send time |
37// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070038constexpr RTPExtensionType AbsoluteSendTime::kId;
39constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070040constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070041
danilchap978504e2017-04-06 01:03:53 -070042bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
43 uint32_t* time_24bits) {
44 if (data.size() != 3)
45 return false;
46 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -070047 return true;
48}
49
Danil Chapovalov9bf31582018-06-18 13:48:20 +020050bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
51 uint32_t time_24bits) {
52 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020053 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020054 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070055 return true;
56}
57
58// An RTP Header Extension for Client-to-Mixer Audio Level Indication
59//
60// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
61//
62// The form of the audio level extension block:
63//
64// 0 1
65// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
66// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67// | ID | len=0 |V| level |
68// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69//
danilchape2a01772016-10-28 07:08:58 -070070constexpr RTPExtensionType AudioLevel::kId;
71constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070072constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070073
danilchap978504e2017-04-06 01:03:53 -070074bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070075 bool* voice_activity,
76 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -070077 if (data.size() != 1)
78 return false;
danilchap1edb7ab2016-04-20 05:25:10 -070079 *voice_activity = (data[0] & 0x80) != 0;
80 *audio_level = data[0] & 0x7F;
81 return true;
82}
83
Danil Chapovalov9bf31582018-06-18 13:48:20 +020084bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070085 bool voice_activity,
86 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +020087 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -070088 RTC_CHECK_LE(audio_level, 0x7f);
89 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
90 return true;
91}
92
93// From RFC 5450: Transmission Time Offsets in RTP Streams.
94//
95// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020096// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070097// of this extension (the transmitted value) is a 24-bit signed integer.
98// When added to the RTP timestamp of the packet, it represents the
99// "effective" RTP transmission time of the packet, on the RTP
100// timescale.
101//
102// The form of the transmission offset extension block:
103//
104// 0 1 2 3
105// 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
106// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107// | ID | len=2 | transmission offset |
108// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700109constexpr RTPExtensionType TransmissionOffset::kId;
110constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700111constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700112
danilchap978504e2017-04-06 01:03:53 -0700113bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
114 int32_t* rtp_time) {
115 if (data.size() != 3)
116 return false;
117 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700118 return true;
119}
120
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200121bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
122 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200123 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200124 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700125 return true;
126}
127
128// 0 1 2
129// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
130// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131// | ID | L=1 |transport wide sequence number |
132// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700133constexpr RTPExtensionType TransportSequenceNumber::kId;
134constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700135constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700136
danilchap978504e2017-04-06 01:03:53 -0700137bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
138 uint16_t* value) {
139 if (data.size() != 2)
140 return false;
141 *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700142 return true;
143}
144
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200145bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
146 uint16_t value) {
147 RTC_DCHECK_EQ(data.size(), 2);
148 ByteWriter<uint16_t>::WriteBigEndian(data.data(), value);
danilchap1edb7ab2016-04-20 05:25:10 -0700149 return true;
150}
151
152// Coordination of Video Orientation in RTP streams.
153//
154// Coordination of Video Orientation consists in signaling of the current
155// orientation of the image captured on the sender side to the receiver for
156// appropriate rendering and displaying.
157//
158// 0 1
159// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
160// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161// | ID | len=0 |0 0 0 0 C F R R|
162// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700163constexpr RTPExtensionType VideoOrientation::kId;
164constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700165constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700166
danilchap978504e2017-04-06 01:03:53 -0700167bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
168 VideoRotation* rotation) {
169 if (data.size() != 1)
170 return false;
magjed71eb61c2016-09-08 03:24:58 -0700171 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700172 return true;
173}
174
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200175bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
176 VideoRotation rotation) {
177 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700178 data[0] = ConvertVideoRotationToCVOByte(rotation);
179 return true;
180}
181
danilchap978504e2017-04-06 01:03:53 -0700182bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
183 uint8_t* value) {
184 if (data.size() != 1)
185 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700186 *value = data[0];
187 return true;
188}
189
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200190bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
191 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700192 data[0] = value;
193 return true;
194}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200195
196// 0 1 2 3
197// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
198// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
199// | ID | len=2 | MIN delay | MAX delay |
200// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201constexpr RTPExtensionType PlayoutDelayLimits::kId;
202constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700203constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200204
danilchap978504e2017-04-06 01:03:53 -0700205bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200206 PlayoutDelay* playout_delay) {
207 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700208 if (data.size() != 3)
209 return false;
210 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200211 uint16_t min_raw = (raw >> 12);
212 uint16_t max_raw = (raw & 0xfff);
213 if (min_raw > max_raw)
214 return false;
215 playout_delay->min_ms = min_raw * kGranularityMs;
216 playout_delay->max_ms = max_raw * kGranularityMs;
217 return true;
218}
219
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200220bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200221 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200222 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200223 RTC_DCHECK_LE(0, playout_delay.min_ms);
224 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
225 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
226 // Convert MS to value to be sent on extension header.
227 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
228 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200229 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
230 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200231 return true;
232}
233
ilnik00d802b2017-04-11 10:34:31 -0700234// Video Content Type.
235//
236// E.g. default video or screenshare.
237//
238// 0 1
239// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
240// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241// | ID | len=0 | Content type |
242// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243constexpr RTPExtensionType VideoContentTypeExtension::kId;
244constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700245constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700246
247bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
248 VideoContentType* content_type) {
249 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700250 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700251 *content_type = static_cast<VideoContentType>(data[0]);
252 return true;
253 }
254 return false;
255}
256
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200257bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700258 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200259 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700260 data[0] = static_cast<uint8_t>(content_type);
261 return true;
262}
263
ilnik04f4d122017-06-19 07:18:55 -0700264// Video Timing.
265// 6 timestamps in milliseconds counted from capture time stored in rtp header:
266// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700267// modification by the network modification. |flags| is a bitmask and has the
268// following allowed values:
269// 0 = Valid data, but no flags available (backwards compatibility)
270// 1 = Frame marked as timing frame due to cyclic timer.
271// 2 = Frame marked as timing frame due to size being outside limit.
272// 255 = Invalid. The whole timing frame extension should be ignored.
273//
ilnik04f4d122017-06-19 07:18:55 -0700274// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100275// 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
276// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277// | ID | len=12| flags | encode start ms delta |
278// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279// | encode finish ms delta | packetizer finish ms delta |
280// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281// | pacer exit ms delta | network timestamp ms delta |
282// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700283// | network2 timestamp ms delta |
284// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700285
286constexpr RTPExtensionType VideoTimingExtension::kId;
287constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700288constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700289
290bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700291 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700292 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700293 // TODO(sprang): Deprecate support for old wire format.
294 ptrdiff_t off = 0;
295 switch (data.size()) {
296 case kValueSizeBytes - 1:
297 timing->flags = 0;
298 off = 1; // Old wire format without the flags field.
299 break;
300 case kValueSizeBytes:
301 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
302 break;
303 default:
304 return false;
305 }
306
307 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
308 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700309 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700310 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700311 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700312 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700313 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700314 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100315 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700316 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100317 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700318 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700319 return true;
320}
321
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200322bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
323 const VideoSendTiming& timing) {
324 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
325 ByteWriter<uint8_t>::WriteBigEndian(
326 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700327 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200328 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700329 timing.encode_start_delta_ms);
330 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200331 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700332 timing.encode_finish_delta_ms);
333 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200334 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700335 timing.packetization_finish_delta_ms);
336 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200337 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700338 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700339 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200340 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100341 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700342 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200343 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100344 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700345 return true;
346}
347
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200348bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700349 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700350 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200351 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100352 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200353 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700354 return true;
355}
356
Johnny Leee0c8b232018-09-11 16:50:49 -0400357// Frame Marking.
358//
359// Meta-information about an RTP stream outside the encrypted media payload,
360// useful for an RTP switch to do codec-agnostic selective forwarding
361// without decrypting the payload.
362//
363// For non-scalable streams:
364// 0 1
365// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
366// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367// | ID | L = 0 |S|E|I|D|0 0 0 0|
368// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
369//
370// For scalable streams:
371// 0 1 2 3
372// 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
373// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374// | ID | L = 2 |S|E|I|D|B| TID | LID | TL0PICIDX |
375// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376
377constexpr RTPExtensionType FrameMarkingExtension::kId;
378constexpr const char FrameMarkingExtension::kUri[];
379
380bool FrameMarkingExtension::IsScalable(uint8_t temporal_id, uint8_t layer_id) {
381 return temporal_id != kNoTemporalIdx || layer_id != kNoSpatialIdx;
382}
383
384bool FrameMarkingExtension::Parse(rtc::ArrayView<const uint8_t> data,
385 FrameMarking* frame_marking) {
386 RTC_DCHECK(frame_marking);
387
388 if (data.size() != 1 && data.size() != 3)
389 return false;
390
391 frame_marking->start_of_frame = (data[0] & 0x80) != 0;
392 frame_marking->end_of_frame = (data[0] & 0x40) != 0;
393 frame_marking->independent_frame = (data[0] & 0x20) != 0;
394 frame_marking->discardable_frame = (data[0] & 0x10) != 0;
395
396 if (data.size() == 3) {
397 frame_marking->base_layer_sync = (data[0] & 0x08) != 0;
398 frame_marking->temporal_id = data[0] & 0x7;
399 frame_marking->layer_id = data[1];
400 frame_marking->tl0_pic_idx = data[2];
401 } else {
402 // non-scalable
403 frame_marking->base_layer_sync = false;
404 frame_marking->temporal_id = kNoTemporalIdx;
405 frame_marking->layer_id = kNoSpatialIdx;
406 frame_marking->tl0_pic_idx = 0;
407 }
408 return true;
409}
410
411size_t FrameMarkingExtension::ValueSize(const FrameMarking& frame_marking) {
412 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id))
413 return 3;
414 else
415 return 1;
416}
417
418bool FrameMarkingExtension::Write(rtc::ArrayView<uint8_t> data,
419 const FrameMarking& frame_marking) {
420 RTC_DCHECK_GE(data.size(), 1);
421 RTC_CHECK_LE(frame_marking.temporal_id, 0x07);
422 data[0] = frame_marking.start_of_frame ? 0x80 : 0x00;
423 data[0] |= frame_marking.end_of_frame ? 0x40 : 0x00;
424 data[0] |= frame_marking.independent_frame ? 0x20 : 0x00;
425 data[0] |= frame_marking.discardable_frame ? 0x10 : 0x00;
426
427 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id)) {
428 RTC_DCHECK_EQ(data.size(), 3);
429 data[0] |= frame_marking.base_layer_sync ? 0x08 : 0x00;
430 data[0] |= frame_marking.temporal_id & 0x07;
431 data[1] = frame_marking.layer_id;
432 data[2] = frame_marking.tl0_pic_idx;
433 }
434 return true;
435}
436
Johannes Kron09d65882018-11-27 14:36:41 +0100437// Color space including HDR metadata as an optional field.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100438//
Johannes Krond0b69a82018-12-03 14:18:53 +0100439// RTP header extension to carry color space information and optionally HDR
440// metadata. The float values in the HDR metadata struct are upscaled by a
441// static factor and transmitted as unsigned integers.
Johannes Kronad1d9f02018-11-09 11:12:36 +0100442//
Johannes Krond0b69a82018-12-03 14:18:53 +0100443// Data layout of color space with HDR metadata (two-byte RTP header extension)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100444// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100445// 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
446// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
447// | ID | length=30 | Primaries | Transfer |
448// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
449// | Matrix | Range | luminance_max |
450// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
451// | | luminance_min |
452// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453// | mastering_metadata.primary_r.x and .y |
454// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
455// | mastering_metadata.primary_g.x and .y |
456// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
457// | mastering_metadata.primary_b.x and .y |
458// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
459// | mastering_metadata.white.x and .y |
460// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
461// | max_content_light_level | max_frame_average_light_level |
462// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Johannes Kron09d65882018-11-27 14:36:41 +0100463//
Johannes Krond0b69a82018-12-03 14:18:53 +0100464// Data layout of color space w/o HDR metadata (one-byte RTP header extension)
Johannes Kron09d65882018-11-27 14:36:41 +0100465// 0 1 2 3
Johannes Krond0b69a82018-12-03 14:18:53 +0100466// 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
467// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468// | ID | L = 3 | Primaries | Transfer | Matrix |
469// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
470// | Range |
471// +-+-+-+-+-+-+-+-+
Johannes Kronad1d9f02018-11-09 11:12:36 +0100472
Johannes Kron09d65882018-11-27 14:36:41 +0100473constexpr RTPExtensionType ColorSpaceExtension::kId;
474constexpr uint8_t ColorSpaceExtension::kValueSizeBytes;
475constexpr const char ColorSpaceExtension::kUri[];
476
477bool ColorSpaceExtension::Parse(rtc::ArrayView<const uint8_t> data,
478 ColorSpace* color_space) {
479 RTC_DCHECK(color_space);
480 if (data.size() != kValueSizeBytes &&
481 data.size() != kValueSizeBytesWithoutHdrMetadata)
Johannes Kronad1d9f02018-11-09 11:12:36 +0100482 return false;
483
484 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100485 // Read color space information.
486 if (!color_space->set_primaries_from_uint8(data.data()[offset++]))
487 return false;
488 if (!color_space->set_transfer_from_uint8(data.data()[offset++]))
489 return false;
490 if (!color_space->set_matrix_from_uint8(data.data()[offset++]))
491 return false;
492 if (!color_space->set_range_from_uint8(data.data()[offset++]))
493 return false;
494
495 // Read HDR metadata if it exists, otherwise clear it.
496 if (data.size() == kValueSizeBytesWithoutHdrMetadata) {
497 color_space->set_hdr_metadata(nullptr);
498 } else {
499 HdrMetadata hdr_metadata;
500 offset += ParseLuminance(data.data() + offset,
501 &hdr_metadata.mastering_metadata.luminance_max,
502 kLuminanceMaxDenominator);
503 offset += ParseLuminance(data.data() + offset,
504 &hdr_metadata.mastering_metadata.luminance_min,
505 kLuminanceMinDenominator);
506 offset += ParseChromaticity(data.data() + offset,
507 &hdr_metadata.mastering_metadata.primary_r);
508 offset += ParseChromaticity(data.data() + offset,
509 &hdr_metadata.mastering_metadata.primary_g);
510 offset += ParseChromaticity(data.data() + offset,
511 &hdr_metadata.mastering_metadata.primary_b);
512 offset += ParseChromaticity(data.data() + offset,
513 &hdr_metadata.mastering_metadata.white_point);
514 hdr_metadata.max_content_light_level =
515 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
516 offset += 2;
517 hdr_metadata.max_frame_average_light_level =
518 ByteReader<uint16_t>::ReadBigEndian(data.data() + offset);
519 offset += 2;
520 color_space->set_hdr_metadata(&hdr_metadata);
521 }
522 RTC_DCHECK_EQ(ValueSize(*color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100523 return true;
524}
525
Johannes Kron09d65882018-11-27 14:36:41 +0100526bool ColorSpaceExtension::Write(rtc::ArrayView<uint8_t> data,
527 const ColorSpace& color_space) {
Johannes Krond0b69a82018-12-03 14:18:53 +0100528 RTC_DCHECK_EQ(data.size(), ValueSize(color_space));
Johannes Kronad1d9f02018-11-09 11:12:36 +0100529 size_t offset = 0;
Johannes Kron09d65882018-11-27 14:36:41 +0100530 // Write color space information.
531 data.data()[offset++] = static_cast<uint8_t>(color_space.primaries());
532 data.data()[offset++] = static_cast<uint8_t>(color_space.transfer());
533 data.data()[offset++] = static_cast<uint8_t>(color_space.matrix());
534 data.data()[offset++] = static_cast<uint8_t>(color_space.range());
Johannes Kronad1d9f02018-11-09 11:12:36 +0100535
Johannes Kron09d65882018-11-27 14:36:41 +0100536 // Write HDR metadata if it exists.
537 if (color_space.hdr_metadata()) {
538 const HdrMetadata& hdr_metadata = *color_space.hdr_metadata();
539 offset += WriteLuminance(data.data() + offset,
540 hdr_metadata.mastering_metadata.luminance_max,
541 kLuminanceMaxDenominator);
542 offset += WriteLuminance(data.data() + offset,
543 hdr_metadata.mastering_metadata.luminance_min,
544 kLuminanceMinDenominator);
545 offset += WriteChromaticity(data.data() + offset,
546 hdr_metadata.mastering_metadata.primary_r);
547 offset += WriteChromaticity(data.data() + offset,
548 hdr_metadata.mastering_metadata.primary_g);
549 offset += WriteChromaticity(data.data() + offset,
550 hdr_metadata.mastering_metadata.primary_b);
551 offset += WriteChromaticity(data.data() + offset,
552 hdr_metadata.mastering_metadata.white_point);
553
554 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset,
555 hdr_metadata.max_content_light_level);
556 offset += 2;
557 ByteWriter<uint16_t>::WriteBigEndian(
558 data.data() + offset, hdr_metadata.max_frame_average_light_level);
559 offset += 2;
560 }
561 RTC_DCHECK_EQ(ValueSize(color_space), offset);
Johannes Kronad1d9f02018-11-09 11:12:36 +0100562 return true;
563}
564
Johannes Kron09d65882018-11-27 14:36:41 +0100565size_t ColorSpaceExtension::ParseChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100566 const uint8_t* data,
567 HdrMasteringMetadata::Chromaticity* p) {
568 uint16_t chromaticity_x_scaled = ByteReader<uint16_t>::ReadBigEndian(data);
569 uint16_t chromaticity_y_scaled =
570 ByteReader<uint16_t>::ReadBigEndian(data + 2);
571 p->x = static_cast<float>(chromaticity_x_scaled) / kChromaticityDenominator;
572 p->y = static_cast<float>(chromaticity_y_scaled) / kChromaticityDenominator;
573 return 4; // Return number of bytes read.
574}
575
Johannes Kron09d65882018-11-27 14:36:41 +0100576size_t ColorSpaceExtension::ParseLuminance(const uint8_t* data,
577 float* f,
578 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100579 uint32_t luminance_scaled = ByteReader<uint32_t, 3>::ReadBigEndian(data);
580 *f = static_cast<float>(luminance_scaled) / denominator;
581 return 3; // Return number of bytes read.
582}
583
Johannes Kron09d65882018-11-27 14:36:41 +0100584size_t ColorSpaceExtension::WriteChromaticity(
Johannes Kronad1d9f02018-11-09 11:12:36 +0100585 uint8_t* data,
586 const HdrMasteringMetadata::Chromaticity& p) {
587 RTC_DCHECK_GE(p.x, 0.0f);
588 RTC_DCHECK_GE(p.y, 0.0f);
589 ByteWriter<uint16_t>::WriteBigEndian(
590 data, std::round(p.x * kChromaticityDenominator));
591 ByteWriter<uint16_t>::WriteBigEndian(
592 data + 2, std::round(p.y * kChromaticityDenominator));
593 return 4; // Return number of bytes written.
594}
595
Johannes Kron09d65882018-11-27 14:36:41 +0100596size_t ColorSpaceExtension::WriteLuminance(uint8_t* data,
597 float f,
598 int denominator) {
Johannes Kronad1d9f02018-11-09 11:12:36 +0100599 RTC_DCHECK_GE(f, 0.0f);
600 ByteWriter<uint32_t, 3>::WriteBigEndian(data, std::round(f * denominator));
601 return 3; // Return number of bytes written.
602}
603
Steve Antona3251dd2017-07-21 09:58:31 -0700604bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
605 StringRtpHeaderExtension* str) {
606 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
607 return false;
608 str->Set(data);
609 RTC_DCHECK(!str->empty());
610 return true;
611}
612
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200613bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700614 const StringRtpHeaderExtension& str) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200615 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700616 RTC_DCHECK_GE(str.size(), 1);
617 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200618 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700619 return true;
620}
621
622bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
623 std::string* str) {
624 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
625 return false;
626 const char* cstr = reinterpret_cast<const char*>(data.data());
627 // If there is a \0 character in the middle of the |data|, treat it as end
628 // of the string. Well-formed string extensions shouldn't contain it.
629 str->assign(cstr, strnlen(cstr, data.size()));
630 RTC_DCHECK(!str->empty());
631 return true;
632}
633
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200634bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
635 const std::string& str) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200636 if (str.size() > StringRtpHeaderExtension::kMaxSize) {
637 return false;
638 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200639 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700640 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200641 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700642 return true;
643}
644
645// Constant declarations for string RTP header extension types.
646
danilchapef8d7732017-04-19 02:59:48 -0700647constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700648constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700649
danilchapef8d7732017-04-19 02:59:48 -0700650constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700651constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700652
Steve Antona3251dd2017-07-21 09:58:31 -0700653constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700654constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700655
danilchap1edb7ab2016-04-20 05:25:10 -0700656} // namespace webrtc