Bug 1380430 - Backport current webrtc.org RtpHeaderExtension handling changes and RtpStreamId implementation. r=drno
authorMichael Froman <mfroman@mozilla.com>
Wed, 12 Jul 2017 13:44:40 -0500
changeset 611657 f9954d5cf6ea0c3d9c8c1a80a72a25f039dbab2b
parent 611331 c5ea72577f794635a334a30780d104a1d89267a0
child 611658 b10cc6c6704b9ea443788a12e29a1100f2925a5e
push id69287
push userCallek@gmail.com
push dateThu, 20 Jul 2017 01:11:37 +0000
reviewersdrno
bugs1380430
milestone56.0a1
Bug 1380430 - Backport current webrtc.org RtpHeaderExtension handling changes and RtpStreamId implementation. r=drno The new RtpHeaderExtension handling works better with variable length header extensions, and the new RtpStreamId implementation takes advantage of it. This is useful to us because we'll be able to add MID support using the same mechanism. MozReview-Commit-ID: 5VYQYvhD5gr
media/webrtc/signaling/src/mediapipeline/MediaPipelineFilter.cpp
media/webrtc/trunk/gtest/moz.build
media/webrtc/trunk/webrtc/common_types.cc
media/webrtc/trunk/webrtc/common_types.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/flexfec_sender.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
media/webrtc/trunk/webrtc/video/video_send_stream.cc
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipelineFilter.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipelineFilter.cpp
@@ -30,24 +30,24 @@ bool MediaPipelineFilter::Filter(const w
       return true;
     }
     // Some other stream; it is possible that an SSRC has moved, so make sure
     // we don't have that SSRC in our filter any more.
     remote_ssrc_set_.erase(header.ssrc);
     return false;
   }
 
-  if (header.extension.hasRID &&
+  if (!header.extension.rtpStreamId.empty() &&
       remote_rid_set_.size() &&
-      remote_rid_set_.count(header.extension.rid.get())) {
+      remote_rid_set_.count(header.extension.rtpStreamId.data())) {
     return true;
   }
-  if (header.extension.hasRID) {
+  if (!header.extension.rtpStreamId.empty()) {
     MOZ_MTLOG(ML_DEBUG, "MediaPipelineFilter ignoring seq# " << header.sequenceNumber <<
-              " ssrc: " << header.ssrc << " RID: " << header.extension.rid.get());
+              " ssrc: " << header.ssrc << " RID: " << header.extension.rtpStreamId.data());
   }
 
   if (remote_ssrc_set_.count(header.ssrc)) {
     return true;
   }
 
   // Last ditch effort...
   if (payload_type_set_.count(header.payloadType)) {
--- a/media/webrtc/trunk/gtest/moz.build
+++ b/media/webrtc/trunk/gtest/moz.build
@@ -363,16 +363,17 @@ if CONFIG['OS_TARGET'] in ['Darwin', 'Li
         '../webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc',
+        '../webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/time_util_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc',
         '../webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator_unittest.cc',
         '../webrtc/modules/utility/source/process_thread_impl_unittest.cc',
         '../webrtc/modules/video_capture/test/video_capture_unittest.cc',
         '../webrtc/modules/video_coding/codecs/test/packet_manipulator.cc',
         '../webrtc/modules/video_coding/codecs/test/predictive_packet_manipulator.cc',
--- a/media/webrtc/trunk/webrtc/common_types.cc
+++ b/media/webrtc/trunk/webrtc/common_types.cc
@@ -15,30 +15,47 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/stringutils.h"
 
 namespace webrtc {
 
 StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}
 
+constexpr size_t StreamId::kMaxSize;
+
+bool StreamId::IsLegalName(rtc::ArrayView<const char> name) {
+  return (name.size() <= kMaxSize && name.size() > 0 &&
+          std::all_of(name.data(), name.data() + name.size(), isalnum));
+}
+
+void StreamId::Set(const char* data, size_t size) {
+  // If |data| contains \0, the stream id size might become less than |size|.
+  RTC_CHECK_LE(size, kMaxSize);
+  memcpy(value_, data, size);
+  // mozilla: value_ is kMaxSize+1 so we always have room to null terminate
+  value_[size] = 0;
+}
+
+// StreamId is used as member of RTPHeader that is sometimes copied with memcpy
+// and thus assume trivial destructibility.
+static_assert(std::is_trivially_destructible<StreamId>::value, "");
+
 RTPHeaderExtension::RTPHeaderExtension()
     : hasTransmissionTimeOffset(false),
       transmissionTimeOffset(0),
       hasAbsoluteSendTime(false),
       absoluteSendTime(0),
       hasTransportSequenceNumber(false),
       transportSequenceNumber(0),
       hasAudioLevel(false),
       voiceActivity(false),
       audioLevel(0),
       hasVideoRotation(false),
-      videoRotation(kVideoRotation_0),
-      hasRID(false),
-      rid(nullptr) {
+      videoRotation(kVideoRotation_0) {
 }
 
 RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& rhs) {
   *this = rhs;
 }
 
 RTPHeaderExtension&
 RTPHeaderExtension::operator=(const RTPHeaderExtension& rhs) {
@@ -51,21 +68,18 @@ RTPHeaderExtension::operator=(const RTPH
 
   hasAudioLevel = rhs.hasAudioLevel;
   voiceActivity = rhs.voiceActivity;
   audioLevel = rhs.audioLevel;
 
   hasVideoRotation = rhs.hasVideoRotation;
   videoRotation = rhs.videoRotation;
 
-  hasRID = rhs.hasRID;
- if (rhs.rid) {
-    rid.reset(new char[strlen(rhs.rid.get())+1]);
-    strcpy(rid.get(), rhs.rid.get());
-  }
+  rtpStreamId = rhs.rtpStreamId;
+
   return *this;
 }
 
 RTPHeader::RTPHeader()
     : markerBit(false),
       payloadType(0),
       sequenceNumber(0),
       timestamp(0),
--- a/media/webrtc/trunk/webrtc/common_types.h
+++ b/media/webrtc/trunk/webrtc/common_types.h
@@ -814,16 +814,56 @@ struct PacketTime {
 //
 // Note: Given that this gets embedded in a union, it is up-to the owner to
 // initialize these values.
 struct PlayoutDelay {
   int min_ms;
   int max_ms;
 };
 
+// Class to represent RtpStreamId which is a string.
+// Unlike std::string, it can be copied with memcpy and cleared with memset.
+// Empty value represent unset RtpStreamId.
+class StreamId {
+ public:
+  // Stream id is limited to 16 bytes because it is the maximum length
+  // that can be encoded with one-byte header extensions.
+  static constexpr size_t kMaxSize = 16;
+
+  static bool IsLegalName(rtc::ArrayView<const char> name);
+
+  StreamId() { value_[0] = 0; }
+  explicit StreamId(rtc::ArrayView<const char> value) {
+    Set(value.data(), value.size());
+  }
+  StreamId(const StreamId&) = default;
+  StreamId& operator=(const StreamId&) = default;
+
+  bool empty() const { return value_[0] == 0; }
+  const char* data() const { return value_; }
+  size_t size() const { return strnlen(value_, kMaxSize); }
+
+  void Set(rtc::ArrayView<const uint8_t> value) {
+    Set(reinterpret_cast<const char*>(value.data()), value.size());
+  }
+  // mozilla: data() is guaranteed to be null terminated after Set completes
+  void Set(const char* data, size_t size);
+
+  friend bool operator==(const StreamId& lhs, const StreamId& rhs) {
+    return (lhs.size() == rhs.size() &&
+            strncmp(lhs.value_, rhs.value_, kMaxSize) == 0);
+  }
+  friend bool operator!=(const StreamId& lhs, const StreamId& rhs) {
+    return !(lhs == rhs);
+  }
+
+ private:
+  char value_[kMaxSize+1]; // mozilla: make sure we have space to null term.
+};
+
 struct RTPHeaderExtension {
   RTPHeaderExtension();
   RTPHeaderExtension(const RTPHeaderExtension& rhs);
   RTPHeaderExtension& operator=(const RTPHeaderExtension& rhs);
 
   bool hasTransmissionTimeOffset;
   int32_t transmissionTimeOffset;
   bool hasAbsoluteSendTime;
@@ -840,19 +880,21 @@ struct RTPHeaderExtension {
   // For Coordination of Video Orientation. See
   // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
   // ts_126114v120700p.pdf
   bool hasVideoRotation;
   VideoRotation videoRotation;
 
   PlayoutDelay playout_delay = {-1, -1};
 
-  // RID values for simulcast; see draft-roach-avtext-rid
-  bool hasRID;
-  std::unique_ptr<char[]> rid; // UTF8 string
+  // For identification of a stream when ssrc is not signaled. See
+  // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
+  // TODO(danilchap): Update url from draft to release version.
+  StreamId rtpStreamId;
+  StreamId repairedStreamId;
 };
 
 struct RTPHeader {
   RTPHeader();
 
   bool markerBit;
   uint8_t payloadType;
   uint16_t sequenceNumber;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/flexfec_sender.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/flexfec_sender.h
@@ -33,16 +33,17 @@ class RtpPacketToSend;
 // synchronization.
 
 class FlexfecSender {
  public:
   FlexfecSender(int payload_type,
                 uint32_t ssrc,
                 uint32_t protected_media_ssrc,
                 const std::vector<RtpExtension>& rtp_header_extensions,
+                rtc::ArrayView<const RtpExtensionSize> extension_sizes,
                 Clock* clock);
   ~FlexfecSender();
 
   uint32_t ssrc() const { return ssrc_; }
 
   // Sets the FEC rate, max frames sent before FEC packets are sent,
   // and what type of generator matrices are used.
   void SetFecParameters(const FecProtectionParams& params);
@@ -74,13 +75,14 @@ class FlexfecSender {
   const uint32_t ssrc_;
   const uint32_t protected_media_ssrc_;
   // Sequence number of next packet to generate.
   uint16_t seq_num_;
 
   // Implementation.
   UlpfecGenerator ulpfec_generator_;
   const RtpHeaderExtensionMap rtp_header_extension_map_;
+  const size_t header_extensions_size_;
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -71,17 +71,18 @@ enum RTPExtensionType {
   kRtpExtensionNone,
   kRtpExtensionTransmissionTimeOffset,
   kRtpExtensionAudioLevel,
   kRtpExtensionAbsoluteSendTime,
   kRtpExtensionVideoRotation,
   kRtpExtensionTransportSequenceNumber,
   kRtpExtensionPlayoutDelay,
   kRtpExtensionRtpStreamId,
-  kRtpExtensionNumberOfExtensions,
+  kRtpExtensionRepairedRtpStreamId,
+  kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
 };
 
 enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
 
 // TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
 enum RTCPPacketType : uint32_t {
   kRtcpReport = 0x0001,
   kRtcpSr = 0x0002,
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc
@@ -59,29 +59,32 @@ RtpHeaderExtensionMap RegisterBweExtensi
 
 }  // namespace
 
 FlexfecSender::FlexfecSender(
     int payload_type,
     uint32_t ssrc,
     uint32_t protected_media_ssrc,
     const std::vector<RtpExtension>& rtp_header_extensions,
+    rtc::ArrayView<const RtpExtensionSize> extension_sizes,
     Clock* clock)
     : clock_(clock),
       random_(clock_->TimeInMicroseconds()),
       last_generated_packet_ms_(-1),
       payload_type_(payload_type),
       // Initialize the timestamp offset and RTP sequence numbers randomly.
       // (This is not intended to be cryptographically strong.)
       timestamp_offset_(random_.Rand<uint32_t>()),
       ssrc_(ssrc),
       protected_media_ssrc_(protected_media_ssrc),
       seq_num_(random_.Rand(1, kMaxInitRtpSeqNumber)),
       ulpfec_generator_(ForwardErrorCorrection::CreateFlexfec()),
-      rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)) {
+      rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)),
+      header_extensions_size_(
+          rtp_header_extension_map_.GetTotalLengthInBytes(extension_sizes)) {
   // This object should not have been instantiated if FlexFEC is disabled.
   RTC_DCHECK_GE(payload_type, 0);
   RTC_DCHECK_LE(payload_type, 127);
 }
 
 FlexfecSender::~FlexfecSender() = default;
 
 // We are reusing the implementation from UlpfecGenerator for SetFecParameters,
@@ -143,13 +146,12 @@ std::vector<std::unique_ptr<RtpPacketToS
     last_generated_packet_ms_ = now_ms;
   }
 
   return fec_packets_to_send;
 }
 
 // The overhead is BWE RTP header extensions and FlexFEC header.
 size_t FlexfecSender::MaxPacketOverhead() const {
-  return rtp_header_extension_map_.GetTotalLengthInBytes() +
-         kFlexfecMaxHeaderSize;
+  return header_extensions_size_ + kFlexfecMaxHeaderSize;
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
@@ -11,30 +11,34 @@
 #include <vector>
 
 #include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/test/gtest.h"
 
 namespace webrtc {
 
 namespace {
 
+using RtpUtility::Word32Align;
 using test::fec::AugmentedPacket;
 using test::fec::AugmentedPacketGenerator;
 
 constexpr int kFlexfecPayloadType = 123;
 constexpr uint32_t kMediaSsrc = 1234;
 constexpr uint32_t kFlexfecSsrc = 5678;
 const std::vector<RtpExtension> kNoRtpHeaderExtensions;
+const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes;
 // Assume a single protected media SSRC.
 constexpr size_t kFlexfecMaxHeaderSize = 32;
 constexpr size_t kPayloadLength = 50;
 
 constexpr int64_t kInitialSimulatedClockTime = 1;
 // These values are deterministically given by the PRNG, due to our fixed seed.
 // They should be updated if the PRNG implementation changes.
 constexpr uint16_t kDeterministicSequenceNumber = 28732;
@@ -68,35 +72,38 @@ std::unique_ptr<RtpPacketToSend> Generat
   return std::move(fec_packets.front());
 }
 
 }  // namespace
 
 TEST(FlexfecSenderTest, Ssrc) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_EQ(kFlexfecSsrc, sender.ssrc());
 }
 
 TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_FALSE(sender.FecAvailable());
   auto fec_packets = sender.GetFecPackets();
   EXPECT_EQ(0U, fec_packets.size());
 }
 
 TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size());
   EXPECT_FALSE(fec_packet->Marker());
   EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType());
   EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber());
   EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp());
   EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc());
@@ -108,17 +115,18 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   FecProtectionParams params;
   params.fec_rate = 15;
   params.max_fec_frames = 2;
   params.fec_mask_type = kFecMaskRandom;
   constexpr size_t kNumFrames = 2;
   constexpr size_t kNumPacketsPerFrame = 2;
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   sender.SetFecParameters(params);
 
   AugmentedPacketGenerator packet_generator(kMediaSsrc);
   for (size_t i = 0; i < kNumFrames; ++i) {
     packet_generator.NewFrame(kNumPacketsPerFrame);
     for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
       std::unique_ptr<AugmentedPacket> packet =
           packet_generator.NextPacket(i, kPayloadLength);
@@ -147,17 +155,18 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   FecProtectionParams params;
   params.fec_rate = 30;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
   constexpr size_t kNumFrames = 2;
   constexpr size_t kNumPacketsPerFrame = 2;
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   sender.SetFecParameters(params);
 
   AugmentedPacketGenerator packet_generator(kMediaSsrc);
   for (size_t i = 0; i < kNumFrames; ++i) {
     packet_generator.NewFrame(kNumPacketsPerFrame);
     for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
       std::unique_ptr<AugmentedPacket> packet =
           packet_generator.NextPacket(i, kPayloadLength);
@@ -182,79 +191,106 @@ TEST(FlexfecSenderTest, ProtectTwoFrames
   }
 }
 
 // In the tests, we only consider RTP header extensions that are useful for BWE.
 TEST(FlexfecSenderTest, NoRtpHeaderExtensionsForBweByDefault) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kAbsSendTimeUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kTimestampOffsetUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kTransportSequenceNumberUri, 1}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) {
   const std::vector<RtpExtension> kRtpHeaderExtensions{
       {RtpExtension::kAbsSendTimeUri, 1},
       {RtpExtension::kTimestampOffsetUri, 2},
       {RtpExtension::kTransportSequenceNumberUri, 3}};
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kRtpHeaderExtensions, &clock);
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
   auto fec_packet = GenerateSingleFlexfecPacket(&sender);
 
   EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
   EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
   EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
 }
 
 TEST(FlexfecSenderTest, MaxPacketOverhead) {
   SimulatedClock clock(kInitialSimulatedClockTime);
   FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                       kNoRtpHeaderExtensions, &clock);
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &clock);
 
   EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead());
 }
 
+TEST(FlexfecSenderTest, MaxPacketOverheadWithExtensions) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kAbsSendTimeUri, 1},
+      {RtpExtension::kTimestampOffsetUri, 2},
+      {RtpExtension::kTransportSequenceNumberUri, 3}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  const size_t kExtensionHeaderLength = 1;
+  const size_t kRtpOneByteHeaderLength = 4;
+  const size_t kExtensionsTotalSize = Word32Align(
+      kRtpOneByteHeaderLength +
+      kExtensionHeaderLength + AbsoluteSendTime::kValueSizeBytes +
+      kExtensionHeaderLength + TransmissionOffset::kValueSizeBytes +
+      kExtensionHeaderLength + TransportSequenceNumber::kValueSizeBytes);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                       kRtpHeaderExtensions, RTPSender::FecExtensionSizes(),
+                       &clock);
+
+  EXPECT_EQ(kExtensionsTotalSize + kFlexfecMaxHeaderSize,
+            sender.MaxPacketOverhead());
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -18,113 +18,107 @@
 
 namespace webrtc {
 namespace {
 
 using RtpUtility::Word32Align;
 
 struct ExtensionInfo {
   RTPExtensionType type;
-  size_t value_size;
   const char* uri;
 };
 
 template <typename Extension>
 constexpr ExtensionInfo CreateExtensionInfo() {
-  return {Extension::kId, Extension::kValueSizeBytes, Extension::kUri};
+  return {Extension::kId, Extension::kUri};
 }
 
 constexpr ExtensionInfo kExtensions[] = {
     CreateExtensionInfo<TransmissionOffset>(),
     CreateExtensionInfo<AudioLevel>(),
     CreateExtensionInfo<AbsoluteSendTime>(),
     CreateExtensionInfo<VideoOrientation>(),
     CreateExtensionInfo<TransportSequenceNumber>(),
     CreateExtensionInfo<PlayoutDelayLimits>(),
-    CreateExtensionInfo<StreamId>(),
+    CreateExtensionInfo<RtpStreamId>(),
+    CreateExtensionInfo<RepairedRtpStreamId>(),
 };
 
 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
 // number of known extensions.
 static_assert(arraysize(kExtensions) ==
                   static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
               "kExtensions expect to list all known extensions");
 
-size_t ValueSize(RTPExtensionType type) {
-  for (const ExtensionInfo& extension : kExtensions)
-    if (type == extension.type)
-      return extension.value_size;
-
-  RTC_NOTREACHED();
-  return 0;
-}
-
 }  // namespace
 
 constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType;
 constexpr uint8_t RtpHeaderExtensionMap::kInvalidId;
 constexpr uint8_t RtpHeaderExtensionMap::kMinId;
 constexpr uint8_t RtpHeaderExtensionMap::kMaxId;
 
 RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
-  total_values_size_bytes_ = 0;
   for (auto& type : types_)
     type = kInvalidType;
   for (auto& id : ids_)
     id = kInvalidId;
 }
 
 RtpHeaderExtensionMap::RtpHeaderExtensionMap(
     rtc::ArrayView<const RtpExtension> extensions)
     : RtpHeaderExtensionMap() {
   for (const RtpExtension& extension : extensions)
     RegisterByUri(extension.id, extension.uri);
 }
 
 bool RtpHeaderExtensionMap::RegisterByType(uint8_t id, RTPExtensionType type) {
   for (const ExtensionInfo& extension : kExtensions)
     if (type == extension.type)
-      return Register(id, extension.type, extension.value_size, extension.uri);
+      return Register(id, extension.type, extension.uri);
   RTC_NOTREACHED();
   return false;
 }
 
 bool RtpHeaderExtensionMap::RegisterByUri(uint8_t id, const std::string& uri) {
   for (const ExtensionInfo& extension : kExtensions)
     if (uri == extension.uri)
-      return Register(id, extension.type, extension.value_size, extension.uri);
+      return Register(id, extension.type, extension.uri);
   LOG(LS_WARNING) << "Unknown extension uri:'" << uri
                   << "', id: " << static_cast<int>(id) << '.';
   return false;
 }
 
-size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
-  if (total_values_size_bytes_ == 0)
+size_t RtpHeaderExtensionMap::GetTotalLengthInBytes(
+    rtc::ArrayView<const RtpExtensionSize> extensions) const {
+  // Header size of each individual extension, see RFC5285 Section 4.2
+  static constexpr size_t kExtensionHeaderLength = 1;
+  size_t values_size = 0;
+  for (const RtpExtensionSize& extension : extensions) {
+    if (IsRegistered(extension.type))
+      values_size += extension.value_size + kExtensionHeaderLength;
+  }
+  if (values_size == 0)
     return 0;
-  return Word32Align(kRtpOneByteHeaderLength + total_values_size_bytes_);
+  return Word32Align(kRtpOneByteHeaderLength + values_size);
 }
 
 int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) {
   if (IsRegistered(type)) {
     uint8_t id = GetId(type);
-    total_values_size_bytes_ -= (ValueSize(type) + 1);
     types_[id] = kInvalidType;
     ids_[type] = kInvalidId;
   }
   return 0;
 }
 
 bool RtpHeaderExtensionMap::Register(uint8_t id,
                                      RTPExtensionType type,
-                                     size_t value_size,
                                      const char* uri) {
   RTC_DCHECK_GT(type, kRtpExtensionNone);
   RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
-  RTC_DCHECK_GE(value_size, 1U);
-  RTC_DCHECK_LE(value_size, 16U);
 
   if (id < kMinId || id > kMaxId) {
     LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
                     << "' with invalid id:" << static_cast<int>(id) << ".";
     return false;
   }
 
   if (GetType(id) == type) {  // Same type/id pair already registered.
@@ -139,13 +133,12 @@ bool RtpHeaderExtensionMap::Register(uin
                     << ". Id already in use by extension type "
                     << static_cast<int>(GetType(id));
     return false;
   }
   RTC_DCHECK(!IsRegistered(type));
 
   types_[id] = type;
   ids_[type] = id;
-  total_values_size_bytes_ += (value_size + 1);
   return true;
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -17,46 +17,41 @@
 #include "webrtc/base/basictypes.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/config.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 
 namespace webrtc {
 
 const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
-
 const size_t kRtpOneByteHeaderLength = 4;
-const size_t kTransmissionTimeOffsetLength = 4;
-const size_t kAudioLevelLength = 2;
-const size_t kAbsoluteSendTimeLength = 4;
-const size_t kVideoRotationLength = 2;
-const size_t kTransportSequenceNumberLength = 3;
-const size_t kPlayoutDelayLength = 4;
-// kRtpStreamIdLength is variable
-const size_t kRtpStreamIdLength = 4; // max 1-byte header extension length
 
 // Playout delay in milliseconds. A playout delay limit (min or max)
 // has 12 bits allocated. This allows a range of 0-4095 values which translates
 // to a range of 0-40950 in milliseconds.
 const int kPlayoutDelayGranularityMs = 10;
 // Maximum playout delay value in milliseconds.
 const int kPlayoutDelayMaxMs = 40950;
 
+struct RtpExtensionSize {
+  RTPExtensionType type;
+  uint8_t value_size;
+};
+
 class RtpHeaderExtensionMap {
  public:
   static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
   static constexpr uint8_t kInvalidId = 0;
 
   RtpHeaderExtensionMap();
   explicit RtpHeaderExtensionMap(rtc::ArrayView<const RtpExtension> extensions);
 
   template <typename Extension>
   bool Register(uint8_t id) {
-    return Register(id, Extension::kId, Extension::kValueSizeBytes,
-                    Extension::kUri);
+    return Register(id, Extension::kId, Extension::kUri);
   }
   bool RegisterByType(uint8_t id, RTPExtensionType type);
   bool RegisterByUri(uint8_t id, const std::string& uri);
 
   bool IsRegistered(RTPExtensionType type) const {
     return GetId(type) != kInvalidId;
   }
   // Return kInvalidType if not found.
@@ -67,33 +62,30 @@ class RtpHeaderExtensionMap {
   }
   // Return kInvalidId if not found.
   uint8_t GetId(RTPExtensionType type) const {
     RTC_DCHECK_GT(type, kRtpExtensionNone);
     RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
     return ids_[type];
   }
 
-  size_t GetTotalLengthInBytes() const;
+  size_t GetTotalLengthInBytes(
+      rtc::ArrayView<const RtpExtensionSize> extensions) const;
 
   // TODO(danilchap): Remove use of the functions below.
   int32_t Register(RTPExtensionType type, uint8_t id) {
     return RegisterByType(id, type) ? 0 : -1;
   }
   int32_t Deregister(RTPExtensionType type);
 
  private:
   static constexpr uint8_t kMinId = 1;
   static constexpr uint8_t kMaxId = 14;
-  bool Register(uint8_t id,
-                RTPExtensionType type,
-                size_t value_size,
-                const char* uri);
+  bool Register(uint8_t id, RTPExtensionType type, const char* uri);
 
-  size_t total_values_size_bytes_ = 0;
   RTPExtensionType types_[kMaxId + 1];
   uint8_t ids_[kRtpExtensionNumberOfExtensions];
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSION_H_
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension_unittest.cc
@@ -80,20 +80,22 @@ TEST(RtpHeaderExtensionTest, NonUniqueId
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
   EXPECT_FALSE(map.Register<AudioLevel>(3));
   EXPECT_TRUE(map.Register<AudioLevel>(4));
 }
 
 TEST(RtpHeaderExtensionTest, GetTotalLength) {
   RtpHeaderExtensionMap map;
-  EXPECT_EQ(0u, map.GetTotalLengthInBytes());
+  constexpr RtpExtensionSize kExtensionSizes[] = {
+      {TransmissionOffset::kId, TransmissionOffset::kValueSizeBytes}};
+  EXPECT_EQ(0u, map.GetTotalLengthInBytes(kExtensionSizes));
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
   EXPECT_EQ(kRtpOneByteHeaderLength + (TransmissionOffset::kValueSizeBytes + 1),
-            map.GetTotalLengthInBytes());
+            map.GetTotalLengthInBytes(kExtensionSizes));
 }
 
 TEST(RtpHeaderExtensionTest, GetType) {
   RtpHeaderExtensionMap map;
   EXPECT_EQ(RtpHeaderExtensionMap::kInvalidType, map.GetType(3));
   EXPECT_TRUE(map.Register<TransmissionOffset>(3));
 
   EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -30,23 +30,27 @@ namespace webrtc {
 //    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               |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType AbsoluteSendTime::kId;
 constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
 constexpr const char* AbsoluteSendTime::kUri;
 
-bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* time_24bits) {
-  *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint32_t* time_24bits) {
+  if (data.size() != 3)
+    return false;
+  *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
   return true;
 }
 
-bool AbsoluteSendTime::Write(uint8_t* data, int64_t time_ms) {
-  ByteWriter<uint32_t, 3>::WriteBigEndian(data, MsTo24Bits(time_ms));
+bool AbsoluteSendTime::Write(uint8_t* data, uint32_t time_24bits) {
+  RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
+  ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24bits);
   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:
@@ -56,19 +60,21 @@ bool AbsoluteSendTime::Write(uint8_t* da
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //   |  ID   | len=0 |V|   level     |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //
 constexpr RTPExtensionType AudioLevel::kId;
 constexpr uint8_t AudioLevel::kValueSizeBytes;
 constexpr const char* AudioLevel::kUri;
 
-bool AudioLevel::Parse(const uint8_t* data,
+bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
                        bool* voice_activity,
                        uint8_t* audio_level) {
+  if (data.size() != 1)
+    return false;
   *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) {
@@ -92,18 +98,21 @@ bool AudioLevel::Write(uint8_t* data,
 //    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              |
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransmissionOffset::kId;
 constexpr uint8_t TransmissionOffset::kValueSizeBytes;
 constexpr const char* TransmissionOffset::kUri;
 
-bool TransmissionOffset::Parse(const uint8_t* data, int32_t* rtp_time) {
-  *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data);
+bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
+                               int32_t* rtp_time) {
+  if (data.size() != 3)
+    return false;
+  *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
   return true;
 }
 
 bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) {
   RTC_DCHECK_LE(rtp_time, 0x00ffffff);
   ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time);
   return true;
 }
@@ -112,18 +121,21 @@ bool TransmissionOffset::Write(uint8_t* 
 //   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 |
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType TransportSequenceNumber::kId;
 constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
 constexpr const char* TransportSequenceNumber::kUri;
 
-bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) {
-  *value = ByteReader<uint16_t>::ReadBigEndian(data);
+bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
+                                    uint16_t* value) {
+  if (data.size() != 2)
+    return false;
+  *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
   return true;
 }
 
 bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
   ByteWriter<uint16_t>::WriteBigEndian(data, value);
   return true;
 }
 
@@ -137,27 +149,33 @@ bool TransportSequenceNumber::Write(uint
 //    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|
 //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType VideoOrientation::kId;
 constexpr uint8_t VideoOrientation::kValueSizeBytes;
 constexpr const char* VideoOrientation::kUri;
 
-bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) {
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             VideoRotation* rotation) {
+  if (data.size() != 1)
+    return false;
   *rotation = ConvertCVOByteToVideoRotation(data[0]);
   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) {
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint8_t* value) {
+  if (data.size() != 1)
+    return false;
   *value = data[0];
   return true;
 }
 
 bool VideoOrientation::Write(uint8_t* data, uint8_t value) {
   data[0] = value;
   return true;
 }
@@ -166,20 +184,22 @@ bool VideoOrientation::Write(uint8_t* da
 //   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 |   MIN delay           |   MAX delay           |
 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 constexpr RTPExtensionType PlayoutDelayLimits::kId;
 constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
 constexpr const char* PlayoutDelayLimits::kUri;
 
-bool PlayoutDelayLimits::Parse(const uint8_t* data,
+bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
                                PlayoutDelay* playout_delay) {
   RTC_DCHECK(playout_delay);
-  uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+  if (data.size() != 3)
+    return false;
+  uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
   uint16_t min_raw = (raw >> 12);
   uint16_t max_raw = (raw & 0xfff);
   if (min_raw > max_raw)
     return false;
   playout_delay->min_ms = min_raw * kGranularityMs;
   playout_delay->max_ms = max_raw * kGranularityMs;
   return true;
 }
@@ -191,40 +211,81 @@ bool PlayoutDelayLimits::Write(uint8_t* 
   RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
   // Convert MS to value to be sent on extension header.
   uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
   uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
   ByteWriter<uint32_t, 3>::WriteBigEndian(data, (min_delay << 12) | max_delay);
   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=?   |UTF-8 RID value......          |...
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-constexpr RTPExtensionType StreamId::kId;
-constexpr uint8_t StreamId::kValueSizeBytes;
-constexpr const char* StreamId::kUri;
+// RtpStreamId.
+constexpr RTPExtensionType RtpStreamId::kId;
+constexpr const char* RtpStreamId::kUri;
+
+bool RtpStreamId::Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid) {
+  if (data.empty() || data[0] == 0 ||  // Valid rsid can't be empty.
+      data.size() <= StreamId::kMaxSize) // mozilla
+    return false;
+  // If there is a \0 character in the middle of the |data|, it will be treated
+  // as the end of the StreamId when StreamId::size() is called.
+  rsid->Set(data);
+  RTC_DCHECK(!rsid->empty());
+  return true;
+}
 
-bool StreamId::Parse(const uint8_t* data, char rid[kRIDSize+1]) {
-  uint8_t len = (data[0] & 0x0F) + 1;
-  memcpy(rid, &data[1], len);
-  rid[len] = '\0';
+bool RtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
+  return true;
+}
+
+bool RtpStreamId::Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid) {
+  if (data.empty() || data[0] == 0 ||  // Valid rsid can't be empty.
+      data.size() <= StreamId::kMaxSize) // mozilla
+    return false;
+  const char* str = reinterpret_cast<const char*>(data.data());
+  // If there is a \0 character in the middle of the |data|, treat it as end of
+  // the string. Well-formed rsid shouldn't contain it.
+  rsid->assign(str, strnlen(str, data.size()));
+  RTC_DCHECK(!rsid->empty());
   return true;
 }
 
-bool StreamId::Write(uint8_t* data, const char *rid) {
-  // XXX FIX!  how to get it to modify the length?  data points to the RID value
-  int len = strlen(rid);
-  RTC_DCHECK(len > 0 && len <= 16);
-  if (len > 16) {
-    len = 16;
-  } else if (len == 0) {
-    // really bad, but don't blow up
-    rid = "x";
-    len = 1;
-  }
-  memcpy(data, rid, len);
+bool RtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  RTC_DCHECK_GE(rsid.size(), 1);
+  RTC_DCHECK_LE(rsid.size(), StreamId::kMaxSize);
+  memcpy(data, rsid.data(), rsid.size());
   return true;
 }
 
+// RepairedRtpStreamId.
+constexpr RTPExtensionType RepairedRtpStreamId::kId;
+constexpr const char* RepairedRtpStreamId::kUri;
+
+// RtpStreamId and RepairedRtpStreamId use the same format to store rsid.
+bool RepairedRtpStreamId::Parse(rtc::ArrayView<const uint8_t> data,
+                                StreamId* rsid) {
+  return RtpStreamId::Parse(data, rsid);
+}
+
+size_t RepairedRtpStreamId::ValueSize(const StreamId& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const StreamId& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
+bool RepairedRtpStreamId::Parse(rtc::ArrayView<const uint8_t> data,
+                                std::string* rsid) {
+  return RtpStreamId::Parse(data, rsid);
+}
+
+size_t RepairedRtpStreamId::ValueSize(const std::string& rsid) {
+  return RtpStreamId::ValueSize(rsid);
+}
+
+bool RepairedRtpStreamId::Write(uint8_t* data, const std::string& rsid) {
+  return RtpStreamId::Write(data, rsid);
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -20,67 +20,75 @@ namespace webrtc {
 
 class AbsoluteSendTime {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
   static constexpr uint8_t kValueSizeBytes = 3;
   static constexpr const char* kUri =
       "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
 
-  static bool Parse(const uint8_t* data, uint32_t* time_24bits);
-  static bool Write(uint8_t* data, int64_t time_ms);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits);
+  static size_t ValueSize(uint32_t time_24bits) { return kValueSizeBytes; }
+  static bool Write(uint8_t* data, uint32_t time_24bits);
 
   static constexpr uint32_t MsTo24Bits(int64_t time_ms) {
     return static_cast<uint32_t>(((time_ms << 18) + 500) / 1000) & 0x00FFFFFF;
   }
 };
 
 class AudioLevel {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
   static constexpr uint8_t kValueSizeBytes = 1;
   static constexpr const char* kUri =
       "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
 
-  static bool Parse(const uint8_t* data,
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
                     bool* voice_activity,
                     uint8_t* audio_level);
+  static size_t ValueSize(bool voice_activity, uint8_t audio_level) {
+    return kValueSizeBytes;
+  }
   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 constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:toffset";
 
-  static bool Parse(const uint8_t* data, int32_t* rtp_time);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time);
+  static size_t ValueSize(int32_t rtp_time) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, int32_t rtp_time);
 };
 
 class TransportSequenceNumber {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
   static constexpr uint8_t kValueSizeBytes = 2;
   static constexpr const char* kUri =
       "http://www.ietf.org/id/"
       "draft-holmer-rmcat-transport-wide-cc-extensions-01";
-  static bool Parse(const uint8_t* data, uint16_t* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value);
+  static size_t ValueSize(uint16_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint16_t value);
 };
 
 class VideoOrientation {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
   static constexpr uint8_t kValueSizeBytes = 1;
   static constexpr const char* kUri = "urn:3gpp:video-orientation";
 
-  static bool Parse(const uint8_t* data, VideoRotation* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* value);
+  static size_t ValueSize(VideoRotation) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, VideoRotation value);
-  static bool Parse(const uint8_t* data, uint8_t* value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value);
+  static size_t ValueSize(uint8_t value) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, uint8_t value);
 };
 
 class PlayoutDelayLimits {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionPlayoutDelay;
   static constexpr uint8_t kValueSizeBytes = 3;
   static constexpr const char* kUri =
@@ -88,24 +96,46 @@ class PlayoutDelayLimits {
 
   // Playout delay in milliseconds. A playout delay limit (min or max)
   // has 12 bits allocated. This allows a range of 0-4095 values which
   // translates to a range of 0-40950 in milliseconds.
   static constexpr int kGranularityMs = 10;
   // Maximum playout delay value in milliseconds.
   static constexpr int kMaxMs = 0xfff * kGranularityMs;  // 40950.
 
-  static bool Parse(const uint8_t* data, PlayoutDelay* playout_delay);
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    PlayoutDelay* playout_delay);
+  static size_t ValueSize(const PlayoutDelay&) { return kValueSizeBytes; }
   static bool Write(uint8_t* data, const PlayoutDelay& playout_delay);
 };
 
-class StreamId {
+class RtpStreamId {
  public:
   static constexpr RTPExtensionType kId = kRtpExtensionRtpStreamId;
-  static constexpr uint8_t kValueSizeBytes = 1; // variable! we add the RID length to this
-  static constexpr const char* kUri = "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid) { return rsid.size(); }
+  static bool Write(uint8_t* data, const std::string& rsid);
+};
 
-  static bool Parse(const uint8_t* data, char rid[kRIDSize+1]);
-  static bool Write(uint8_t* data, const char *rid); // 1-16 bytes
+class RepairedRtpStreamId {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionRepairedRtpStreamId;
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* rsid);
+  static size_t ValueSize(const StreamId& rsid);
+  static bool Write(uint8_t* data, const StreamId& rsid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
+  static size_t ValueSize(const std::string& rsid);
+  static bool Write(uint8_t* data, const std::string& rsid);
 };
 
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -13,28 +13,33 @@
 #include <cstring>
 #include <utility>
 
 #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/byte_io.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
+
+constexpr size_t Packet::kMaxExtensionHeaders;
+constexpr int Packet::kMinExtensionId;
+constexpr int Packet::kMaxExtensionId;
+
 //  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            |
@@ -52,16 +57,18 @@ constexpr size_t kDefaultPacketSize = 15
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 // |               padding         | Padding size  |
 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
 
 Packet::Packet(const ExtensionManager* extensions)
     : Packet(extensions, kDefaultPacketSize) {}
 
+Packet::Packet(const Packet&) = default;
+
 Packet::Packet(const ExtensionManager* extensions, size_t capacity)
     : buffer_(capacity) {
   RTC_DCHECK_GE(capacity, kFixedHeaderSize);
   Clear();
   if (extensions) {
     IdentifyExtensions(*extensions);
   } else {
     for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
@@ -159,16 +166,19 @@ void Packet::GetHeader(RTPHeader* header
       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);
+  GetExtension<RtpStreamId>(&header->extension.rtpStreamId);
+  GetExtension<RepairedRtpStreamId>(&header->extension.repairedStreamId);
+  GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
 }
 
 size_t Packet::headers_size() const {
   return payload_offset_;
 }
 
 size_t Packet::payload_size() const {
   return payload_size_;
@@ -268,37 +278,131 @@ void Packet::SetCsrcs(const std::vector<
   size_t offset = kFixedHeaderSize;
   for (uint32_t csrc : csrcs) {
     ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
     offset += 4;
   }
   buffer_.SetSize(payload_offset_);
 }
 
+bool Packet::HasRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return false;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  return extension_entries_[id - 1].offset != 0;
+}
+
+rtc::ArrayView<const uint8_t> Packet::GetRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  const ExtensionInfo& extension = extension_entries_[id - 1];
+  if (extension.offset == 0)
+    return nullptr;
+  return rtc::MakeArrayView(data() + extension.offset, extension.length);
+}
+
+bool Packet::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
+  auto buffer = AllocateRawExtension(id, data.size());
+  if (buffer.empty())
+    return false;
+  RTC_DCHECK_EQ(buffer.size(), data.size());
+  memcpy(buffer.data(), data.data(), data.size());
+  return true;
+}
+
+rtc::ArrayView<uint8_t> Packet::AllocateRawExtension(int id, size_t length) {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  RTC_DCHECK_GE(length, 1);
+  RTC_DCHECK_LE(length, 16);
+
+  ExtensionInfo* extension_entry = &extension_entries_[id - 1];
+  if (extension_entry->offset != 0) {
+    // Extension already reserved. Check if same length is used.
+    if (extension_entry->length == length)
+      return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+
+    LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
+                  << static_cast<int>(extension_entry->type) << ": expected "
+                  << static_cast<int>(extension_entry->length) << ". received "
+                  << length;
+    return nullptr;
+  }
+  if (payload_size_ > 0) {
+    LOG(LS_ERROR) << "Can't add new extension id " << id
+                  << " after payload was set.";
+    return nullptr;
+  }
+  if (padding_size_ > 0) {
+    LOG(LS_ERROR) << "Can't add new extension id " << id
+                  << " after padding was set.";
+    return nullptr;
+  }
+
+  size_t num_csrc = data()[0] & 0x0F;
+  size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+  size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
+  if (extensions_offset + new_extensions_size > capacity()) {
+    LOG(LS_ERROR)
+        << "Extension cannot be registered: Not enough space left in buffer.";
+    return nullptr;
+  }
+
+  // All checks passed, write down the extension headers.
+  if (extensions_size_ == 0) {
+    RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
+    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_, (id << 4) | (length - 1));
+
+  extension_entry->offset =
+      extensions_offset + extensions_size_ + kOneByteHeaderSize;
+  extension_entry->length = length;
+  extensions_size_ = new_extensions_size;
+
+  // Update header length field.
+  uint16_t extensions_words = (extensions_size_ + 3) / 4;  // Wrap up to 32bit.
+  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;
+  buffer_.SetSize(payload_offset_);
+  return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+}
+
 uint8_t* Packet::AllocatePayload(size_t size_bytes) {
+  // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
+  // reallocation and memcpy. Keeping just header reduces memcpy size.
+  SetPayloadSize(0);
+  return SetPayloadSize(size_bytes);
+}
+
+uint8_t* Packet::SetPayloadSize(size_t size_bytes) {
   RTC_DCHECK_EQ(padding_size_, 0);
   if (payload_offset_ + size_bytes > capacity()) {
     LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
     return nullptr;
   }
-  // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
-  // reallocation and memcpy. Setting size to just headers reduces memcpy size.
-  buffer_.SetSize(payload_offset_);
   payload_size_ = size_bytes;
   buffer_.SetSize(payload_offset_ + payload_size_);
   return WriteAt(payload_offset_);
 }
 
-void Packet::SetPayloadSize(size_t size_bytes) {
-  RTC_DCHECK_EQ(padding_size_, 0);
-  RTC_DCHECK_LE(size_bytes, payload_size_);
-  payload_size_ = size_bytes;
-  buffer_.SetSize(payload_offset_ + payload_size_);
-}
-
 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;
   }
@@ -435,119 +539,39 @@ bool Packet::ParseBuffer(const uint8_t* 
 
   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);
+rtc::ArrayView<const uint8_t> Packet::FindExtension(ExtensionType type) const {
   for (const ExtensionInfo& extension : extension_entries_) {
     if (extension.type == type) {
       if (extension.length == 0) {
         // Extension is registered but not set.
-        return false;
-      }
-      if (length != extension.length) {
-        LOG(LS_WARNING) << "Length mismatch for extension '" << type
-                        << "': expected " << static_cast<int>(length)
-                        << ", received " << static_cast<int>(extension.length);
-        return false;
+        return nullptr;
       }
-      *offset = extension.offset;
-      return true;
-    }
-  }
-  return false;
-}
-
-bool Packet::AllocateExtension(ExtensionType type,
-                               uint8_t length,
-                               uint16_t* offset) {
-  uint8_t extension_id = ExtensionManager::kInvalidId;
-  ExtensionInfo* extension_entry = nullptr;
-  for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
-    if (extension_entries_[i].type == type) {
-      extension_id = i + 1;
-      extension_entry = &extension_entries_[i];
-      break;
+      return rtc::MakeArrayView(data() + extension.offset, extension.length);
     }
   }
-
-  if (!extension_entry)  // Extension not registered.
-    return false;
-
-  if (extension_entry->length != 0) {  // Already allocated.
-    if (length != extension_entry->length) {
-      LOG(LS_WARNING) << "Length mismatch for extension '" << type
-                      << "': expected " << static_cast<int>(length)
-                      << ", received "
-                      << static_cast<int>(extension_entry->length);
-      return false;
-    }
-    *offset = extension_entry->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;
-  }
-
-  RTC_DCHECK_GT(length, 0);
-  RTC_DCHECK_LE(length, 16);
+  return nullptr;
+}
 
-  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;
+rtc::ArrayView<uint8_t> Packet::AllocateExtension(ExtensionType type,
+                                                  size_t length) {
+  for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
+    if (extension_entries_[i].type == type) {
+      int extension_id = i + 1;
+      return AllocateRawExtension(extension_id, length);
+    }
   }
-
-  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 (extensions_size_ == 0) {
-    RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
-    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));
-
-  extension_entry->length = length;
-  *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
-  extension_entry->offset = *offset;
-  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;
-  buffer_.SetSize(payload_offset_);
-  return true;
+  // Extension not registered.
+  return nullptr;
 }
 
 uint8_t* Packet::WriteAt(size_t offset) {
   return buffer_.data() + offset;
 }
 
 void Packet::WriteAt(size_t offset, uint8_t byte) {
   buffer_.data()[offset] = byte;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.h
@@ -23,16 +23,18 @@ class RtpHeaderExtensionMap;
 class Random;
 
 namespace rtp {
 class Packet {
  public:
   using ExtensionType = RTPExtensionType;
   using ExtensionManager = RtpHeaderExtensionMap;
   static constexpr size_t kMaxExtensionHeaders = 14;
+  static constexpr int kMinExtensionId = 1;
+  static constexpr int kMaxExtensionId = 14;
 
   // Parse and copy given buffer into Packet.
   bool Parse(const uint8_t* buffer, size_t size);
   bool Parse(rtc::ArrayView<const uint8_t> packet);
 
   // Parse and move given buffer into Packet.
   bool Parse(rtc::CopyOnWriteBuffer packet);
 
@@ -86,67 +88,72 @@ class Packet {
   template <typename Extension>
   bool HasExtension() const;
 
   template <typename Extension, typename... Values>
   bool GetExtension(Values...) const;
 
   template <typename Extension, typename... Values>
   bool SetExtension(Values...);
-  template <typename Extension, typename... Values>
-  bool SetExtensionWithLength(size_t length, Values...);
 
   template <typename Extension>
   bool ReserveExtension();
 
+  // Following 4 helpers identify rtp header extension by |id| negotiated with
+  // remote peer and written in an rtp packet.
+  bool HasRawExtension(int id) const;
+
+  // Returns place where extension with |id| is stored.
+  // Returns empty arrayview if extension is not present.
+  rtc::ArrayView<const uint8_t> GetRawExtension(int id) const;
+
+  // Allocates and store header extension. Returns true on success.
+  bool SetRawExtension(int id, rtc::ArrayView<const uint8_t> data);
+
+  // Allocates and returns place to store rtp header extension.
+  // Returns empty arrayview on failure.
+  rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length);
+
   // Reserve size_bytes for payload. Returns nullptr on failure.
+  uint8_t* SetPayloadSize(size_t size_bytes);
+  // Same as SetPayloadSize but doesn't guarantee to keep current payload.
   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.
   Packet();
   explicit Packet(const ExtensionManager* extensions);
-  Packet(const Packet&) = default;
+  Packet(const Packet&);
   Packet(const ExtensionManager* extensions, size_t capacity);
   virtual ~Packet();
 
   Packet& operator=(const Packet&) = default;
 
  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 an extension |type|.
+  // Returns view of the raw extension or empty view on failure.
+  rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) 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);
+  // Find or allocate an extension |type|. Returns view of size |length|
+  // to write raw extension to or an empty view on failure.
+  rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
 
   uint8_t* WriteAt(size_t offset);
   void WriteAt(size_t offset, uint8_t byte);
 
   // Header.
   bool marker_;
   uint8_t payload_type_;
   uint8_t padding_size_;
@@ -158,48 +165,42 @@ class Packet {
 
   ExtensionInfo extension_entries_[kMaxExtensionHeaders];
   uint16_t extensions_size_ = 0;  // Unaligned.
   rtc::CopyOnWriteBuffer buffer_;
 };
 
 template <typename Extension>
 bool Packet::HasExtension() const {
-  uint16_t offset = 0;
-  return FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset);
+  return !FindExtension(Extension::kId).empty();
 }
 
 template <typename Extension, typename... Values>
 bool Packet::GetExtension(Values... values) const {
-  uint16_t offset = 0;
-  if (!FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  auto raw = FindExtension(Extension::kId);
+  if (raw.empty())
     return false;
-  return Extension::Parse(data() + offset, values...);
+  return Extension::Parse(raw, values...);
 }
 
 template <typename Extension, typename... Values>
 bool Packet::SetExtension(Values... values) {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  const size_t value_size = Extension::ValueSize(values...);
+  if (value_size == 0 || value_size > 16)
     return false;
-  return Extension::Write(WriteAt(offset), values...);
-}
-
-template <typename Extension, typename... Values>
-bool Packet::SetExtensionWithLength(size_t length, Values... values) {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes + length, &offset))
+  auto buffer = AllocateExtension(Extension::kId, value_size);
+  if (buffer.empty())
     return false;
-  return Extension::Write(WriteAt(offset), values...);
+  return Extension::Write(buffer.data(), values...);
 }
 
 template <typename Extension>
 bool Packet::ReserveExtension() {
-  uint16_t offset = 0;
-  if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+  auto buffer = AllocateExtension(Extension::kId, Extension::kValueSizeBytes);
+  if (buffer.empty())
     return false;
-  memset(WriteAt(offset), 0, Extension::kValueSizeBytes);
+  memset(buffer.data(), 0, Extension::kValueSizeBytes);
   return true;
 }
 }  // namespace rtp
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -18,60 +18,74 @@
 
 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 uint16_t kSeqNum = 0x1234;
+constexpr uint8_t kSeqNumFirstByte = kSeqNum >> 8;
+constexpr uint8_t kSeqNumSecondByte = kSeqNum & 0xff;
 constexpr uint32_t kTimestamp = 0x65431278;
 constexpr uint8_t kTransmissionOffsetExtensionId = 1;
 constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr uint8_t kRtpStreamIdExtensionId = 0xa;
 constexpr int32_t kTimeOffset = 0x56ce;
 constexpr bool kVoiceActive = true;
 constexpr uint8_t kAudioLevel = 0x5a;
+constexpr char kStreamId[] = "streamid";
 constexpr size_t kMaxPaddingSize = 224u;
 // clang-format off
 constexpr uint8_t kMinimumPacket[] = {
-    0x80, kPayloadType, 0x00, kSeqNum,
+    0x80, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78};
+
 constexpr uint8_t kPacketWithTO[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x01,
     0x12, 0x00, 0x56, 0xce};
 
 constexpr uint8_t kPacketWithTOAndAL[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x02,
     0x12, 0x00, 0x56, 0xce,
     0x90, 0x80|kAudioLevel, 0x00, 0x00};
 
+constexpr uint8_t kPacketWithRsid[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x03,
+    0xa7, 's',  't',  'r',
+    'e',  'a',  'm',  'i',
+    'd' , 0x00, 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,
+    0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     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};
 
 constexpr uint8_t kPacketWithInvalidExtension[] = {
-    0x90, kPayloadType, 0x00, kSeqNum,
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,  // kTimestamp.
     0x12, 0x34, 0x56, 0x78,  // kSSrc.
     0xbe, 0xde, 0x00, 0x02,  // Extension block of size 2 x 32bit words.
     (kTransmissionOffsetExtensionId << 4) | 6,  // (6+1)-byte extension, but
            'e',  'x',  't',                     // Transmission Offset
      'd',  'a',  't',  'a',                     // expected to be 3-bytes.
      'p',  'a',  'y',  'l',  'o',  'a',  'd'
 };
@@ -111,26 +125,100 @@ TEST(RtpPacketTest, CreateWith2Extension
   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, CreateWithDynamicSizedExtensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<RtpStreamId>(kStreamId);
+  EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
+}
+
+TEST(RtpPacketTest, TryToCreateWithLongRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  constexpr char kLongStreamId[] = "LoooooooooongRsid";
+  ASSERT_EQ(strlen(kLongStreamId), 17u);
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(kLongStreamId));
+}
+
+TEST(RtpPacketTest, CreateWithExtensionsWithoutManager) {
+  RtpPacketToSend packet(nullptr);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+
+  auto raw = packet.AllocateRawExtension(kTransmissionOffsetExtensionId,
+                                         TransmissionOffset::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), TransmissionOffset::kValueSizeBytes);
+  TransmissionOffset::Write(raw.data(), kTimeOffset);
+
+  raw = packet.AllocateRawExtension(kAudioLevelExtensionId,
+                                    AudioLevel::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), AudioLevel::kValueSizeBytes);
+  AudioLevel::Write(raw.data(), kVoiceActive, kAudioLevel);
+
+  EXPECT_THAT(kPacketWithTOAndAL,
+              ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithMaxSizeHeaderExtension) {
+  const size_t kMaxExtensionSize = 16;
+  const int kId = 1;
+  const uint8_t kValue[16] = "123456789abcdef";
+
+  // Write packet with a custom extension.
+  RtpPacketToSend packet(nullptr);
+  packet.SetRawExtension(kId, kValue);
+  // Using different size for same id is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId, kMaxExtensionSize - 1).empty());
+
+  packet.SetPayloadSize(42);
+  // Rewriting allocated extension is allowed.
+  EXPECT_EQ(packet.AllocateRawExtension(kId, kMaxExtensionSize).size(),
+            kMaxExtensionSize);
+  // Adding another extension after payload is set is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId + 1, kMaxExtensionSize).empty());
+
+  // Read packet with the custom extension.
+  RtpPacketReceived parsed;
+  EXPECT_TRUE(parsed.Parse(packet.Buffer()));
+  auto read_raw = parsed.GetRawExtension(kId);
+  EXPECT_THAT(read_raw, ElementsAreArray(kValue, kMaxExtensionSize));
+}
+
 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);
+  packet.SetPayloadSize(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;
@@ -149,17 +237,17 @@ TEST(RtpPacketTest, CreatePurePadding) {
 
 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);
+  packet.SetPayloadSize(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) {
@@ -220,17 +308,17 @@ TEST(RtpPacketTest, ParseWithInvalidSize
 
   // But shouldn't prevent reading payload.
   EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload));
 }
 
 TEST(RtpPacketTest, ParseWithOverSizedExtension) {
   // clang-format off
   const uint8_t bad_packet[] = {
-      0x90, kPayloadType, 0x00, kSeqNum,
+      0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
       0xbe, 0xde, 0x00, 0x01,  // Extension of size 1x32bit word.
       0x00,  // Add a byte of padding.
             0x12,  // Extension id 1 size (2+1).
                   0xda, 0x1a  // Only 2 bytes of extension payload.
   };
   // clang-format on
@@ -295,9 +383,82 @@ TEST(RtpPacketTest, ParseWithExtensionDe
   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());
 }
 
+TEST(RtpPacketTest, ParseWithoutExtensionManager) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kAudioLevelExtensionId));
+  EXPECT_TRUE(packet.GetRawExtension(kAudioLevelExtensionId).empty());
+
+  EXPECT_TRUE(packet.HasRawExtension(kTransmissionOffsetExtensionId));
+
+  int32_t time_offset = 0;
+  auto raw_extension = packet.GetRawExtension(kTransmissionOffsetExtensionId);
+  EXPECT_EQ(raw_extension.size(), TransmissionOffset::kValueSizeBytes);
+  EXPECT_TRUE(TransmissionOffset::Parse(raw_extension, &time_offset));
+
+  EXPECT_EQ(time_offset, kTimeOffset);
+}
+
+TEST(RtpPacketTest, ParseDynamicSizeExtension) {
+  // clang-format off
+  const uint8_t kPacket1[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x78,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x02,  // Extensions block of size 2x32bit words.
+    0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
+    0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
+    0x00};  // Extension padding.
+  const uint8_t kPacket2[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x79,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x01,  // Extensions block of size 1x32bit words.
+    0x11, 'H', 'D',          // Extension with id = 1, size = (1+1).
+    0x00};  // Extension padding.
+  // clang-format on
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(1);
+  extensions.Register<RepairedRtpStreamId>(2);
+  RtpPacketReceived packet(&extensions);
+  ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1)));
+
+  std::string rsid;
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "rtx");
+
+  std::string repaired_rsid;
+  EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+  EXPECT_EQ(repaired_rsid, "HD");
+
+  // Parse another packet with RtpStreamId extension of different size.
+  ASSERT_TRUE(packet.Parse(kPacket2, sizeof(kPacket2)));
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "HD");
+  EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+}
+
+TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) {
+  RtpPacketReceived::ExtensionManager extensions;
+  RtpPacketReceived packet(&extensions);
+  // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for
+  // using zero value as a parameter to Packet::*RawExtension functions.
+  const int kInvalidId = extensions.GetId(TransmissionOffset::kId);
+  ASSERT_EQ(kInvalidId, 0);
+
+  ASSERT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kInvalidId));
+  EXPECT_THAT(packet.GetRawExtension(kInvalidId), IsEmpty());
+  const uint8_t kExtension[] = {'e', 'x', 't'};
+  EXPECT_FALSE(packet.SetRawExtension(kInvalidId, kExtension));
+  EXPECT_THAT(packet.AllocateRawExtension(kInvalidId, 3), IsEmpty());
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc
@@ -64,18 +64,17 @@ RtpReceiverImpl::RtpReceiverImpl(
       cb_rtp_feedback_(incoming_messages_callback),
       last_receive_time_(0),
       last_received_payload_length_(0),
       ssrc_(0),
       num_csrcs_(0),
       current_remote_csrc_(),
       last_received_timestamp_(0),
       last_received_frame_time_ms_(-1),
-      last_received_sequence_number_(0),
-      rid_(NULL) {
+      last_received_sequence_number_(0) {
   assert(incoming_messages_callback);
 
   memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_));
 }
 
 RtpReceiverImpl::~RtpReceiverImpl() {
   for (int i = 0; i < num_csrcs_; ++i) {
     cb_rtp_feedback_->OnIncomingCSRCChanged(current_remote_csrc_[i], false);
@@ -124,22 +123,22 @@ int32_t RtpReceiverImpl::CSRCs(uint32_t 
   assert(num_csrcs_ <= kRtpCsrcSize);
 
   if (num_csrcs_ > 0) {
     memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t)*num_csrcs_);
   }
   return num_csrcs_;
 }
 
-void RtpReceiverImpl::GetRID(char rid[256]) const {
+void RtpReceiverImpl::GetRID(char rtp_stream_id[256]) const {
   rtc::CritScope lock(&critical_section_rtp_receiver_);
-  if (rid_) {
-    strncpy(rid, rid_, 256);
+  if (!rtp_stream_id_.empty()) {
+    strncpy(rtp_stream_id, rtp_stream_id_.data(), 256);
   } else {
-    rid[0] = '\0';
+    rtp_stream_id[0] = '\0';
   }
 }
 
 int32_t RtpReceiverImpl::Energy(
     uint8_t array_of_energy[kRtpCsrcSize]) const {
   return rtp_media_receiver_->Energy(array_of_energy);
 }
 
@@ -194,23 +193,21 @@ bool RtpReceiverImpl::IncomingRtpPacket(
 
   {
     rtc::CritScope lock(&critical_section_rtp_receiver_);
 
     last_receive_time_ = clock_->TimeInMilliseconds();
     last_received_payload_length_ = payload_data_length;
 
     // RID rarely if ever changes
-    if (rtp_header.extension.hasRID &&
-        (!rid_ || strcmp(rtp_header.extension.rid.get(), rid_) != 0)) {
-      delete [] rid_;
-      rid_ = new char[strlen(rtp_header.extension.rid.get())+1];
-      strcpy(rid_, rtp_header.extension.rid.get());
-      LOG(LS_INFO) << "Received new RID value: " << rid_;
-  }
+    if (!rtp_header.extension.rtpStreamId.empty() &&
+        (rtp_header.extension.rtpStreamId != rtp_stream_id_)) {
+      rtp_stream_id_ = rtp_header.extension.rtpStreamId;
+      LOG(LS_INFO) << "Received new RID value: " << rtp_stream_id_.data();
+    }
     if (in_order) {
       if (last_received_timestamp_ != rtp_header.timestamp) {
         last_received_timestamp_ = rtp_header.timestamp;
         last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
       }
       last_received_sequence_number_ = rtp_header.sequenceNumber;
     }
   }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h
@@ -47,17 +47,17 @@ class RtpReceiverImpl : public RtpReceiv
   // Returns the last received timestamp.
   bool Timestamp(uint32_t* timestamp) const override;
   bool LastReceivedTimeMs(int64_t* receive_time_ms) const override;
 
   uint32_t SSRC() const override;
 
   int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const override;
 
-  void GetRID(char rid[256]) const override;
+  void GetRID(char rtp_stream_id[256]) const override;
 
   int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const override;
 
   TelephoneEventHandler* GetTelephoneEventHandler() override;
 
  private:
   bool HaveReceivedFrame() const;
 
@@ -81,12 +81,12 @@ class RtpReceiverImpl : public RtpReceiv
   // SSRCs.
   uint32_t ssrc_;
   uint8_t num_csrcs_;
   uint32_t current_remote_csrc_[kRtpCsrcSize];
 
   uint32_t last_received_timestamp_;
   int64_t last_received_frame_time_ms_;
   uint16_t last_received_sequence_number_;
-  char *rid_;
+  StreamId rtp_stream_id_;
 };
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -25,30 +25,44 @@
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 #include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
 #include "webrtc/modules/rtp_rtcp/source/time_util.h"
 #include "webrtc/system_wrappers/include/field_trial.h"
+#include "webrtc/modules/rtp_rtcp/source/ssrc_database.h"
 
 namespace webrtc {
 
 namespace {
 // Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
 constexpr size_t kMaxPaddingLength = 224;
 constexpr int kSendSideDelayWindowMs = 1000;
 constexpr size_t kRtpHeaderLength = 12;
 constexpr uint16_t kMaxInitRtpSeqNumber = 32767;  // 2^15 -1.
 constexpr uint32_t kTimestampTicksPerMs = 90;
 constexpr int kBitrateStatisticsWindowMs = 1000;
 
 constexpr size_t kMinFlexfecPacketsToStoreForPacing = 50;
 
+template <typename Extension>
+constexpr RtpExtensionSize CreateExtensionSize() {
+  return {Extension::kId, Extension::kValueSizeBytes};
+}
+
+// Size info for header extensions that might be used in padding or FEC packets.
+constexpr RtpExtensionSize kExtensionSizes[] = {
+    CreateExtensionSize<AbsoluteSendTime>(),
+    CreateExtensionSize<TransmissionOffset>(),
+    CreateExtensionSize<TransportSequenceNumber>(),
+    CreateExtensionSize<PlayoutDelayLimits>(),
+};
+
 const char* FrameTypeToString(FrameType frame_type) {
   switch (frame_type) {
     case kEmptyFrame:
       return "empty";
     case kAudioFrameSpeech: return "audio_speech";
     case kAudioFrameCN: return "audio_cn";
     case kVideoFrameKey: return "video_key";
     case kVideoFrameDelta: return "video_delta";
@@ -92,17 +106,16 @@ RTPSender::RTPSender(
       transport_feedback_observer_(transport_feedback_observer),
       last_capture_time_ms_sent_(0),
       transport_(transport),
       sending_media_(true),                   // Default to sending media.
       max_packet_size_(IP_PACKET_SIZE - 28),  // Default is IP-v4/UDP.
       payload_type_(-1),
       payload_type_map_(),
       rtp_header_extension_map_(),
-      rid_{0},
       packet_history_(clock),
       flexfec_packet_history_(clock),
       // Statistics
       rtp_stats_callback_(nullptr),
       total_bitrate_sent_(kBitrateStatisticsWindowMs,
                           RateStatistics::kBpsScale),
       nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
       frame_count_observer_(frame_count_observer),
@@ -163,16 +176,20 @@ RTPSender::~RTPSender() {
   while (!payload_type_map_.empty()) {
     std::map<int8_t, RtpUtility::Payload*>::iterator it =
         payload_type_map_.begin();
     delete it->second;
     payload_type_map_.erase(it);
   }
 }
 
+rtc::ArrayView<const RtpExtensionSize> RTPSender::FecExtensionSizes() {
+  return rtc::MakeArrayView(kExtensionSizes, arraysize(kExtensionSizes));
+}
+
 uint16_t RTPSender::ActualSendBitrateKbit() const {
   rtc::CritScope cs(&statistics_crit_);
   return static_cast<uint16_t>(
       total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
       1000);
 }
 
 uint32_t RTPSender::VideoBitrateSent() const {
@@ -191,46 +208,30 @@ uint32_t RTPSender::FecOverheadRate() co
 
 uint32_t RTPSender::NackOverheadRate() const {
   rtc::CritScope cs(&statistics_crit_);
   return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
 }
 
 int32_t RTPSender::SetRID(const char* rid) {
   rtc::CritScope lock(&send_critsect_);
-  const size_t len = rid ? strlen(rid) : 0;
-  if (!len || len >= sizeof(rid_)) {
-    rid_[0] = '\0';
-  } else {
-    memmove(&rid_[0], rid, len + 1);
+  const size_t len = (rid && rid[0]) ? strlen(rid) : 0;
+  if (len) {
+    rtpStreamId.Set(rid, len);
   }
   return 0;
 }
 
 int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
                                               uint8_t id) {
   rtc::CritScope lock(&send_critsect_);
-  switch (type) {
-    case kRtpExtensionVideoRotation:
-    case kRtpExtensionPlayoutDelay:
-    case kRtpExtensionTransmissionTimeOffset:
-    case kRtpExtensionAbsoluteSendTime:
-    case kRtpExtensionAudioLevel:
-    case kRtpExtensionTransportSequenceNumber:
-    case kRtpExtensionRtpStreamId:
-      return rtp_header_extension_map_.Register(type, id);
-    case kRtpExtensionNone:
-    case kRtpExtensionNumberOfExtensions:
-      LOG(LS_ERROR) << "Invalid RTP extension type for registration";
-      return -1;
-  }
-  return -1;
+  return rtp_header_extension_map_.RegisterByType(id, type) ? 0 : -1;
 }
 
-bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) {
+bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) const {
   rtc::CritScope lock(&send_critsect_);
   return rtp_header_extension_map_.IsRegistered(type);
 }
 
 int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) {
   rtc::CritScope lock(&send_critsect_);
   return rtp_header_extension_map_.Deregister(type);
 }
@@ -445,17 +446,17 @@ bool RTPSender::SendOutgoingData(FrameTy
     if (rtp_header) {
       playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
                                           sequence_number);
     }
 
     result = video_->SendVideo(video_type, frame_type, payload_type,
                                rtp_timestamp, capture_time_ms, payload_data,
                                payload_size, fragmentation, rtp_header,
-                               &rid_[0]);
+                               &rtpStreamId);
   }
 
   rtc::CritScope cs(&statistics_crit_);
   // Note: This is currently only counting for video.
   if (frame_type == kVideoFrameKey) {
     ++frame_counts_.key_frames;
   } else if (frame_type == kVideoFrameDelta) {
     ++frame_counts_.delta_frames;
@@ -554,17 +555,18 @@ size_t RTPSender::SendPadData(size_t byt
     padding_packet->SetSequenceNumber(sequence_number);
     padding_packet->SetTimestamp(timestamp);
     padding_packet->SetSsrc(ssrc);
 
     if (capture_time_ms > 0) {
       padding_packet->SetExtension<TransmissionOffset>(
           (now_ms - capture_time_ms) * kTimestampTicksPerMs);
     }
-    padding_packet->SetExtension<AbsoluteSendTime>(now_ms);
+    padding_packet->SetExtension<AbsoluteSendTime>(
+        AbsoluteSendTime::MsTo24Bits(now_ms));
     PacketOptions options;
     bool has_transport_seq_num =
       UpdateTransportSequenceNumber(padding_packet.get(), &options.packet_id);
     padding_packet->SetPadding(padding_bytes_in_packet, &random_);
 
     if (has_transport_seq_num) {
       AddPacketToTransportFeedback(options.packet_id, *padding_packet,
                                    probe_cluster_id);
@@ -738,17 +740,18 @@ bool RTPSender::PrepareAndSendPacket(std
       return false;
     packet_to_send = packet_rtx.get();
   }
 
   int64_t now_ms = clock_->TimeInMilliseconds();
   int64_t diff_ms = now_ms - capture_time_ms;
   packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs *
                                                    diff_ms);
-  packet_to_send->SetExtension<AbsoluteSendTime>(now_ms);
+  packet_to_send->SetExtension<AbsoluteSendTime>(
+      AbsoluteSendTime::MsTo24Bits(now_ms));
 
   PacketOptions options;
   if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id)) {
     AddPacketToTransportFeedback(options.packet_id, *packet_to_send,
                                  probe_cluster_id);
   }
 
   if (!is_retransmit && !send_over_rtx) {
@@ -827,17 +830,17 @@ bool RTPSender::SendToNetwork(std::uniqu
 
   // |capture_time_ms| <= 0 is considered invalid.
   // TODO(holmer): This should be changed all over Video Engine so that negative
   // time is consider invalid, while 0 is considered a valid time.
   if (packet->capture_time_ms() > 0) {
     packet->SetExtension<TransmissionOffset>(
         kTimestampTicksPerMs * (now_ms - packet->capture_time_ms()));
   }
-  packet->SetExtension<AbsoluteSendTime>(now_ms);
+  packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms));
 
   if (video_) {
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
                                     ActualSendBitrateKbit(), packet->Ssrc());
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
                                     FecOverheadRate() / 1000, packet->Ssrc());
     BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
                                     NackOverheadRate() / 1000, packet->Ssrc());
@@ -965,17 +968,18 @@ void RTPSender::ProcessBitrate() {
   bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
                             nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc);
 }
 
 size_t RTPSender::RtpHeaderLength() const {
   rtc::CritScope lock(&send_critsect_);
   size_t rtp_header_length = kRtpHeaderLength;
   rtp_header_length += sizeof(uint32_t) * csrcs_.size();
-  rtp_header_length += rtp_header_extension_map_.GetTotalLengthInBytes();
+  rtp_header_length +=
+      rtp_header_extension_map_.GetTotalLengthInBytes(kExtensionSizes);
   return rtp_header_length;
 }
 
 uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) {
   rtc::CritScope lock(&send_critsect_);
   uint16_t first_allocated_sequence_number = sequence_number_;
   sequence_number_ += packets_to_send;
   return first_allocated_sequence_number;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -12,41 +12,42 @@
 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
 
 #include <map>
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "webrtc/api/call/transport.h"
+#include "webrtc/base/array_view.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/base/deprecation.h"
 #include "webrtc/base/optional.h"
 #include "webrtc/base/random.h"
 #include "webrtc/base/rate_statistics.h"
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
-#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
-#include "webrtc/modules/rtp_rtcp/source/ssrc_database.h"
 
 namespace webrtc {
 
 class OverheadObserver;
 class RateLimiter;
 class RtcEventLog;
 class RtpPacketToSend;
 class RTPSenderAudio;
 class RTPSenderVideo;
+class SSRCDatabase;
 
 class RTPSender {
  public:
   RTPSender(bool audio,
             Clock* clock,
             Transport* transport,
             RtpPacketSender* paced_sender,
             // TODO(brandtr): Remove |flexfec_sender| when that is hooked up
@@ -117,17 +118,17 @@ class RTPSender {
                         const RTPFragmentationHeader* fragmentation,
                         const RTPVideoHeader* rtp_header,
                         uint32_t* transport_frame_id_out);
 
   int32_t SetRID(const char* rid);
 
   // RTP header extension
   int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id);
-  bool IsRtpHeaderExtensionRegistered(RTPExtensionType type);
+  bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) const;
   int32_t DeregisterRtpHeaderExtension(RTPExtensionType type);
 
   bool TimeToSendPacket(uint32_t ssrc,
                         uint16_t sequence_number,
                         int64_t capture_time_ms,
                         bool retransmission,
                         int probe_cluster_id);
   size_t TimeToSendPadding(size_t bytes, int probe_cluster_id);
@@ -151,24 +152,28 @@ class RTPSender {
   void SetRtxStatus(int mode);
   int RtxStatus() const;
 
   uint32_t RtxSsrc() const;
   void SetRtxSsrc(uint32_t ssrc);
 
   void SetRtxPayloadType(int payload_type, int associated_payload_type);
 
+  // Size info for header extensions used by FEC packets.
+  static rtc::ArrayView<const RtpExtensionSize> FecExtensionSizes();
+
   // Create empty packet, fills ssrc, csrcs and reserve place for header
   // extensions RtpSender updates before sending.
   std::unique_ptr<RtpPacketToSend> AllocatePacket() const;
   // Allocate sequence number for provided packet.
   // Save packet's fields to generate padding that doesn't break media stream.
   // Return false if sending was turned off.
   bool AssignSequenceNumber(RtpPacketToSend* packet);
 
+  // Used for padding and FEC packets only.
   size_t RtpHeaderLength() const;
   uint16_t AllocateSequenceNumber(uint16_t packets_to_send);
   // Including RTP headers.
   size_t MaxRtpPacketSize() const;
 
   uint32_t SSRC() const;
 
   rtc::Optional<uint32_t> FlexfecSsrc() const;
@@ -275,17 +280,17 @@ class RTPSender {
 
   size_t max_packet_size_;
 
   int8_t payload_type_ GUARDED_BY(send_critsect_);
   std::map<int8_t, RtpUtility::Payload*> payload_type_map_;
 
   RtpHeaderExtensionMap rtp_header_extension_map_ GUARDED_BY(send_critsect_);
 
-  char rid_[kRIDSize + 1] GUARDED_BY(send_critsect_);
+  StreamId rtpStreamId GUARDED_BY(send_critsect_);
 
   // Tracks the current request for playout delay limits from application
   // and decides whether the current RTP frame should include the playout
   // delay extension on header.
   PlayoutDelayOracle playout_delay_oracle_;
 
   RtpPacketHistory packet_history_;
   // TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -799,18 +799,20 @@ TEST_F(RtpSenderTestWithoutPacer, SendGe
 }
 
 TEST_F(RtpSenderTest, SendFlexfecPackets) {
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
   constexpr uint32_t kFlexfecSsrc = 5678;
   const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
   FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                               kNoRtpExtensions, &fake_clock_);
+                               kNoRtpExtensions, kNoRtpExtensionSizes,
+                               &fake_clock_);
 
   // Reset |rtp_sender_| to use FlexFEC.
   rtp_sender_.reset(new RTPSender(
       false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
       &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
       &mock_rtc_event_log_, &send_packet_observer_,
       &retransmission_rate_limiter_, nullptr));
   rtp_sender_->SetSSRC(kMediaSsrc);
@@ -853,18 +855,20 @@ TEST_F(RtpSenderTest, SendFlexfecPackets
 }
 
 TEST_F(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
   constexpr uint32_t kFlexfecSsrc = 5678;
   const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
   FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
-                               kNoRtpExtensions, &fake_clock_);
+                               kNoRtpExtensions, kNoRtpExtensionSizes,
+                               &fake_clock_);
 
   // Reset |rtp_sender_| to use FlexFEC.
   rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr,
                                   &flexfec_sender, &seq_num_allocator_, nullptr,
                                   nullptr, nullptr, nullptr,
                                   &mock_rtc_event_log_, &send_packet_observer_,
                                   &retransmission_rate_limiter_, nullptr));
   rtp_sender_->SetSSRC(kMediaSsrc);
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -286,17 +286,17 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
                                FrameType frame_type,
                                int8_t payload_type,
                                uint32_t rtp_timestamp,
                                int64_t capture_time_ms,
                                const uint8_t* payload_data,
                                size_t payload_size,
                                const RTPFragmentationHeader* fragmentation,
                                const RTPVideoHeader* video_header,
-                               const char* rid) {
+                               const StreamId* rtpStreamId) {
   if (payload_size == 0)
     return false;
 
   // Create header that will be reused in all packets.
   std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
   rtp_header->SetPayloadType(payload_type);
   rtp_header->SetTimestamp(rtp_timestamp);
   rtp_header->set_capture_time_ms(capture_time_ms);
@@ -320,21 +320,18 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
       // Set rotation when key frame or when changed (to follow standard).
       // Or when different from 0 (to follow current receiver implementation).
       VideoRotation current_rotation = video_header->rotation;
       if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
           current_rotation != kVideoRotation_0)
         rtp_header->SetExtension<VideoOrientation>(current_rotation);
       last_rotation_ = current_rotation;
     }
-    if (rid && rid[0]) {
-      const size_t len = strlen(rid);
-      if (len) {
-        rtp_header->SetExtensionWithLength<StreamId>(len - 1, rid);
-      }
+    if (rtpStreamId && !rtpStreamId->empty()) {
+       rtp_header->SetExtension<RtpStreamId>(*rtpStreamId);
     }
 
     // FEC settings.
     const FecProtectionParams& fec_params =
         frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
     if (flexfec_enabled())
       flexfec_sender_->SetFecParameters(fec_params);
     if (ulpfec_enabled())
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -56,17 +56,17 @@ class RTPSenderVideo {
                  FrameType frame_type,
                  int8_t payload_type,
                  uint32_t capture_timestamp,
                  int64_t capture_time_ms,
                  const uint8_t* payload_data,
                  size_t payload_size,
                  const RTPFragmentationHeader* fragmentation,
                  const RTPVideoHeader* video_header,
-                 const char* rid);
+                 const StreamId* rtpStreamId);
 
   void SetVideoCodecType(RtpVideoCodecTypes type);
 
   // ULPFEC.
   void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
   void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const;
 
   // FlexFEC/ULPFEC.
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -249,20 +249,16 @@ bool RtpHeaderParser::Parse(RTPHeader* h
   header->extension.voiceActivity = false;
   header->extension.audioLevel = 0;
 
   // May not be present in packet.
   header->extension.hasVideoRotation = false;
   header->extension.videoRotation = kVideoRotation_0;
 
   // May not be present in packet.
-  header->extension.hasRID = false;
-  header->extension.rid = NULL;
-
-  // May not be present in packet.
   header->extension.playout_delay.min_ms = -1;
   header->extension.playout_delay.max_ms = -1;
 
   if (X) {
     /* 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
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -456,35 +452,22 @@ void RtpHeaderParser::ParseOneByteExtens
           int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2];
           header->extension.playout_delay.min_ms =
               min_playout_delay * kPlayoutDelayGranularityMs;
           header->extension.playout_delay.max_ms =
               max_playout_delay * kPlayoutDelayGranularityMs;
           break;
         }
         case kRtpExtensionRtpStreamId: {
-          //   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=?   |UTF-8 RID value......          |...
-          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-          // As per RFC 5285 section 4.2, len is the length of the header data
-          // - 1. E.G. a len of 0 indicates a header data length of 1
-          if ( &ptr[len + 1] > ptrRTPDataExtensionEnd ) {
-            LOG(LS_WARNING) << "Extension RtpStreamId data length " << (len + 1)
-              << " is longer than remaining input parse buffer "
-              << static_cast<size_t>(ptrRTPDataExtensionEnd - ptr);
-            return;
-          }
-
-          header->extension.rid.reset(new char[len + 2]);
-          memcpy(header->extension.rid.get(), ptr, len + 1);
-          header->extension.rid.get()[len + 1] = '\0';
-          header->extension.hasRID = true;
+          header->extension.rtpStreamId.Set(rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
+        case kRtpExtensionRepairedRtpStreamId: {
+          header->extension.repairedStreamId.Set(
+              rtc::MakeArrayView(ptr, len + 1));
           break;
         }
         default:
         case kRtpExtensionNone:
         case kRtpExtensionNumberOfExtensions: {
           RTC_NOTREACHED() << "Invalid extension type: " << type;
           return;
         }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
@@ -143,42 +143,46 @@ TEST(RtpHeaderParser, ParseWithOverSized
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   // Parse should ignore extension.
   EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(sizeof(kPacket), header.headerLength);
 }
 
-TEST(RtpHeaderParser, ParseAll6Extensions) {
+TEST(RtpHeaderParser, ParseAll8Extensions) {
   const uint8_t kAudioLevel = 0x5a;
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
-      0xbe, 0xde, 0x00, 0x05,  // Extension of size 5x32bit word.
+      0xbe, 0xde, 0x00, 0x08,  // Extension of size 8x32bit words.
       0x40, 0x80|kAudioLevel,  // AudioLevel.
       0x22, 0x01, 0x56, 0xce,  // TransmissionOffset.
       0x62, 0x12, 0x34, 0x56,  // AbsoluteSendTime.
       0x81, 0xce, 0xab,        // TransportSequenceNumber.
       0xa0, 0x03,              // VideoRotation.
       0xb2, 0x12, 0x48, 0x76,  // PlayoutDelayLimits.
-      0x00,                    // Padding to 32bit boundary.
+      0xc2, 'r', 't', 'x',     // RtpStreamId
+      0xd5, 's', 't', 'r', 'e', 'a', 'm',  // RepairedRtpStreamId
+      0x00, 0x00,              // Padding to 32bit boundary.
   };
   // clang-format on
   ASSERT_EQ(sizeof(kPacket) % 4, 0u);
 
   RtpHeaderExtensionMap extensions;
   extensions.Register<TransmissionOffset>(2);
   extensions.Register<AudioLevel>(4);
   extensions.Register<AbsoluteSendTime>(6);
   extensions.Register<TransportSequenceNumber>(8);
   extensions.Register<VideoOrientation>(0xa);
   extensions.Register<PlayoutDelayLimits>(0xb);
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
   RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
   RTPHeader header;
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
 
@@ -194,16 +198,43 @@ TEST(RtpHeaderParser, ParseAll6Extension
 
   EXPECT_TRUE(header.extension.hasVideoRotation);
   EXPECT_EQ(kVideoRotation_270, header.extension.videoRotation);
 
   EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.min_ms);
   EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.max_ms);
+  EXPECT_EQ(header.extension.rtpStreamId, StreamId("rtx"));
+  EXPECT_EQ(header.extension.repairedStreamId, StreamId("stream"));
+}
+
+TEST(RtpHeaderParser, ParseMalformedRsidExtensions) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x03,  // Extension of size 3x32bit words.
+      0xc2, '\0', 't', 'x',    // empty RtpStreamId
+      0xd5, 's', 't', 'r', '\0', 'a', 'm',  // RepairedRtpStreamId
+      0x00,                    // Padding to 32bit boundary.
+  };
+  // clang-format on
+  ASSERT_EQ(sizeof(kPacket) % 4, 0u);
+
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+  EXPECT_TRUE(header.extension.rtpStreamId.empty());
+  EXPECT_EQ(header.extension.repairedStreamId, StreamId("str"));
 }
 
 TEST(RtpHeaderParser, ParseWithCsrcsExtensionAndPadding) {
   const uint8_t kPacketPaddingSize = 8;
   const uint32_t kCsrcs[] = {0x34567890, 0x32435465};
   const size_t kPayloadSize = 7;
   // clang-format off
   const uint8_t kPacket[] = {
--- a/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -9,40 +9,41 @@
  */
 
 #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/rtp_packet_received.h"
 
 namespace webrtc {
 
-// We decide which header extensions to register by reading one byte
+// We decide which header extensions to register by reading two bytes
 // from the beginning of |data| and interpreting it as a bitmask over
-// the RTPExtensionType enum. This assert ensures one byte is enough.
-static_assert(kRtpExtensionNumberOfExtensions <= 8,
+// the RTPExtensionType enum. This assert ensures two bytes are enough.
+static_assert(kRtpExtensionNumberOfExtensions <= 16,
               "Insufficient bits read to configure all header extensions. Add "
               "an extra byte and update the switches.");
 
 void FuzzOneInput(const uint8_t* data, size_t size) {
-  if (size <= 1)
+  if (size <= 2)
     return;
 
-  // Don't use the configuration byte as part of the packet.
-  std::bitset<8> extensionMask(data[0]);
-  data++;
-  size--;
+  // Don't use the configuration bytes as part of the packet.
+  std::bitset<16> extensionMask(*reinterpret_cast<const uint16_t*>(data));
+  data += 2;
+  size -= 2;
 
   RtpPacketReceived::ExtensionManager extensions;
-  for (int i = 0; i < kRtpExtensionNumberOfExtensions; i++) {
+  // Skip i = 0 since it maps to ExtensionNone and extension id = 0 is invalid.
+  for (int i = 1; i < kRtpExtensionNumberOfExtensions; i++) {
     RTPExtensionType extension_type = static_cast<RTPExtensionType>(i);
     if (extensionMask[i] && extension_type != kRtpExtensionNone) {
       // Extensions are registered with an ID, which you signal to the
       // peer so they know what to expect. This code only cares about
       // parsing so the value of the ID isn't relevant; we use i.
-      extensions.Register(extension_type, i);
+      extensions.RegisterByType(i, extension_type);
     }
   }
 
   RtpPacketReceived packet(&extensions);
   packet.Parse(data, size);
 
   // Call packet accessors because they have extra checks.
   packet.Marker();
@@ -80,12 +81,22 @@ void FuzzOneInput(const uint8_t* data, s
       case kRtpExtensionTransportSequenceNumber:
         uint16_t seqnum;
         packet.GetExtension<TransportSequenceNumber>(&seqnum);
         break;
       case kRtpExtensionPlayoutDelay:
         PlayoutDelay playout;
         packet.GetExtension<PlayoutDelayLimits>(&playout);
         break;
+      case kRtpExtensionRtpStreamId: {
+        std::string rsid;
+        packet.GetExtension<RtpStreamId>(&rsid);
+        break;
+      }
+      case kRtpExtensionRepairedRtpStreamId: {
+        std::string rsid;
+        packet.GetExtension<RepairedRtpStreamId>(&rsid);
+        break;
+      }
     }
   }
 }
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
+++ b/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
@@ -385,18 +385,18 @@ bool RtpStreamReceiver::DeliverRtp(const
       ss << "Packet received on SSRC: " << header.ssrc << " with payload type: "
          << static_cast<int>(header.payloadType) << ", timestamp: "
          << header.timestamp << ", sequence number: " << header.sequenceNumber
          << ", arrival time: " << arrival_time_ms;
       if (header.extension.hasTransmissionTimeOffset)
         ss << ", toffset: " << header.extension.transmissionTimeOffset;
       if (header.extension.hasAbsoluteSendTime)
         ss << ", abs send time: " << header.extension.absoluteSendTime;
-			if (header.extension.hasRID)
-				ss << ", rid: " << header.extension.rid.get();
+      if (!header.extension.rtpStreamId.empty())
+        ss << ", rid: " << header.extension.rtpStreamId.data();
       LOG(LS_INFO) << ss.str();
       last_packet_log_ms_ = now_ms;
     }
   }
 
   remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_length,
                                             header);
   header.payload_type_frequency = kVideoPayloadTypeFrequency;
--- a/media/webrtc/trunk/webrtc/video/video_send_stream.cc
+++ b/media/webrtc/trunk/webrtc/video/video_send_stream.cc
@@ -22,16 +22,17 @@
 #include "webrtc/base/file.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/trace_event.h"
 #include "webrtc/base/weak_ptr.h"
 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
 #include "webrtc/modules/congestion_controller/include/congestion_controller.h"
 #include "webrtc/modules/pacing/packet_router.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
 #include "webrtc/modules/utility/include/process_thread.h"
 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
 #include "webrtc/system_wrappers/include/field_trial.h"
 #include "webrtc/video/call_stats.h"
 #include "webrtc/video/vie_remb.h"
 #include "webrtc/video_send_stream.h"
 
 namespace webrtc {
@@ -125,17 +126,17 @@ std::unique_ptr<FlexfecSender> MaybeCrea
            "To avoid confusion, disabling FlexFEC completely.";
     return nullptr;
   }
 
   RTC_DCHECK_EQ(1U, config.rtp.flexfec.protected_media_ssrcs.size());
   return std::unique_ptr<FlexfecSender>(new FlexfecSender(
       config.rtp.flexfec.payload_type, config.rtp.flexfec.ssrc,
       config.rtp.flexfec.protected_media_ssrcs[0], config.rtp.extensions,
-      Clock::GetRealTimeClock()));
+      RTPSender::FecExtensionSizes(), Clock::GetRealTimeClock()));
 }
 
 }  // namespace
 
 std::string
 VideoSendStream::Config::EncoderSettings::ToString() const {
   std::stringstream ss;
   ss << "{payload_name: " << payload_name;