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

Unified 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: Created 4 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/rtp_rtcp/source/rtp_packet.cc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f06750e17553e8c12a0b6eb5dbeb83b5a602e67d
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
+
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/random.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtp {
+namespace {
+const size_t kFixedHeaderSize = 12;
+const uint8_t kRtpVersion = 2;
+const uint16_t kOneByteExtensionId = 0xBEDE;
+const size_t kDefaultPacketSize = 1500;
+} // namespace
+// 0 1 2 3
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P|X| CC |M| PT | sequence number |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | timestamp |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | synchronization source (SSRC) identifier |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// | Contributing source (CSRC) identifiers |
+// | .... |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// |One-byte eXtensions id = 0xbede| length in 32bits |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Extensions |
+// | .... |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// | Payload |
+// | .... : padding... |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | padding | Padding size |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Packet::Packet(const ExtensionManager* extensions)
+ : extensions_(extensions), buffer_(kDefaultPacketSize) {
+ Clear();
+}
+
+Packet::Packet(const ExtensionManager* extensions, size_t capacity)
+ : extensions_(extensions), buffer_(capacity) {
+ RTC_DCHECK_GE(capacity, kFixedHeaderSize);
+ Clear();
+}
+
+Packet::~Packet() {}
+
+bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
+ if (!ParseBuffer(buffer, buffer_size)) {
+ Clear();
+ return false;
+ }
+ RTC_DCHECK_EQ(size(), buffer_size);
+ buffer_.SetData(buffer, buffer_size);
+ return true;
+}
+
+bool Packet::Parse(rtc::Buffer buffer) {
+ if (!ParseBuffer(buffer.data(), buffer.size())) {
+ Clear();
+ return false;
+ }
+ RTC_DCHECK_EQ(size(), buffer.size());
+ buffer_ = std::move(buffer);
+ return true;
+}
+
+bool Packet::Marker() const {
philipel 2016/04/13 12:01:19 Functions with very low cost (if it is reasonable
danilchap 2016/04/13 16:18:33 I'm not sure current implementation would stay. Ma
philipel 2016/04/14 10:32:02 Acknowledged.
+ return marker_;
+}
+
+uint8_t Packet::PayloadType() const {
philipel 2016/04/13 12:01:19 payload_type()
+ return payload_type_;
+}
+
+uint16_t Packet::SequenceNumber() const {
+ return sequence_number_;
philipel 2016/04/13 12:01:18 sequence_number()
+}
+
+uint32_t Packet::Timestamp() const {
philipel 2016/04/13 12:01:18 timestamp()
+ return timestamp_;
+}
+
+uint32_t Packet::Ssrc() const {
philipel 2016/04/13 12:01:19 ssrc()
+ return ssrc_;
+}
+
+std::vector<uint32_t> Packet::Csrcs() const {
+ size_t num_csrc = data()[0] & 0x0F;
+ std::vector<uint32_t> csrcs(num_csrc);
+ for (size_t i = 0; i < num_csrc; ++i)
+ csrcs[i] = ByteReader<uint32_t>::ReadBigEndian(&data()[12 + 4 * i]);
+ return csrcs;
+}
+
+void Packet::GetHeader(RTPHeader* header) const {
+ header->markerBit = Marker();
+ header->payloadType = PayloadType();
+ header->sequenceNumber = SequenceNumber();
+ header->timestamp = Timestamp();
+ header->ssrc = Ssrc();
+ std::vector<uint32_t> csrcs = Csrcs();
+ header->numCSRCs = csrcs.size();
+ for (size_t i = 0; i < csrcs.size(); ++i)
+ header->arrOfCSRCs[i] = csrcs[i];
+ header->paddingLength = PaddingSize();
+ header->headerLength = HeadersSize();
+ header->payload_type_frequency = 0;
+ header->extension.hasTransmissionTimeOffset =
+ GetExtension<TransmissionOffset>(
+ &header->extension.transmissionTimeOffset);
+ header->extension.hasAbsoluteSendTime =
+ GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
+ header->extension.hasTransportSequenceNumber =
+ GetExtension<TransportSequenceNumber>(
+ &header->extension.transportSequenceNumber);
+ header->extension.hasAudioLevel = GetExtension<AudioLevel>(
+ &header->extension.voiceActivity, &header->extension.audioLevel);
+ header->extension.hasVideoRotation =
+ GetExtension<VideoOrientation>(&header->extension.videoRotation);
+}
+
+size_t Packet::HeadersSize() const {
philipel 2016/04/13 12:01:19 header_size()
danilchap 2016/04/13 16:18:34 Done.
+ return payload_offset_;
+}
+
+size_t Packet::PayloadSize() const {
philipel 2016/04/13 12:01:19 payload_size()
danilchap 2016/04/13 16:18:34 Done.
+ return payload_size_;
+}
+
+size_t Packet::PaddingSize() const {
philipel 2016/04/13 12:01:18 padding_size()
danilchap 2016/04/13 16:18:34 Done.
+ return padding_size_;
+}
+
+const uint8_t* Packet::Payload() const {
+ return data() + payload_offset_;
+}
+
+size_t Packet::capacity() const {
+ return buffer_.capacity();
+}
+
+size_t Packet::size() const {
+ return payload_offset_ + payload_size_ + padding_size_;
+}
+
+const uint8_t* Packet::data() const {
+ return buffer_.data();
+}
+
+void Packet::CopyHeader(const Packet& packet) {
+ RTC_DCHECK_GE(capacity(), packet.HeadersSize());
+
+ marker_ = packet.marker_;
+ payload_type_ = packet.payload_type_;
+ sequence_number_ = packet.sequence_number_;
+ timestamp_ = packet.timestamp_;
+ ssrc_ = packet.ssrc_;
+ payload_offset_ = packet.payload_offset_;
+ num_extensions_ = packet.num_extensions_;
+ for (size_t i = 0; i < num_extensions_; ++i)
+ extension_entries_[i] = packet.extension_entries_[i];
+ extensions_size_ = packet.extensions_size_;
+ buffer_.SetData(packet.data(), packet.HeadersSize());
+ // Reset payload and padding.
+ payload_size_ = 0;
+ padding_size_ = 0;
+}
+
+void Packet::SetMarker(bool marker_bit) {
+ marker_ = marker_bit;
+ if (marker_) {
+ WriteAt(1, data()[1] | 0x80);
+ } else {
+ WriteAt(1, data()[1] & 0x7F);
+ }
+}
+
+void Packet::SetPayloadType(uint8_t payload_type) {
+ RTC_DCHECK_LE(payload_type, 0x7Fu);
+ payload_type_ = payload_type;
+ WriteAt(1, (data()[1] & 0x80) | payload_type);
+}
+
+void Packet::SetSequenceNumber(uint16_t seq_no) {
+ sequence_number_ = seq_no;
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
+}
+
+void Packet::SetTimestamp(uint32_t timestamp) {
+ timestamp_ = timestamp;
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
+}
+
+void Packet::SetSsrc(uint32_t ssrc) {
+ ssrc_ = ssrc;
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
+}
+
+void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+ RTC_DCHECK_EQ(num_extensions_, 0u);
+ RTC_DCHECK_EQ(payload_size_, 0u);
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ RTC_DCHECK_LE(csrcs.size(), 0x0fu);
+ RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
+ payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
+ WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
+ size_t offset = kFixedHeaderSize;
+ for (uint32_t csrc : csrcs) {
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
+ offset += 4;
+ }
+}
+
+uint8_t* Packet::AllocatePayload(size_t size_bytes) {
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ if (payload_offset_ + size_bytes > capacity()) {
+ LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
+ return nullptr;
+ }
+ payload_size_ = size_bytes;
+ return WriteAt(payload_offset_);
+}
+
+void Packet::SetPayloadSize(size_t size_bytes) {
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ RTC_DCHECK_LE(size_bytes, payload_size_);
+ payload_size_ = size_bytes;
+}
+
+bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
+ RTC_DCHECK(random);
+ if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
+ LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
+ << (capacity() - payload_offset_ - payload_size_)
+ << " left in buffer.";
philipel 2016/04/13 12:01:18 " bytes left in buffer.";
danilchap 2016/04/13 16:18:33 Done.
+ return false;
+ }
+ padding_size_ = size_bytes;
+ if (padding_size_ > 0) {
+ auto padding_words = std::div(padding_size_, 4);
+ size_t offset = payload_offset_ + payload_size_;
+ size_t padding_end = offset + padding_size_;
+ for (int i = 0; i < padding_words.quot; ++i, offset += 4) {
+ *reinterpret_cast<uint32_t*>(WriteAt(offset)) = random->Rand<uint32_t>();
terelius 2016/04/13 13:17:00 Do you know that the destination is aligned to a 3
danilchap 2016/04/13 16:18:34 True, though usually it is, this code can't assume
+ }
+ for (; offset < padding_end - 1; ++offset) {
+ WriteAt(offset, random->Rand<uint8_t>());
philipel 2016/04/13 12:01:19 remove {}
terelius 2016/04/13 13:17:00 I believe different parts of the code use differen
philipel 2016/04/14 10:32:02 True, but then other parts of the code has to be u
danilchap 2016/04/14 11:07:49 Good point! Updated.
+ }
+ WriteAt(padding_end - 1, size_bytes);
+ WriteAt(0, data()[0] | 0x20); // Set padding bit.
+ } else {
+ WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
+ }
+ return true;
+}
+
+void Packet::Clear() {
+ marker_ = false;
+ payload_type_ = 0;
+ sequence_number_ = 0;
+ timestamp_ = 0;
+ ssrc_ = 0;
+ payload_offset_ = kFixedHeaderSize;
+ payload_size_ = 0;
+ padding_size_ = 0;
+ num_extensions_ = 0;
+ extensions_size_ = 0;
+
+ memset(WriteAt(0), 0, kFixedHeaderSize);
+ WriteAt(0, kRtpVersion << 6);
+}
+
+bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
+ if (size < kFixedHeaderSize)
+ return false;
+ const uint8_t version = buffer[0] >> 6;
+ if (version != kRtpVersion)
+ return false;
+ const bool has_padding = (buffer[0] & 0x20) != 0;
+ // eXtension
+ const bool has_extension = (buffer[0] & 0x10) != 0;
+ const uint8_t number_of_crcs = buffer[0] & 0x0f;
+ marker_ = (buffer[1] & 0x80) != 0;
+ payload_type_ = buffer[1] & 0x7f;
+
+ sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
+ timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+ ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+ if (size < kFixedHeaderSize + number_of_crcs * 4)
+ return false;
+ payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
+
+ if (has_padding) {
+ padding_size_ = buffer[size - 1];
+ if (padding_size_ == 0) {
+ LOG(LS_WARNING) << "Padding was set, but padding size is zero";
+ return false;
+ }
+ } else {
+ padding_size_ = 0;
+ }
+
+ num_extensions_ = 0;
+ extensions_size_ = 0;
+ if (has_extension) {
+ /* RTP header extension, RFC 3550.
+ 0 1 2 3
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | defined by profile | length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | header extension |
+ | .... |
+ */
+ size_t extension_offset = payload_offset_ + 4;
+ if (extension_offset > size)
+ return false;
+ uint16_t profile =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
+ size_t extensions_capacity =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
+ extensions_capacity *= 4;
+ if (extension_offset + extensions_capacity > size)
+ return false;
+ if (profile == kOneByteExtensionId) {
+ const size_t kOneByteHeaderSize = 1;
+ const uint8_t kPaddingId = 0;
+ const uint8_t kReservedId = 15;
+ while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
+ uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
+ if (id == kReservedId) {
+ break;
+ } else if (id == kPaddingId) {
+ extensions_size_++;
+ continue;
+ }
+ uint8_t length =
+ 1 + (buffer[extension_offset + extensions_size_] & 0xf);
+ extensions_size_ += kOneByteHeaderSize;
+ if (num_extensions_ >= kMaxExtensionHeaders)
+ break;
+ extension_entries_[num_extensions_].type =
+ extensions_ ? extensions_->GetType(id)
+ : ExtensionManager::kInvalidType;
+ extension_entries_[num_extensions_].length = length;
+ extension_entries_[num_extensions_].offset =
+ extension_offset + extensions_size_;
+ num_extensions_++;
+ extensions_size_ += length;
+ }
+ }
+ payload_offset_ = extension_offset + extensions_capacity;
+ }
+
+ if (payload_offset_ + padding_size_ > size)
+ return false;
+ payload_size_ = size - payload_offset_ - padding_size_;
+ return true;
+}
+
+bool Packet::FindExtension(ExtensionType type,
+ uint8_t length,
+ uint16_t* offset) const {
+ RTC_DCHECK(offset);
+ for (size_t i = 0; i < num_extensions_; ++i) {
+ if (extension_entries_[i].type == type) {
+ RTC_CHECK_EQ(length, extension_entries_[i].length)
+ << "Length mismatch for extension '" << type << "'"
+ << "should be " << length << ", received "
+ << extension_entries_[i].length;
+ *offset = extension_entries_[i].offset;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Packet::AllocateExtension(ExtensionType type,
+ uint8_t length,
+ uint16_t* offset) {
+ if (!extensions_)
+ return false;
+ if (FindExtension(type, length, offset))
+ return true;
+
+ // Can't add new extension after payload/paddin was set.
terelius 2016/04/13 13:17:00 nit: padding
danilchap 2016/04/13 16:18:33 Done.
+ if (payload_size_ > 0)
+ return false;
+ if (padding_size_ > 0)
+ return false;
+
+ uint8_t extension_id = extensions_->GetId(type);
+ if (extension_id == ExtensionManager::kInvalidId)
+ return false;
+ RTC_DCHECK(0 < length && length <= 16);
+
+ size_t num_csrc = data()[0] & 0x0F;
+ size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+ const uint8_t kExtensionHeaderSize = 1; // Using one-byte extensions only.
+ if (extensions_offset + extensions_size_ + kExtensionHeaderSize + length >
+ capacity()) {
+ LOG(LS_WARNING) << "Extension cannot be registered: "
+ "Not enough space left in buffer.";
+ return false;
+ }
+
+ uint16_t new_extensions_size =
+ extensions_size_ + kExtensionHeaderSize + length;
+ uint16_t extensions_words =
+ (new_extensions_size + 3) / 4; // Wrap up to 32bit.
+ if (extensions_words > 0xFFFF) {
+ LOG(LS_WARNING) << "Too much extension header data, exceeds 2^16 DWORDS.";
+ return false;
+ }
+
+ // All checks passed, write down the extension.
+ if (num_extensions_ == 0) {
+ RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
+ RTC_DCHECK_EQ(extensions_size_, 0);
+ WriteAt(0, data()[0] | 0x10); // Set extension bit.
+ // Profile specific ID always set to OneByteExtensionHeader.
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
+ kOneByteExtensionId);
+ }
+
+ WriteAt(extensions_offset + extensions_size_,
+ (extension_id << 4) | (length - 1));
+ RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders);
+ extension_entries_[num_extensions_].type = type;
+ extension_entries_[num_extensions_].length = length;
+ *offset = extensions_offset + kExtensionHeaderSize + extensions_size_;
+ extension_entries_[num_extensions_].offset = *offset;
+ ++num_extensions_;
+ extensions_size_ = new_extensions_size;
+
+ // Update header length field.
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
+ extensions_words);
+ // Fill extension padding place with zeroes.
+ size_t extension_padding_size = 4 * extensions_words - extensions_size_;
+ memset(WriteAt(extensions_offset + extensions_size_), 0,
+ extension_padding_size);
+ payload_offset_ = extensions_offset + 4 * extensions_words;
+ return true;
+}
+} // namespace rtp
+
+void ReceivedRtpPacket::GetHeader(RTPHeader* header) const {
+ Packet::GetHeader(header);
+ header->payload_type_frequency = payload_type_frequency();
+}
+
+} // namespace webrtc
« webrtc/modules/rtp_rtcp/source/rtp_packet.h ('K') | « webrtc/modules/rtp_rtcp/source/rtp_packet.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698