RtpPacket class introduced.

BUG=webrtc:1994, webrtc:5261

Review URL: https://codereview.webrtc.org/1841453004

Cr-Commit-Position: refs/heads/master@{#12444}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 8ae5bbb..6474253 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -337,6 +337,7 @@
             'rtp_rtcp/source/rtp_format_vp8_unittest.cc',
             'rtp_rtcp/source/rtp_format_vp9_unittest.cc',
             'rtp_rtcp/source/rtp_packet_history_unittest.cc',
+            'rtp_rtcp/source/rtp_packet_unittest.cc',
             'rtp_rtcp/source/rtp_payload_registry_unittest.cc',
             'rtp_rtcp/source/rtp_rtcp_impl_unittest.cc',
             'rtp_rtcp/source/rtp_header_extension_unittest.cc',
diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn
index d386951..9d69811 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -118,9 +118,15 @@
     "source/rtp_format_vp9.h",
     "source/rtp_header_extension.cc",
     "source/rtp_header_extension.h",
+    "source/rtp_header_extensions.cc",
+    "source/rtp_header_extensions.h",
     "source/rtp_header_parser.cc",
+    "source/rtp_packet.cc",
+    "source/rtp_packet.h",
     "source/rtp_packet_history.cc",
     "source/rtp_packet_history.h",
+    "source/rtp_packet_received.h",
+    "source/rtp_packet_to_send.h",
     "source/rtp_payload_registry.cc",
     "source/rtp_receiver_audio.cc",
     "source/rtp_receiver_audio.h",
diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
index 23a64b7..3f1e935 100644
--- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -35,10 +35,6 @@
         'source/receive_statistics_impl.cc',
         'source/receive_statistics_impl.h',
         'source/remote_ntp_time_estimator.cc',
-        'source/rtp_header_parser.cc',
-        'source/rtp_rtcp_config.h',
-        'source/rtp_rtcp_impl.cc',
-        'source/rtp_rtcp_impl.h',
         'source/rtcp_packet.cc',
         'source/rtcp_packet.h',
         'source/rtcp_packet/app.cc',
@@ -103,8 +99,18 @@
         'source/rtcp_utility.h',
         'source/rtp_header_extension.cc',
         'source/rtp_header_extension.h',
+        'source/rtp_header_extensions.cc',
+        'source/rtp_header_extensions.h',
+        'source/rtp_header_parser.cc',
+        'source/rtp_packet.cc',
+        'source/rtp_packet.h',
+        'source/rtp_packet_received.h',
+        'source/rtp_packet_to_send.h',
         'source/rtp_receiver_impl.cc',
         'source/rtp_receiver_impl.h',
+        'source/rtp_rtcp_config.h',
+        'source/rtp_rtcp_impl.cc',
+        'source/rtp_rtcp_impl.h',
         'source/rtp_sender.cc',
         'source/rtp_sender.h',
         'source/rtp_utility.cc',
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
index 8605925..2c2a0a1 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -112,6 +112,14 @@
   return 0;
 }
 
+RTPExtensionType RtpHeaderExtensionMap::GetType(uint8_t id) const {
+  auto it = extensionMap_.find(id);
+  if (it == extensionMap_.end()) {
+    return kInvalidType;
+  }
+  return it->second->type;
+}
+
 int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
                                      uint8_t* id) const {
   assert(id);
@@ -129,6 +137,14 @@
   return -1;
 }
 
+uint8_t RtpHeaderExtensionMap::GetId(RTPExtensionType type) const {
+  for (auto kv : extensionMap_) {
+    if (kv.second->type == type)
+      return kv.first;
+  }
+  return kInvalidId;
+}
+
 size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
   // Get length for each extension block.
   size_t length = 0;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
index 342e38a..beaf989 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -70,6 +70,8 @@
 
 class RtpHeaderExtensionMap {
  public:
+  static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
+  static constexpr uint8_t kInvalidId = 0;
   RtpHeaderExtensionMap();
   ~RtpHeaderExtensionMap();
 
@@ -89,8 +91,12 @@
   bool IsRegistered(RTPExtensionType type) const;
 
   int32_t GetType(const uint8_t id, RTPExtensionType* type) const;
+  // Return kInvalidType if not found.
+  RTPExtensionType GetType(uint8_t id) const;
 
   int32_t GetId(const RTPExtensionType type, uint8_t* id) const;
+  // Return kInvalidId if not found.
+  uint8_t GetId(RTPExtensionType type) const;
 
   //
   // Methods below ignore any inactive rtp header extensions.
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
new file mode 100644
index 0000000..a551b15
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -0,0 +1,203 @@
+/*
+ *  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_header_extensions.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+// Absolute send time in RTP streams.
+//
+// The absolute send time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit unsigned integer
+// containing the sender's current time in seconds as a fixed point number
+// with 18 bits fractional part.
+//
+// The form of the absolute send time extension block:
+//
+//    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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=2 |              absolute send time               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* AbsoluteSendTime::kName =
+    "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+bool AbsoluteSendTime::IsSupportedFor(MediaType type) {
+  return true;
+}
+
+bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* value) {
+  *value = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+  return true;
+}
+
+bool AbsoluteSendTime::Write(uint8_t* data, int64_t time_ms) {
+  const uint32_t kAbsSendTimeFraction = 18;
+  uint32_t time_24_bits =
+      static_cast<uint32_t>(((time_ms << kAbsSendTimeFraction) + 500) / 1000) &
+      0x00FFFFFF;
+
+  ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24_bits);
+  return true;
+}
+
+// An RTP Header Extension for Client-to-Mixer Audio Level Indication
+//
+// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+//
+// The form of the audio level extension block:
+//
+//    0                   1
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=0 |V|   level     |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+const char* AudioLevel::kName = "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+bool AudioLevel::IsSupportedFor(MediaType type) {
+  switch (type) {
+    case MediaType::ANY:
+    case MediaType::AUDIO:
+      return true;
+    case MediaType::VIDEO:
+    case MediaType::DATA:
+      return false;
+  }
+  RTC_NOTREACHED();
+  return false;
+}
+
+bool AudioLevel::Parse(const uint8_t* data,
+                       bool* voice_activity,
+                       uint8_t* audio_level) {
+  *voice_activity = (data[0] & 0x80) != 0;
+  *audio_level = data[0] & 0x7F;
+  return true;
+}
+
+bool AudioLevel::Write(uint8_t* data,
+                       bool voice_activity,
+                       uint8_t audio_level) {
+  RTC_CHECK_LE(audio_level, 0x7f);
+  data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
+  return true;
+}
+
+// From RFC 5450: Transmission Time Offsets in RTP Streams.
+//
+// The transmission time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit signed integer.
+// When added to the RTP timestamp of the packet, it represents the
+// "effective" RTP transmission time of the packet, on the RTP
+// timescale.
+//
+// The form of the transmission offset extension block:
+//
+//    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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=2 |              transmission offset              |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* TransmissionOffset::kName = "urn:ietf:params:rtp-hdrext:toffset";
+bool TransmissionOffset::IsSupportedFor(MediaType type) {
+  switch (type) {
+    case MediaType::ANY:
+    case MediaType::VIDEO:
+      return true;
+    case MediaType::AUDIO:
+    case MediaType::DATA:
+      return false;
+  }
+  RTC_NOTREACHED();
+  return false;
+}
+
+bool TransmissionOffset::Parse(const uint8_t* data, int32_t* value) {
+  *value = ByteReader<int32_t, 3>::ReadBigEndian(data);
+  return true;
+}
+
+bool TransmissionOffset::Write(uint8_t* data, int64_t value) {
+  RTC_CHECK_LE(value, 0x00ffffff);
+  ByteWriter<int32_t, 3>::WriteBigEndian(data, value);
+  return true;
+}
+
+//   0                   1                   2
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  ID   | L=1   |transport wide sequence number |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* TransportSequenceNumber::kName =
+    "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions";
+bool TransportSequenceNumber::IsSupportedFor(MediaType type) {
+  return true;
+}
+
+bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) {
+  *value = ByteReader<uint16_t>::ReadBigEndian(data);
+  return true;
+}
+
+bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
+  ByteWriter<uint16_t>::WriteBigEndian(data, value);
+  return true;
+}
+
+// Coordination of Video Orientation in RTP streams.
+//
+// Coordination of Video Orientation consists in signaling of the current
+// orientation of the image captured on the sender side to the receiver for
+// appropriate rendering and displaying.
+//
+//    0                   1
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=0 |0 0 0 0 C F R R|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* VideoOrientation::kName = "urn:3gpp:video-orientation";
+bool VideoOrientation::IsSupportedFor(MediaType type) {
+  switch (type) {
+    case MediaType::ANY:
+    case MediaType::VIDEO:
+      return true;
+    case MediaType::AUDIO:
+    case MediaType::DATA:
+      return false;
+  }
+  RTC_NOTREACHED();
+  return false;
+}
+
+bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) {
+  *rotation = ConvertCVOByteToVideoRotation(data[0] & 0x03);
+  return true;
+}
+
+bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) {
+  data[0] = ConvertVideoRotationToCVOByte(rotation);
+  return true;
+}
+
+bool VideoOrientation::Parse(const uint8_t* data, uint8_t* value) {
+  *value = data[0];
+  return true;
+}
+
+bool VideoOrientation::Write(uint8_t* data, uint8_t value) {
+  data[0] = value;
+  return true;
+}
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
new file mode 100644
index 0000000..cdbf806
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -0,0 +1,75 @@
+/*
+ *  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.
+ */
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/call.h"
+#include "webrtc/common_video/rotation.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+class AbsoluteSendTime {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
+  static constexpr uint8_t kValueSizeBytes = 3;
+  static const char* kName;
+  static bool IsSupportedFor(MediaType type);
+  static bool Parse(const uint8_t* data, uint32_t* time_ms);
+  static bool Write(uint8_t* data, int64_t time_ms);
+};
+
+class AudioLevel {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
+  static constexpr uint8_t kValueSizeBytes = 1;
+  static const char* kName;
+  static bool IsSupportedFor(MediaType type);
+  static bool Parse(const uint8_t* data,
+                    bool* voice_activity,
+                    uint8_t* audio_level);
+  static bool Write(uint8_t* data, bool voice_activity, uint8_t audio_level);
+};
+
+class TransmissionOffset {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset;
+  static constexpr uint8_t kValueSizeBytes = 3;
+  static const char* kName;
+  static bool IsSupportedFor(MediaType type);
+  static bool Parse(const uint8_t* data, int32_t* time_ms);
+  static bool Write(uint8_t* data, int64_t time_ms);
+};
+
+class TransportSequenceNumber {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
+  static constexpr uint8_t kValueSizeBytes = 2;
+  static const char* kName;
+  static bool IsSupportedFor(MediaType type);
+  static bool Parse(const uint8_t* data, uint16_t* value);
+  static bool Write(uint8_t* data, uint16_t value);
+};
+
+class VideoOrientation {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
+  static constexpr uint8_t kValueSizeBytes = 1;
+  static const char* kName;
+  static bool IsSupportedFor(MediaType type);
+  static bool Parse(const uint8_t* data, VideoRotation* value);
+  static bool Write(uint8_t* data, VideoRotation value);
+  static bool Parse(const uint8_t* data, uint8_t* value);
+  static bool Write(uint8_t* data, uint8_t value);
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
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 0000000..f663486
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -0,0 +1,509 @@
+/*
+ *  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/common_types.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 {
+constexpr size_t kFixedHeaderSize = 12;
+constexpr uint8_t kRtpVersion = 2;
+constexpr uint16_t kOneByteExtensionId = 0xBEDE;
+constexpr size_t kOneByteHeaderSize = 1;
+constexpr 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() {}
+
+void Packet::IdentifyExtensions(const ExtensionManager* extensions) {
+  RTC_DCHECK(extensions);
+  extensions_ = extensions;
+  for (size_t i = 0; i < num_extensions_; ++i) {
+    uint8_t id = data()[extension_entries_[i].offset - 1] >> 4;
+    extension_entries_[i].type = extensions_->GetType(id);
+  }
+}
+
+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 {
+  RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
+  return marker_;
+}
+
+uint8_t Packet::PayloadType() const {
+  RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
+  return payload_type_;
+}
+
+uint16_t Packet::SequenceNumber() const {
+  RTC_DCHECK_EQ(sequence_number_,
+                ByteReader<uint16_t>::ReadBigEndian(data() + 2));
+  return sequence_number_;
+}
+
+uint32_t Packet::Timestamp() const {
+  RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
+  return timestamp_;
+}
+
+uint32_t Packet::Ssrc() const {
+  RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
+  return ssrc_;
+}
+
+std::vector<uint32_t> Packet::Csrcs() const {
+  size_t num_csrc = data()[0] & 0x0F;
+  RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
+  std::vector<uint32_t> csrcs(num_csrc);
+  for (size_t i = 0; i < num_csrc; ++i) {
+    csrcs[i] =
+        ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
+  }
+  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 = padding_size();
+  header->headerLength = headers_size();
+  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::headers_size() const {
+  return payload_offset_;
+}
+
+size_t Packet::payload_size() const {
+  return payload_size_;
+}
+
+size_t Packet::padding_size() const {
+  return padding_size_;
+}
+
+const uint8_t* Packet::payload() const {
+  return data() + payload_offset_;
+}
+
+size_t Packet::capacity() const {
+  return buffer_.size();
+}
+
+size_t Packet::size() const {
+  return payload_offset_ + payload_size_ + padding_size_;
+}
+
+const uint8_t* Packet::data() const {
+  return buffer_.data();
+}
+
+size_t Packet::FreeCapacity() const {
+  return capacity() - size();
+}
+
+size_t Packet::MaxPayloadSize() const {
+  return capacity() - payload_offset_;
+}
+
+void Packet::CopyHeader(const Packet& packet) {
+  RTC_DCHECK_GE(capacity(), packet.headers_size());
+
+  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.headers_size());
+  // 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_)
+                    << " bytes left in buffer.";
+    return false;
+  }
+  padding_size_ = size_bytes;
+  if (padding_size_ > 0) {
+    size_t padding_offset = payload_offset_ + payload_size_;
+    size_t padding_end = padding_offset + padding_size_;
+    for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
+      WriteAt(offset, random->Rand<uint8_t>());
+    }
+    WriteAt(padding_end - 1, padding_size_);
+    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;
+  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) {
+      LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
+    } else {
+      constexpr uint8_t kPaddingId = 0;
+      constexpr 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) {
+          LOG(LS_WARNING) << "Too many extensions.";
+          return false;
+        }
+        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/padding was set.
+  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_GT(length, 0u);
+  RTC_DCHECK_LE(length, 16u);
+
+  size_t num_csrc = data()[0] & 0x0F;
+  size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+  if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
+      capacity()) {
+    LOG(LS_WARNING) << "Extension cannot be registered: "
+                       "Not enough space left in buffer.";
+    return false;
+  }
+
+  uint16_t new_extensions_size =
+      extensions_size_ + kOneByteHeaderSize + length;
+  uint16_t extensions_words =
+      (new_extensions_size + 3) / 4;  // Wrap up to 32bit.
+
+  // 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 + kOneByteHeaderSize + 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;
+}
+
+uint8_t* Packet::WriteAt(size_t offset) {
+  return buffer_.data() + offset;
+}
+
+void Packet::WriteAt(size_t offset, uint8_t byte) {
+  buffer_.data()[offset] = byte;
+}
+
+}  // namespace rtp
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet.h b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
new file mode 100644
index 0000000..9e9f4c1
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
@@ -0,0 +1,186 @@
+/*
+ *  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.
+ */
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+struct RTPHeader;
+class RtpHeaderExtensionMap;
+class Random;
+
+namespace rtp {
+class Packet {
+ public:
+  using ExtensionType = RTPExtensionType;
+  using ExtensionManager = RtpHeaderExtensionMap;
+  static constexpr size_t kMaxExtensionHeaders = 14;
+
+  // Parse and copy given buffer into Packet.
+  bool Parse(const uint8_t* buffer, size_t size);
+
+  // Parse and move given buffer into Packet.
+  bool Parse(rtc::Buffer packet);
+
+  // Maps parsed extensions to their types to allow use of GetExtension.
+  // Used after parsing when |extensions| can't be provided until base rtp
+  // header is parsed.
+  void IdentifyExtensions(const ExtensionManager* extensions);
+
+  // Header.
+  bool Marker() const;
+  uint8_t PayloadType() const;
+  uint16_t SequenceNumber() const;
+  uint32_t Timestamp() const;
+  uint32_t Ssrc() const;
+  std::vector<uint32_t> Csrcs() const;
+
+  // TODO(danilchap): Remove this function when all code update to use RtpPacket
+  // directly. Function is there just for easier backward compatibilty.
+  void GetHeader(RTPHeader* header) const;
+
+  size_t headers_size() const;
+
+  // Payload.
+  size_t payload_size() const;
+  size_t padding_size() const;
+  const uint8_t* payload() const;
+
+  // Buffer.
+  size_t capacity() const;
+  size_t size() const;
+  const uint8_t* data() const;
+  size_t FreeCapacity() const;
+  size_t MaxPayloadSize() const;
+
+  // Reset fields and buffer.
+  void Clear();
+
+  // Header setters.
+  void CopyHeader(const Packet& packet);
+  void SetMarker(bool marker_bit);
+  void SetPayloadType(uint8_t payload_type);
+  void SetSequenceNumber(uint16_t seq_no);
+  void SetTimestamp(uint32_t timestamp);
+  void SetSsrc(uint32_t ssrc);
+
+  // Writes csrc list. Assumes:
+  // a) There is enough room left in buffer.
+  // b) Extension headers, payload or padding data has not already been added.
+  void SetCsrcs(const std::vector<uint32_t>& csrcs);
+
+  // Header extensions.
+  template <typename Extension, typename... Values>
+  bool GetExtension(Values...) const;
+
+  template <typename Extension, typename... Values>
+  bool SetExtension(Values...);
+
+  template <typename Extension>
+  bool ReserveExtension();
+
+  // Reserve size_bytes for payload. Returns nullptr on failure.
+  uint8_t* AllocatePayload(size_t size_bytes);
+  void SetPayloadSize(size_t size_bytes);
+  bool SetPadding(uint8_t size_bytes, Random* random);
+
+ protected:
+  // |extensions| required for SetExtension/ReserveExtension functions during
+  // packet creating and used if available in Parse function.
+  // Adding and getting extensions will fail until |extensions| is
+  // provided via constructor or IdentifyExtensions function.
+  explicit Packet(const ExtensionManager* extensions);
+  Packet(const ExtensionManager* extensions, size_t capacity);
+  virtual ~Packet();
+
+ private:
+  struct ExtensionInfo {
+    ExtensionType type;
+    uint16_t offset;
+    uint8_t length;
+  };
+
+  // Helper function for Parse. Fill header fields using data in given buffer,
+  // but does not touch packet own buffer, leaving packet in invalid state.
+  bool ParseBuffer(const uint8_t* buffer, size_t size);
+
+  // Find an extension based on the type field of the parameter.
+  // If found, length field would be validated, the offset field will be set
+  // and true returned,
+  // otherwise the parameter will be unchanged and false is returned.
+  bool FindExtension(ExtensionType type,
+                     uint8_t length,
+                     uint16_t* offset) const;
+
+  // Find or allocate an extension, based on the type field of the parameter.
+  // If found, the length field be checked against what is already registered
+  // and the offset field will be set, then true is returned. If allocated, the
+  // length field will be used for allocation and the offset update to indicate
+  // position, the true is returned.
+  // If not found and allocations fails, false is returned and parameter remains
+  // unchanged.
+  bool AllocateExtension(ExtensionType type, uint8_t length, uint16_t* offset);
+
+  uint8_t* WriteAt(size_t offset);
+  void WriteAt(size_t offset, uint8_t byte);
+
+  const ExtensionManager* extensions_;
+
+  // Header.
+  bool marker_;
+  uint8_t payload_type_;
+  uint8_t padding_size_;
+  uint16_t sequence_number_;
+  uint32_t timestamp_;
+  uint32_t ssrc_;
+  size_t payload_offset_;  // Match header size with csrcs and extensions.
+  size_t payload_size_;
+
+  uint8_t num_extensions_ = 0;
+  ExtensionInfo extension_entries_[kMaxExtensionHeaders];
+  uint16_t extensions_size_ = 0;  // Unaligned.
+  rtc::Buffer buffer_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Packet);
+};
+
+template <typename Extension, typename... Values>
+bool Packet::GetExtension(Values... values) const {
+  uint16_t offset = 0;
+  if (!FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+    return false;
+  return Extension::Parse(data() + offset, values...);
+}
+
+template <typename Extension, typename... Values>
+bool Packet::SetExtension(Values... values) {
+  uint16_t offset = 0;
+  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+    return false;
+  return Extension::Write(WriteAt(offset), values...);
+}
+
+template <typename Extension>
+bool Packet::ReserveExtension() {
+  uint16_t offset = 0;
+  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+    return false;
+  memset(WriteAt(offset), 0, Extension::kValueSizeBytes);
+  return true;
+}
+}  // namespace rtp
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h b/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
new file mode 100644
index 0000000..e2222b9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
@@ -0,0 +1,56 @@
+/*
+ *  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.
+ */
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+
+#include "webrtc/common_types.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
+#include "webrtc/system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for receiver side.
+class RtpPacketReceived : public rtp::Packet {
+ public:
+  RtpPacketReceived() : Packet(nullptr) {}
+  explicit RtpPacketReceived(const ExtensionManager* extensions)
+      : Packet(extensions) {}
+
+  void GetHeader(RTPHeader* header) const {
+    Packet::GetHeader(header);
+    header->payload_type_frequency = payload_type_frequency();
+  }
+
+  // Time in local time base as close as it can to packet arrived on the
+  // network.
+  int64_t arrival_time_ms() const { return arrival_time_ms_; }
+  void set_arrival_time_ms(int64_t time) { arrival_time_ms_ = time; }
+
+  // Estimated from Timestamp() using rtcp Sender Reports.
+  NtpTime capture_ntp_time() const { return capture_time_; }
+  void set_capture_ntp_time(NtpTime time) { capture_time_ = time; }
+
+  // Flag if packet arrived via rtx.
+  bool retransmit() const { return retransmit_; }
+  void set_retransmit(bool value) { retransmit_ = value; }
+
+  int payload_type_frequency() const { return payload_type_frequency_; }
+  void set_payload_type_frequency(int value) {
+    payload_type_frequency_ = value;
+  }
+
+ private:
+  NtpTime capture_time_;
+  int64_t arrival_time_ms_ = 0;
+  int payload_type_frequency_ = 0;
+  bool retransmit_ = false;
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h b/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
new file mode 100644
index 0000000..ad749ff
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
@@ -0,0 +1,33 @@
+/*
+ *  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.
+ */
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
+
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for sender side.
+class RtpPacketToSend : public rtp::Packet {
+ public:
+  explicit RtpPacketToSend(const ExtensionManager* extensions)
+      : Packet(extensions) {}
+  RtpPacketToSend(const ExtensionManager* extensions, size_t capacity)
+      : Packet(extensions, capacity) {}
+
+  // Time in local time base as close as it can to frame capture time.
+  int64_t capture_time_ms() const { return capture_time_ms_; }
+  void set_capture_time_ms(int64_t time) { capture_time_ms_ = time; }
+
+ private:
+  int64_t capture_time_ms_ = 0;
+};
+
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
new file mode 100644
index 0000000..b992d2d
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -0,0 +1,252 @@
+/*
+ *  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_received.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/random.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+
+namespace webrtc {
+namespace {
+constexpr int8_t kPayloadType = 100;
+constexpr uint32_t kSsrc = 0x12345678;
+constexpr uint16_t kSeqNum = 88;
+constexpr uint32_t kTimestamp = 0x65431278;
+constexpr uint8_t kTransmissionOffsetExtensionId = 1;
+constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr int32_t kTimeOffset = 0x56ce;
+constexpr bool kVoiceActive = true;
+constexpr uint8_t kAudioLevel = 0x5a;
+constexpr size_t kMaxPaddingSize = 224u;
+constexpr uint8_t kMinimumPacket[] = {
+    0x80, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78};
+constexpr uint8_t kPacketWithTO[] = {
+    0x90, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x01,
+    0x12, 0x00, 0x56, 0xce};
+
+constexpr uint8_t kPacketWithTOAndAL[] = {
+    0x90, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x02,
+    0x12, 0x00, 0x56, 0xce,
+    0x90, 0x80|kAudioLevel, 0x00, 0x00};
+
+constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
+constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
+constexpr uint8_t kPacketPaddingSize = 8;
+constexpr uint8_t kPacket[] = {
+    0xb2, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0x34, 0x56, 0x78, 0x90,
+    0x32, 0x43, 0x54, 0x65,
+    0xbe, 0xde, 0x00, 0x01,
+    0x12, 0x00, 0x56, 0xce,
+    'p', 'a', 'y', 'l', 'o', 'a', 'd',
+    'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
+
+}  // namespace
+
+TEST(RtpPacketTest, CreateMinimum) {
+  RtpPacketToSend packet(nullptr);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  EXPECT_THAT(kMinimumPacket, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithExtension) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<TransmissionOffset>(kTimeOffset);
+  EXPECT_THAT(kPacketWithTO, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWith2Extensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<TransmissionOffset>(kTimeOffset);
+  packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel);
+  EXPECT_THAT(kPacketWithTOAndAL,
+              ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) {
+  const size_t kPayloadSize = 4;
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketToSend packet(&extensions);
+
+  EXPECT_TRUE(packet.ReserveExtension<TransmissionOffset>());
+  packet.AllocatePayload(kPayloadSize);
+  // Can't set extension after payload.
+  EXPECT_FALSE(packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel));
+  // Unless reserved.
+  EXPECT_TRUE(packet.SetExtension<TransmissionOffset>(kTimeOffset));
+}
+
+TEST(RtpPacketTest, CreatePurePadding) {
+  const size_t kPaddingSize = kMaxPaddingSize - 1;
+  RtpPacketToSend packet(nullptr, 12 + kPaddingSize);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  Random random(0x123456789);
+
+  EXPECT_LT(packet.size(), packet.capacity());
+  EXPECT_FALSE(packet.SetPadding(kPaddingSize + 1, &random));
+  EXPECT_TRUE(packet.SetPadding(kPaddingSize, &random));
+  EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, CreateUnalignedPadding) {
+  const size_t kPayloadSize = 3;  // Make padding start at unaligned address.
+  RtpPacketToSend packet(nullptr, 12 + kPayloadSize + kMaxPaddingSize);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.AllocatePayload(kPayloadSize);
+  Random r(0x123456789);
+
+  EXPECT_LT(packet.size(), packet.capacity());
+  EXPECT_TRUE(packet.SetPadding(kMaxPaddingSize, &r));
+  EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, ParseMinimum) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kMinimumPacket, sizeof(kMinimumPacket)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_EQ(0u, packet.padding_size());
+  EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseBuffer) {
+  rtc::Buffer unparsed(kMinimumPacket);
+  const uint8_t* raw = unparsed.data();
+
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(std::move(unparsed)));
+  EXPECT_EQ(raw, packet.data());  // Expect packet took over the buffer.
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_EQ(0u, packet.padding_size());
+  EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseWithExtension) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  EXPECT_EQ(0u, packet.payload_size());
+  EXPECT_EQ(0u, packet.padding_size());
+}
+
+TEST(RtpPacketTest, ParseWith2Extensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithTOAndAL, sizeof(kPacketWithTOAndAL)));
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  bool voice_active;
+  uint8_t audio_level;
+  EXPECT_TRUE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
+  EXPECT_EQ(kVoiceActive, voice_active);
+  EXPECT_EQ(kAudioLevel, audio_level);
+}
+
+TEST(RtpPacketTest, ParseWithAllFeatures) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_THAT(packet.Csrcs(), ElementsAreArray(kCsrcs));
+  EXPECT_THAT(make_tuple(packet.payload(), packet.payload_size()),
+              ElementsAreArray(kPayload));
+  EXPECT_EQ(kPacketPaddingSize, packet.padding_size());
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+}
+
+TEST(RtpPacketTest, ParseWithExtensionDelayed) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+
+  int32_t time_offset;
+  EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  packet.IdentifyExtensions(&extensions);
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  EXPECT_EQ(0u, packet.payload_size());
+  EXPECT_EQ(0u, packet.padding_size());
+}
+
+}  // namespace webrtc
diff --git a/webrtc/test/fuzzers/BUILD.gn b/webrtc/test/fuzzers/BUILD.gn
index c46cc1e..3e59339 100644
--- a/webrtc/test/fuzzers/BUILD.gn
+++ b/webrtc/test/fuzzers/BUILD.gn
@@ -75,6 +75,15 @@
   ]
 }
 
+webrtc_fuzzer_test("rtp_packet_fuzzer") {
+  sources = [
+    "rtp_packet_fuzzer.cc",
+  ]
+  deps = [
+    "../../modules/rtp_rtcp/",
+  ]
+}
+
 source_set("audio_decoder_fuzzer") {
   public_configs = [ "../..:common_inherited_config" ]
   sources = [
diff --git a/webrtc/test/fuzzers/rtp_packet_fuzzer.cc b/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
new file mode 100644
index 0000000..a9efdb9
--- /dev/null
+++ b/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -0,0 +1,29 @@
+/*
+ *  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_received.h"
+
+namespace webrtc {
+
+void FuzzOneInput(const uint8_t* data, size_t size) {
+  RtpPacketReceived packet;
+
+  packet.Parse(data, size);
+
+  // Call packet accessors because they have extra checks.
+  packet.Marker();
+  packet.PayloadType();
+  packet.SequenceNumber();
+  packet.Timestamp();
+  packet.Ssrc();
+  packet.Csrcs();
+}
+
+}  // namespace webrtc
+