Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtp_packet.cc

Issue 1841453004: RtpPacket class introduced. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added unittests and fuzzer Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
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
11 #include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
12
13 #include <cstring>
14
15 #include "webrtc/base/checks.h"
16 #include "webrtc/base/logging.h"
17 #include "webrtc/base/random.h"
18 #include "webrtc/common_types.h"
19 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
20 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
21 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
22
23 namespace webrtc {
24 namespace rtp {
25 namespace {
26 const size_t kFixedHeaderSize = 12;
27 const uint8_t kRtpVersion = 2;
28 const uint16_t kOneByteExtensionId = 0xBEDE;
29 const size_t kDefaultPacketSize = 1500;
30 } // namespace
31 // 0 1 2 3
32 // 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
33 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 // |V=2|P|X| CC |M| PT | sequence number |
35 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 // | timestamp |
37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 // | synchronization source (SSRC) identifier |
39 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
40 // | Contributing source (CSRC) identifiers |
41 // | .... |
42 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
43 // |One-byte eXtensions id = 0xbede| length in 32bits |
44 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 // | Extensions |
46 // | .... |
47 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
48 // | Payload |
49 // | .... : padding... |
50 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 // | padding | Padding size |
52 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 Packet::Packet(const ExtensionManager* extensions)
54 : extensions_(extensions), buffer_(kDefaultPacketSize) {
55 Clear();
56 }
57
58 Packet::Packet(const ExtensionManager* extensions, size_t capacity)
59 : extensions_(extensions), buffer_(capacity) {
60 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
61 Clear();
62 }
63
64 Packet::~Packet() {}
65
66 void Packet::IdentifyExtensions(const ExtensionManager* extensions) {
67 RTC_DCHECK(extensions);
68 extensions_ = extensions;
69 for (size_t i = 0; i < num_extensions_; ++i) {
70 uint8_t id = data()[extension_entries_[i].offset - 1] >> 4;
71 extension_entries_[i].type = extensions_->GetType(id);
72 }
73 }
74
75 bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
76 if (!ParseBuffer(buffer, buffer_size)) {
77 Clear();
78 return false;
79 }
80 RTC_DCHECK_EQ(size(), buffer_size);
81 buffer_.SetData(buffer, buffer_size);
82 return true;
83 }
84
85 bool Packet::Parse(rtc::Buffer buffer) {
86 if (!ParseBuffer(buffer.data(), buffer.size())) {
87 Clear();
88 return false;
89 }
90 RTC_DCHECK_EQ(size(), buffer.size());
91 buffer_ = std::move(buffer);
92 return true;
93 }
94
95 bool Packet::Marker() const {
96 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
97 return marker_;
98 }
99
100 uint8_t Packet::PayloadType() const {
101 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
102 return payload_type_;
103 }
104
105 uint16_t Packet::SequenceNumber() const {
106 RTC_DCHECK_EQ(sequence_number_,
107 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
108 return sequence_number_;
109 }
110
111 uint32_t Packet::Timestamp() const {
112 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
113 return timestamp_;
114 }
115
116 uint32_t Packet::Ssrc() const {
117 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
118 return ssrc_;
119 }
120
121 std::vector<uint32_t> Packet::Csrcs() const {
122 size_t num_csrc = data()[0] & 0x0F;
123 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
124 std::vector<uint32_t> csrcs(num_csrc);
125 for (size_t i = 0; i < num_csrc; ++i) {
126 csrcs[i] =
127 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
128 }
129 return csrcs;
130 }
131
132 void Packet::GetHeader(RTPHeader* header) const {
133 header->markerBit = Marker();
134 header->payloadType = PayloadType();
135 header->sequenceNumber = SequenceNumber();
136 header->timestamp = Timestamp();
137 header->ssrc = Ssrc();
138 std::vector<uint32_t> csrcs = Csrcs();
139 header->numCSRCs = csrcs.size();
140 for (size_t i = 0; i < csrcs.size(); ++i) {
141 header->arrOfCSRCs[i] = csrcs[i];
142 }
143 header->paddingLength = padding_size();
144 header->headerLength = headers_size();
145 header->payload_type_frequency = 0;
146 header->extension.hasTransmissionTimeOffset =
147 GetExtension<TransmissionOffset>(
148 &header->extension.transmissionTimeOffset);
149 header->extension.hasAbsoluteSendTime =
150 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
151 header->extension.hasTransportSequenceNumber =
152 GetExtension<TransportSequenceNumber>(
153 &header->extension.transportSequenceNumber);
154 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
155 &header->extension.voiceActivity, &header->extension.audioLevel);
156 header->extension.hasVideoRotation =
157 GetExtension<VideoOrientation>(&header->extension.videoRotation);
158 }
159
160 size_t Packet::headers_size() const {
161 return payload_offset_;
162 }
163
164 size_t Packet::payload_size() const {
165 return payload_size_;
166 }
167
168 size_t Packet::padding_size() const {
169 return padding_size_;
170 }
171
172 const uint8_t* Packet::payload() const {
173 return data() + payload_offset_;
174 }
175
176 size_t Packet::capacity() const {
177 return buffer_.size();
terelius 2016/04/19 14:18:20 Whats the reason for changing to .size() instead o
178 }
179
180 size_t Packet::size() const {
181 return payload_offset_ + payload_size_ + padding_size_;
182 }
183
184 const uint8_t* Packet::data() const {
185 return buffer_.data();
186 }
187
188 size_t Packet::FreeCapacity() const {
189 return capacity() - size();
190 }
191
192 size_t Packet::MaxPayloadSize() const {
193 return capacity() - payload_offset_;
194 }
195
196 void Packet::CopyHeader(const Packet& packet) {
197 RTC_DCHECK_GE(capacity(), packet.headers_size());
198
199 marker_ = packet.marker_;
200 payload_type_ = packet.payload_type_;
201 sequence_number_ = packet.sequence_number_;
202 timestamp_ = packet.timestamp_;
203 ssrc_ = packet.ssrc_;
204 payload_offset_ = packet.payload_offset_;
205 num_extensions_ = packet.num_extensions_;
206 for (size_t i = 0; i < num_extensions_; ++i) {
207 extension_entries_[i] = packet.extension_entries_[i];
208 }
209 extensions_size_ = packet.extensions_size_;
210 buffer_.SetData(packet.data(), packet.headers_size());
211 // Reset payload and padding.
212 payload_size_ = 0;
213 padding_size_ = 0;
214 }
215
216 void Packet::SetMarker(bool marker_bit) {
217 marker_ = marker_bit;
218 if (marker_) {
219 WriteAt(1, data()[1] | 0x80);
220 } else {
221 WriteAt(1, data()[1] & 0x7F);
222 }
223 }
224
225 void Packet::SetPayloadType(uint8_t payload_type) {
226 RTC_DCHECK_LE(payload_type, 0x7Fu);
227 payload_type_ = payload_type;
228 WriteAt(1, (data()[1] & 0x80) | payload_type);
229 }
230
231 void Packet::SetSequenceNumber(uint16_t seq_no) {
232 sequence_number_ = seq_no;
233 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
234 }
235
236 void Packet::SetTimestamp(uint32_t timestamp) {
237 timestamp_ = timestamp;
238 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
239 }
240
241 void Packet::SetSsrc(uint32_t ssrc) {
242 ssrc_ = ssrc;
243 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
244 }
245
246 void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
247 RTC_DCHECK_EQ(num_extensions_, 0u);
248 RTC_DCHECK_EQ(payload_size_, 0u);
249 RTC_DCHECK_EQ(padding_size_, 0u);
250 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
251 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
252 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
253 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
254 size_t offset = kFixedHeaderSize;
255 for (uint32_t csrc : csrcs) {
256 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
257 offset += 4;
258 }
259 }
260
261 uint8_t* Packet::AllocatePayload(size_t size_bytes) {
262 RTC_DCHECK_EQ(padding_size_, 0u);
263 if (payload_offset_ + size_bytes > capacity()) {
264 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
265 return nullptr;
266 }
267 payload_size_ = size_bytes;
268 return WriteAt(payload_offset_);
269 }
270
271 void Packet::SetPayloadSize(size_t size_bytes) {
272 RTC_DCHECK_EQ(padding_size_, 0u);
273 RTC_DCHECK_LE(size_bytes, payload_size_);
274 payload_size_ = size_bytes;
275 }
276
277 bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
278 RTC_DCHECK(random);
279 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
280 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
281 << (capacity() - payload_offset_ - payload_size_)
282 << " bytes left in buffer.";
283 return false;
284 }
285 padding_size_ = size_bytes;
286 if (padding_size_ > 0) {
287 size_t padding_offset = payload_offset_ + payload_size_;
288 size_t padding_end = padding_offset + padding_size_;
289 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
290 WriteAt(offset, random->Rand<uint8_t>());
291 }
292 WriteAt(padding_end - 1, padding_size_);
293 WriteAt(0, data()[0] | 0x20); // Set padding bit.
294 } else {
295 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
296 }
297 return true;
298 }
299
300 void Packet::Clear() {
301 marker_ = false;
302 payload_type_ = 0;
303 sequence_number_ = 0;
304 timestamp_ = 0;
305 ssrc_ = 0;
306 payload_offset_ = kFixedHeaderSize;
307 payload_size_ = 0;
308 padding_size_ = 0;
309 num_extensions_ = 0;
310 extensions_size_ = 0;
311
312 memset(WriteAt(0), 0, kFixedHeaderSize);
313 WriteAt(0, kRtpVersion << 6);
314 }
315
316 bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
317 if (size < kFixedHeaderSize) {
318 return false;
319 }
320 const uint8_t version = buffer[0] >> 6;
321 if (version != kRtpVersion) {
322 return false;
323 }
324 const bool has_padding = (buffer[0] & 0x20) != 0;
325 const bool has_extension = (buffer[0] & 0x10) != 0;
326 const uint8_t number_of_crcs = buffer[0] & 0x0f;
327 marker_ = (buffer[1] & 0x80) != 0;
328 payload_type_ = buffer[1] & 0x7f;
329
330 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
331 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
332 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
333 if (size < kFixedHeaderSize + number_of_crcs * 4) {
334 return false;
335 }
336 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
337
338 if (has_padding) {
339 padding_size_ = buffer[size - 1];
340 if (padding_size_ == 0) {
341 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
342 return false;
343 }
344 } else {
345 padding_size_ = 0;
346 }
347
348 num_extensions_ = 0;
349 extensions_size_ = 0;
350 if (has_extension) {
351 /* RTP header extension, RFC 3550.
352 0 1 2 3
353 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
354 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355 | defined by profile | length |
356 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357 | header extension |
358 | .... |
359 */
360 size_t extension_offset = payload_offset_ + 4;
361 if (extension_offset > size) {
362 return false;
363 }
364 uint16_t profile =
365 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
366 size_t extensions_capacity =
367 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
368 extensions_capacity *= 4;
369 if (extension_offset + extensions_capacity > size) {
370 return false;
371 }
372 if (profile != kOneByteExtensionId) {
373 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
374 } else {
375 const size_t kOneByteHeaderSize = 1;
376 const uint8_t kPaddingId = 0;
377 const uint8_t kReservedId = 15;
378 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
379 uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
380 if (id == kReservedId) {
381 break;
382 } else if (id == kPaddingId) {
383 extensions_size_++;
384 continue;
385 }
386 uint8_t length =
387 1 + (buffer[extension_offset + extensions_size_] & 0xf);
388 extensions_size_ += kOneByteHeaderSize;
389 if (num_extensions_ >= kMaxExtensionHeaders) {
390 LOG(LS_WARNING) << "Too many extensions.";
391 return false;
392 }
393 extension_entries_[num_extensions_].type =
394 extensions_ ? extensions_->GetType(id)
395 : ExtensionManager::kInvalidType;
396 extension_entries_[num_extensions_].length = length;
397 extension_entries_[num_extensions_].offset =
398 extension_offset + extensions_size_;
399 num_extensions_++;
400 extensions_size_ += length;
401 }
402 }
403 payload_offset_ = extension_offset + extensions_capacity;
404 }
405
406 if (payload_offset_ + padding_size_ > size) {
407 return false;
408 }
409 payload_size_ = size - payload_offset_ - padding_size_;
410 return true;
411 }
412
413 bool Packet::FindExtension(ExtensionType type,
414 uint8_t length,
415 uint16_t* offset) const {
416 RTC_DCHECK(offset);
417 for (size_t i = 0; i < num_extensions_; ++i) {
418 if (extension_entries_[i].type == type) {
419 RTC_CHECK_EQ(length, extension_entries_[i].length)
420 << "Length mismatch for extension '" << type << "'"
421 << "should be " << length << ", received "
422 << extension_entries_[i].length;
423 *offset = extension_entries_[i].offset;
424 return true;
425 }
426 }
427 return false;
428 }
429
430 bool Packet::AllocateExtension(ExtensionType type,
431 uint8_t length,
432 uint16_t* offset) {
433 if (!extensions_) {
434 return false;
435 }
436 if (FindExtension(type, length, offset)) {
437 return true;
438 }
439
440 // Can't add new extension after payload/padding was set.
441 if (payload_size_ > 0) {
442 return false;
443 }
444 if (padding_size_ > 0) {
445 return false;
446 }
447
448 uint8_t extension_id = extensions_->GetId(type);
449 if (extension_id == ExtensionManager::kInvalidId) {
450 return false;
451 }
452 RTC_DCHECK_GT(length, 0u);
453 RTC_DCHECK_LE(length, 16u);
454
455 size_t num_csrc = data()[0] & 0x0F;
456 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
457 const uint8_t kExtensionHeaderSize = 1; // Using one-byte extensions only.
458 if (extensions_offset + extensions_size_ + kExtensionHeaderSize + length >
459 capacity()) {
460 LOG(LS_WARNING) << "Extension cannot be registered: "
461 "Not enough space left in buffer.";
462 return false;
463 }
464
465 uint16_t new_extensions_size =
466 extensions_size_ + kExtensionHeaderSize + length;
467 uint16_t extensions_words =
468 (new_extensions_size + 3) / 4; // Wrap up to 32bit.
469 if (extensions_words > 0xFFFF) {
470 LOG(LS_WARNING) << "Too much extension header data, exceeds 2^16 DWORDS.";
471 return false;
472 }
473
474 // All checks passed, write down the extension.
475 if (num_extensions_ == 0) {
476 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
477 RTC_DCHECK_EQ(extensions_size_, 0);
478 WriteAt(0, data()[0] | 0x10); // Set extension bit.
479 // Profile specific ID always set to OneByteExtensionHeader.
480 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
481 kOneByteExtensionId);
482 }
483
484 WriteAt(extensions_offset + extensions_size_,
485 (extension_id << 4) | (length - 1));
486 RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders);
terelius 2016/04/19 14:18:20 Why not use DCHECK_LT here?
487 extension_entries_[num_extensions_].type = type;
488 extension_entries_[num_extensions_].length = length;
489 *offset = extensions_offset + kExtensionHeaderSize + extensions_size_;
490 extension_entries_[num_extensions_].offset = *offset;
491 ++num_extensions_;
492 extensions_size_ = new_extensions_size;
493
494 // Update header length field.
495 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
496 extensions_words);
497 // Fill extension padding place with zeroes.
498 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
499 memset(WriteAt(extensions_offset + extensions_size_), 0,
500 extension_padding_size);
501 payload_offset_ = extensions_offset + 4 * extensions_words;
502 return true;
503 }
504
505 uint8_t* Packet::WriteAt(size_t offset) {
506 return buffer_.data() + offset;
507 }
508
509 void Packet::WriteAt(size_t offset, uint8_t byte) {
510 buffer_.data()[offset] = byte;
511 }
512
513 } // namespace rtp
514 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698