blob: 082e0e0d6112fe6d26581d93c78e45e395a07041 [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>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/rtp_rtcp/include/rtp_cvo.h"
16#include "modules/rtp_rtcp/source/byte_io.h"
Yves Gerey988cc082018-10-23 12:03:01 +020017// TODO(bug:9855) Move kNoSpatialIdx from vp9_globals.h to common_constants
18#include "modules/video_coding/codecs/interface/common_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
danilchap1edb7ab2016-04-20 05:25:10 -070020
21namespace webrtc {
22// Absolute send time in RTP streams.
23//
24// The absolute send time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020025// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070026// of this extension (the transmitted value) is a 24-bit unsigned integer
27// containing the sender's current time in seconds as a fixed point number
28// with 18 bits fractional part.
29//
30// The form of the absolute send time extension block:
31//
32// 0 1 2 3
33// 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
34// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35// | ID | len=2 | absolute send time |
36// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070037constexpr RTPExtensionType AbsoluteSendTime::kId;
38constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070039constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070040
danilchap978504e2017-04-06 01:03:53 -070041bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
42 uint32_t* time_24bits) {
43 if (data.size() != 3)
44 return false;
45 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -070046 return true;
47}
48
Danil Chapovalov9bf31582018-06-18 13:48:20 +020049bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
50 uint32_t time_24bits) {
51 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020052 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020053 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070054 return true;
55}
56
57// An RTP Header Extension for Client-to-Mixer Audio Level Indication
58//
59// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
60//
61// The form of the audio level extension block:
62//
63// 0 1
64// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
65// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66// | ID | len=0 |V| level |
67// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68//
danilchape2a01772016-10-28 07:08:58 -070069constexpr RTPExtensionType AudioLevel::kId;
70constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070071constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070072
danilchap978504e2017-04-06 01:03:53 -070073bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070074 bool* voice_activity,
75 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -070076 if (data.size() != 1)
77 return false;
danilchap1edb7ab2016-04-20 05:25:10 -070078 *voice_activity = (data[0] & 0x80) != 0;
79 *audio_level = data[0] & 0x7F;
80 return true;
81}
82
Danil Chapovalov9bf31582018-06-18 13:48:20 +020083bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070084 bool voice_activity,
85 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +020086 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -070087 RTC_CHECK_LE(audio_level, 0x7f);
88 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
89 return true;
90}
91
92// From RFC 5450: Transmission Time Offsets in RTP Streams.
93//
94// The transmission time is signaled to the receiver in-band using the
Johannes Kron07ba2b92018-09-26 13:33:35 +020095// general mechanism for RTP header extensions [RFC8285]. The payload
danilchap1edb7ab2016-04-20 05:25:10 -070096// of this extension (the transmitted value) is a 24-bit signed integer.
97// When added to the RTP timestamp of the packet, it represents the
98// "effective" RTP transmission time of the packet, on the RTP
99// timescale.
100//
101// The form of the transmission offset extension block:
102//
103// 0 1 2 3
104// 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
105// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106// | ID | len=2 | transmission offset |
107// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700108constexpr RTPExtensionType TransmissionOffset::kId;
109constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700110constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700111
danilchap978504e2017-04-06 01:03:53 -0700112bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
113 int32_t* rtp_time) {
114 if (data.size() != 3)
115 return false;
116 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700117 return true;
118}
119
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200120bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
121 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200122 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200123 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700124 return true;
125}
126
127// 0 1 2
128// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
129// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130// | ID | L=1 |transport wide sequence number |
131// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700132constexpr RTPExtensionType TransportSequenceNumber::kId;
133constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700134constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700135
danilchap978504e2017-04-06 01:03:53 -0700136bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
137 uint16_t* value) {
138 if (data.size() != 2)
139 return false;
140 *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700141 return true;
142}
143
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200144bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
145 uint16_t value) {
146 RTC_DCHECK_EQ(data.size(), 2);
147 ByteWriter<uint16_t>::WriteBigEndian(data.data(), value);
danilchap1edb7ab2016-04-20 05:25:10 -0700148 return true;
149}
150
151// Coordination of Video Orientation in RTP streams.
152//
153// Coordination of Video Orientation consists in signaling of the current
154// orientation of the image captured on the sender side to the receiver for
155// appropriate rendering and displaying.
156//
157// 0 1
158// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
159// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160// | ID | len=0 |0 0 0 0 C F R R|
161// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700162constexpr RTPExtensionType VideoOrientation::kId;
163constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700164constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700165
danilchap978504e2017-04-06 01:03:53 -0700166bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
167 VideoRotation* rotation) {
168 if (data.size() != 1)
169 return false;
magjed71eb61c2016-09-08 03:24:58 -0700170 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700171 return true;
172}
173
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200174bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
175 VideoRotation rotation) {
176 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700177 data[0] = ConvertVideoRotationToCVOByte(rotation);
178 return true;
179}
180
danilchap978504e2017-04-06 01:03:53 -0700181bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
182 uint8_t* value) {
183 if (data.size() != 1)
184 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700185 *value = data[0];
186 return true;
187}
188
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200189bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
190 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700191 data[0] = value;
192 return true;
193}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200194
195// 0 1 2 3
196// 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
197// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198// | ID | len=2 | MIN delay | MAX delay |
199// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200constexpr RTPExtensionType PlayoutDelayLimits::kId;
201constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700202constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200203
danilchap978504e2017-04-06 01:03:53 -0700204bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200205 PlayoutDelay* playout_delay) {
206 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700207 if (data.size() != 3)
208 return false;
209 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200210 uint16_t min_raw = (raw >> 12);
211 uint16_t max_raw = (raw & 0xfff);
212 if (min_raw > max_raw)
213 return false;
214 playout_delay->min_ms = min_raw * kGranularityMs;
215 playout_delay->max_ms = max_raw * kGranularityMs;
216 return true;
217}
218
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200219bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200220 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200221 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200222 RTC_DCHECK_LE(0, playout_delay.min_ms);
223 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
224 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
225 // Convert MS to value to be sent on extension header.
226 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
227 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200228 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
229 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200230 return true;
231}
232
ilnik00d802b2017-04-11 10:34:31 -0700233// Video Content Type.
234//
235// E.g. default video or screenshare.
236//
237// 0 1
238// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
239// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240// | ID | len=0 | Content type |
241// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
242constexpr RTPExtensionType VideoContentTypeExtension::kId;
243constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700244constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700245
246bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
247 VideoContentType* content_type) {
248 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700249 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700250 *content_type = static_cast<VideoContentType>(data[0]);
251 return true;
252 }
253 return false;
254}
255
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200256bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700257 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200258 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700259 data[0] = static_cast<uint8_t>(content_type);
260 return true;
261}
262
ilnik04f4d122017-06-19 07:18:55 -0700263// Video Timing.
264// 6 timestamps in milliseconds counted from capture time stored in rtp header:
265// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700266// modification by the network modification. |flags| is a bitmask and has the
267// following allowed values:
268// 0 = Valid data, but no flags available (backwards compatibility)
269// 1 = Frame marked as timing frame due to cyclic timer.
270// 2 = Frame marked as timing frame due to size being outside limit.
271// 255 = Invalid. The whole timing frame extension should be ignored.
272//
ilnik04f4d122017-06-19 07:18:55 -0700273// 0 1 2 3
274// 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 2
275// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700276// | ID | len=12| flags | encode start ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700277// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700278// | encode finish ms delta | packetizer finish ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700279// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700280// | pacer exit ms delta | network timestamp ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700281// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700282// | network2 timestamp ms delta |
283// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700284
285constexpr RTPExtensionType VideoTimingExtension::kId;
286constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700287constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700288
289bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700290 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700291 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700292 // TODO(sprang): Deprecate support for old wire format.
293 ptrdiff_t off = 0;
294 switch (data.size()) {
295 case kValueSizeBytes - 1:
296 timing->flags = 0;
297 off = 1; // Old wire format without the flags field.
298 break;
299 case kValueSizeBytes:
300 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
301 break;
302 default:
303 return false;
304 }
305
306 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
307 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700308 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700309 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700310 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700311 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700312 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700313 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100314 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700315 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100316 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700317 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700318 return true;
319}
320
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200321bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
322 const VideoSendTiming& timing) {
323 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
324 ByteWriter<uint8_t>::WriteBigEndian(
325 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700326 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200327 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700328 timing.encode_start_delta_ms);
329 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200330 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700331 timing.encode_finish_delta_ms);
332 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200333 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700334 timing.packetization_finish_delta_ms);
335 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200336 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700337 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700338 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200339 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100340 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700341 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200342 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100343 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700344 return true;
345}
346
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200347bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700348 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700349 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200350 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100351 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200352 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700353 return true;
354}
355
Johnny Leee0c8b232018-09-11 16:50:49 -0400356// Frame Marking.
357//
358// Meta-information about an RTP stream outside the encrypted media payload,
359// useful for an RTP switch to do codec-agnostic selective forwarding
360// without decrypting the payload.
361//
362// For non-scalable streams:
363// 0 1
364// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
365// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366// | ID | L = 0 |S|E|I|D|0 0 0 0|
367// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368//
369// For scalable streams:
370// 0 1 2 3
371// 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
372// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
373// | ID | L = 2 |S|E|I|D|B| TID | LID | TL0PICIDX |
374// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375
376constexpr RTPExtensionType FrameMarkingExtension::kId;
377constexpr const char FrameMarkingExtension::kUri[];
378
379bool FrameMarkingExtension::IsScalable(uint8_t temporal_id, uint8_t layer_id) {
380 return temporal_id != kNoTemporalIdx || layer_id != kNoSpatialIdx;
381}
382
383bool FrameMarkingExtension::Parse(rtc::ArrayView<const uint8_t> data,
384 FrameMarking* frame_marking) {
385 RTC_DCHECK(frame_marking);
386
387 if (data.size() != 1 && data.size() != 3)
388 return false;
389
390 frame_marking->start_of_frame = (data[0] & 0x80) != 0;
391 frame_marking->end_of_frame = (data[0] & 0x40) != 0;
392 frame_marking->independent_frame = (data[0] & 0x20) != 0;
393 frame_marking->discardable_frame = (data[0] & 0x10) != 0;
394
395 if (data.size() == 3) {
396 frame_marking->base_layer_sync = (data[0] & 0x08) != 0;
397 frame_marking->temporal_id = data[0] & 0x7;
398 frame_marking->layer_id = data[1];
399 frame_marking->tl0_pic_idx = data[2];
400 } else {
401 // non-scalable
402 frame_marking->base_layer_sync = false;
403 frame_marking->temporal_id = kNoTemporalIdx;
404 frame_marking->layer_id = kNoSpatialIdx;
405 frame_marking->tl0_pic_idx = 0;
406 }
407 return true;
408}
409
410size_t FrameMarkingExtension::ValueSize(const FrameMarking& frame_marking) {
411 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id))
412 return 3;
413 else
414 return 1;
415}
416
417bool FrameMarkingExtension::Write(rtc::ArrayView<uint8_t> data,
418 const FrameMarking& frame_marking) {
419 RTC_DCHECK_GE(data.size(), 1);
420 RTC_CHECK_LE(frame_marking.temporal_id, 0x07);
421 data[0] = frame_marking.start_of_frame ? 0x80 : 0x00;
422 data[0] |= frame_marking.end_of_frame ? 0x40 : 0x00;
423 data[0] |= frame_marking.independent_frame ? 0x20 : 0x00;
424 data[0] |= frame_marking.discardable_frame ? 0x10 : 0x00;
425
426 if (IsScalable(frame_marking.temporal_id, frame_marking.layer_id)) {
427 RTC_DCHECK_EQ(data.size(), 3);
428 data[0] |= frame_marking.base_layer_sync ? 0x08 : 0x00;
429 data[0] |= frame_marking.temporal_id & 0x07;
430 data[1] = frame_marking.layer_id;
431 data[2] = frame_marking.tl0_pic_idx;
432 }
433 return true;
434}
435
Steve Antona3251dd2017-07-21 09:58:31 -0700436bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
437 StringRtpHeaderExtension* str) {
438 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
439 return false;
440 str->Set(data);
441 RTC_DCHECK(!str->empty());
442 return true;
443}
444
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200445bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700446 const StringRtpHeaderExtension& str) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200447 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700448 RTC_DCHECK_GE(str.size(), 1);
449 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200450 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700451 return true;
452}
453
454bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
455 std::string* str) {
456 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
457 return false;
458 const char* cstr = reinterpret_cast<const char*>(data.data());
459 // If there is a \0 character in the middle of the |data|, treat it as end
460 // of the string. Well-formed string extensions shouldn't contain it.
461 str->assign(cstr, strnlen(cstr, data.size()));
462 RTC_DCHECK(!str->empty());
463 return true;
464}
465
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200466bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
467 const std::string& str) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200468 if (str.size() > StringRtpHeaderExtension::kMaxSize) {
469 return false;
470 }
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200471 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700472 RTC_DCHECK_GE(str.size(), 1);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200473 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700474 return true;
475}
476
477// Constant declarations for string RTP header extension types.
478
danilchapef8d7732017-04-19 02:59:48 -0700479constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700480constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700481
danilchapef8d7732017-04-19 02:59:48 -0700482constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700483constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700484
Steve Antona3251dd2017-07-21 09:58:31 -0700485constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700486constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700487
danilchap1edb7ab2016-04-20 05:25:10 -0700488} // namespace webrtc