Add a ParseHeader method to RtcpPacket, for parsing common RTCP header.

Also refactor TransportFeedback to use this.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#9935}
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
index 8cb6fb0..e5ea37e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -743,7 +743,7 @@
     uint8_t packet_type,
     size_t length,
     uint8_t* buffer,
-    size_t* pos) const {
+    size_t* pos) {
   assert(length <= 0xffff);
   const uint8_t kVersion = 2;
   AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
index c5432de..cfbe8ce 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -99,11 +99,11 @@
                       size_t max_length,
                       PacketReadyCallback* callback) const = 0;
 
-  void CreateHeader(uint8_t count_or_format,
-                    uint8_t packet_type,
-                    size_t length,
-                    uint8_t* buffer,
-                    size_t* pos) const;
+  static void CreateHeader(uint8_t count_or_format,
+                           uint8_t packet_type,
+                           size_t block_length,  // Size in 32bit words - 1.
+                           uint8_t* buffer,
+                           size_t* pos);
 
   bool OnBufferFull(uint8_t* packet,
                     size_t* index,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
index 975d3f3..9cd5ac3 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -13,6 +13,7 @@
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 
 namespace webrtc {
 namespace rtcp {
@@ -662,54 +663,23 @@
     return nullptr;
   }
 
-  size_t packet_size_words =
-      ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) + 1;
-  if (length < packet_size_words * 4) {
-    LOG(LS_WARNING) << "Buffer too small (" << length
-                    << " bytes) to fit a FeedbackPacket of "
-                    << packet_size_words << " 32bit words.";
+  RTCPUtility::RtcpCommonHeader header;
+  if (!RtcpParseCommonHeader(buffer, length, &header))
     return nullptr;
-  }
 
-  // TODO(sprang): Break this out and generalize when implementing parsing of
-  // other RtcpPacket subclasses.
-
-  const uint8_t kRtcpVersion = 2;
-  uint8_t version = buffer[0] >> 6;
-  if (version != kRtcpVersion) {
-    LOG(LS_WARNING) << "Invalid RTCP header: Version must be " << kRtcpVersion
-                    << " but was " << version;
-    return nullptr;
-  }
-
-  bool has_padding = (buffer[0] & 0x20) != 0;
-
-  uint8_t format = buffer[0] & 0x1F;
-  if (format != kFeedbackMessageType) {
+  if (header.count_or_format != kFeedbackMessageType) {
     LOG(LS_WARNING) << "Invalid RTCP header: FMT must be "
-                    << kFeedbackMessageType << " but was " << format;
+                    << kFeedbackMessageType << " but was "
+                    << header.count_or_format;
     return nullptr;
   }
 
-  uint8_t payload_type = buffer[1];
-  if (payload_type != kPayloadType) {
+  if (header.packet_type != kPayloadType) {
     LOG(LS_WARNING) << "Invalid RTCP header: PT must be " << kPayloadType
-                    << " but was " << payload_type;
+                    << " but was " << header.packet_type;
     return nullptr;
   }
 
-  size_t payload_size = packet_size_words * 4;
-  if (has_padding) {
-    uint8_t padding_bytes = buffer[payload_size - 1];
-    if (payload_size < kMinSizeBytes + padding_bytes) {
-      LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
-                      << padding_bytes << ") for a packet size of "
-                      << payload_size << "bytes.";
-      return nullptr;
-    }
-    payload_size -= padding_bytes;
-  }
-
   packet->packet_sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
   packet->media_source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
   packet->base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
@@ -717,6 +687,7 @@
   packet->base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[16]);
   packet->feedback_seq_ = buffer[19];
   size_t index = 20;
+  const size_t end_index = kHeaderLength + header.payload_size_bytes;
 
   if (num_packets == 0) {
     LOG(LS_WARNING) << "Empty feedback messages not allowed.";
@@ -726,7 +697,7 @@
 
   size_t packets_read = 0;
   while (packets_read < num_packets) {
-    if (index + 2 > payload_size) {
+    if (index + 2 > end_index) {
       LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
       return nullptr;
     }
@@ -748,7 +719,7 @@
   for (StatusSymbol symbol : symbols) {
     switch (symbol) {
       case StatusSymbol::kReceivedSmallDelta:
-        if (index + 1 > payload_size) {
+        if (index + 1 > end_index) {
           LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
           return nullptr;
         }
@@ -756,7 +727,7 @@
         ++index;
         break;
       case StatusSymbol::kReceivedLargeDelta:
-        if (index + 2 > payload_size) {
+        if (index + 2 > end_index) {
           LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
           return nullptr;
         }
@@ -769,8 +740,8 @@
     }
   }
 
-  DCHECK_GE(index, payload_size - 3);
-  DCHECK_LE(index, payload_size);
+  DCHECK_GE(index, end_index - 3);
+  DCHECK_LE(index, end_index);
 
   return packet;
 }
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
index 4e37cf3..47a6331 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -14,6 +14,10 @@
 #include <math.h>   // ceil
 #include <string.h> // memcpy
 
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
 namespace webrtc {
 
 namespace RTCPUtility {
@@ -155,43 +159,40 @@
 {
     for (;;)
     {
-        RTCPCommonHeader header;
+      RtcpCommonHeader header;
+      if (_ptrRTCPDataEnd <= _ptrRTCPData)
+        return;
 
-        const bool success = RTCPParseCommonHeader(_ptrRTCPData,
-                                                    _ptrRTCPDataEnd,
-                                                    header);
-
-        if (!success)
-        {
+      if (!RtcpParseCommonHeader(_ptrRTCPData, _ptrRTCPDataEnd - _ptrRTCPData,
+                                 &header)) {
             return;
         }
-        _ptrRTCPBlockEnd = _ptrRTCPData + header.LengthInOctets;
+        _ptrRTCPBlockEnd = _ptrRTCPData + header.BlockSize();
         if (_ptrRTCPBlockEnd > _ptrRTCPDataEnd)
         {
             // Bad block!
             return;
         }
 
-        switch (header.PT)
-        {
+        switch (header.packet_type) {
         case PT_SR:
         {
             // number of Report blocks
-            _numberOfBlocks = header.IC;
+            _numberOfBlocks = header.count_or_format;
             ParseSR();
             return;
         }
         case PT_RR:
         {
             // number of Report blocks
-            _numberOfBlocks = header.IC;
+            _numberOfBlocks = header.count_or_format;
             ParseRR();
             return;
         }
         case PT_SDES:
         {
             // number of SDES blocks
-            _numberOfBlocks = header.IC;
+            _numberOfBlocks = header.count_or_format;
             const bool ok = ParseSDES();
             if (!ok)
             {
@@ -202,7 +203,7 @@
         }
         case PT_BYE:
         {
-            _numberOfBlocks = header.IC;
+          _numberOfBlocks = header.count_or_format;
             const bool ok = ParseBYE();
             if (!ok)
             {
@@ -214,7 +215,7 @@
         case PT_IJ:
         {
             // number of Report blocks
-            _numberOfBlocks = header.IC;
+            _numberOfBlocks = header.count_or_format;
             ParseIJ();
             return;
         }
@@ -410,20 +411,16 @@
 void
 RTCPUtility::RTCPParserV2::Validate()
 {
-    if (_ptrRTCPData == NULL)
-    {
-        return; // NOT VALID
-    }
+  if (_ptrRTCPData == nullptr)
+    return;  // NOT VALID
 
-    RTCPCommonHeader header;
-    const bool success = RTCPParseCommonHeader(_ptrRTCPDataBegin,
-                                               _ptrRTCPDataEnd,
-                                               header);
+  RtcpCommonHeader header;
+  if (_ptrRTCPDataEnd <= _ptrRTCPDataBegin)
+    return;  // NOT VALID
 
-    if (!success)
-    {
-        return; // NOT VALID!
-    }
+  if (!RtcpParseCommonHeader(_ptrRTCPDataBegin,
+                             _ptrRTCPDataEnd - _ptrRTCPDataBegin, &header))
+    return;  // NOT VALID!
 
     // * if (!reducedSize) : first packet must be RR or SR.
     //
@@ -437,8 +434,7 @@
 
     if (!_RTCPReducedSizeEnable)
     {
-        if ((header.PT != PT_SR) && (header.PT != PT_RR))
-        {
+      if ((header.packet_type != PT_SR) && (header.packet_type != PT_RR)) {
             return; // NOT VALID
         }
     }
@@ -458,48 +454,74 @@
     _ptrRTCPData = _ptrRTCPBlockEnd;
 }
 
-bool
-RTCPUtility::RTCPParseCommonHeader( const uint8_t* ptrDataBegin,
-                                    const uint8_t* ptrDataEnd,
-                                    RTCPCommonHeader& parsedHeader)
-{
-    if (!ptrDataBegin || !ptrDataEnd)
-    {
-        return false;
+//  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|    IC   |      PT       |             length            |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Common header for all RTCP packets, 4 octets.
+
+bool RTCPUtility::RtcpParseCommonHeader(const uint8_t* packet,
+                                        size_t size_bytes,
+                                        RtcpCommonHeader* parsed_header) {
+  DCHECK(parsed_header != nullptr);
+  if (size_bytes < RtcpCommonHeader::kHeaderSizeBytes) {
+    LOG(LS_WARNING) << "Too little data (" << size_bytes << " byte"
+                    << (size_bytes != 1 ? "s" : "")
+                    << ") remaining in buffer to parse RTCP header (4 bytes).";
+    return false;
+  }
+
+  const uint8_t kRtcpVersion = 2;
+  uint8_t version = packet[0] >> 6;
+  if (version != kRtcpVersion) {
+    LOG(LS_WARNING) << "Invalid RTCP header: Version must be "
+                    << static_cast<int>(kRtcpVersion) << " but was "
+                    << static_cast<int>(version);
+    return false;
+  }
+
+  bool has_padding = (packet[0] & 0x20) != 0;
+  uint8_t format = packet[0] & 0x1F;
+  uint8_t packet_type = packet[1];
+  size_t packet_size_words =
+      ByteReader<uint16_t>::ReadBigEndian(&packet[2]) + 1;
+
+  if (size_bytes < packet_size_words * 4) {
+    LOG(LS_WARNING) << "Buffer too small (" << size_bytes
+                    << " bytes) to fit an RtcpPacket of " << packet_size_words
+                    << " 32bit words.";
+    return false;
+  }
+
+  size_t payload_size = packet_size_words * 4;
+  size_t padding_bytes = 0;
+  if (has_padding) {
+    if (payload_size <= RtcpCommonHeader::kHeaderSizeBytes) {
+      LOG(LS_WARNING) << "Invalid RTCP header: Padding bit set but 0 payload "
+                         "size specified.";
+      return false;
     }
 
-    //  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|    IC   |      PT       |             length            |
-    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    //
-    // Common header for all RTCP packets, 4 octets.
-
-    if ((ptrDataEnd - ptrDataBegin) < 4)
-    {
-        return false;
+    padding_bytes = packet[payload_size - 1];
+    if (RtcpCommonHeader::kHeaderSizeBytes + padding_bytes > payload_size) {
+      LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
+                      << padding_bytes << ") for a packet size of "
+                      << payload_size << "bytes.";
+      return false;
     }
+    payload_size -= padding_bytes;
+  }
+  payload_size -= RtcpCommonHeader::kHeaderSizeBytes;
 
-    parsedHeader.V              = ptrDataBegin[0] >> 6;
-    parsedHeader.P              = ((ptrDataBegin[0] & 0x20) == 0) ? false : true;
-    parsedHeader.IC             = ptrDataBegin[0] & 0x1f;
-    parsedHeader.PT             = ptrDataBegin[1];
+  parsed_header->version = kRtcpVersion;
+  parsed_header->count_or_format = format;
+  parsed_header->packet_type = packet_type;
+  parsed_header->payload_size_bytes = payload_size;
+  parsed_header->padding_bytes = padding_bytes;
 
-    parsedHeader.LengthInOctets = (ptrDataBegin[2] << 8) + ptrDataBegin[3] + 1;
-    parsedHeader.LengthInOctets *= 4;
-
-    if(parsedHeader.LengthInOctets == 0)
-    {
-        return false;
-    }
-    // Check if RTP version field == 2
-    if (parsedHeader.V != 2)
-    {
-        return false;
-    }
-
-    return true;
+  return true;
 }
 
 bool
@@ -1137,10 +1159,9 @@
   return false;
 }
 
-bool
-RTCPUtility::RTCPParserV2::ParseFBCommon(const RTCPCommonHeader& header)
-{
-    assert((header.PT == PT_RTPFB) || (header.PT == PT_PSFB)); // Parser logic check
+bool RTCPUtility::RTCPParserV2::ParseFBCommon(const RtcpCommonHeader& header) {
+  assert((header.packet_type == PT_RTPFB) ||
+         (header.packet_type == PT_PSFB));  // Parser logic check
 
     const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
 
@@ -1162,12 +1183,10 @@
     mediaSSRC += *_ptrRTCPData++ << 8;
     mediaSSRC += *_ptrRTCPData++;
 
-    if (header.PT == PT_RTPFB)
-    {
+    if (header.packet_type == PT_RTPFB) {
         // Transport layer feedback
 
-        switch (header.IC)
-        {
+        switch (header.count_or_format) {
         case 1:
         {
             // NACK
@@ -1222,12 +1241,9 @@
         }
         EndCurrentBlock();
         return false;
-    }
-    else if (header.PT == PT_PSFB)
-    {
+    } else if (header.packet_type == PT_PSFB) {
         // Payload specific feedback
-        switch (header.IC)
-        {
+        switch (header.count_or_format) {
         case 1:
             // PLI
           _packetType = RTCPPacketTypes::kPsfbPli;
@@ -1579,9 +1595,7 @@
     return true;
 }
 
-bool
-RTCPUtility::RTCPParserV2::ParseAPP( const RTCPCommonHeader& header)
-{
+bool RTCPUtility::RTCPParserV2::ParseAPP(const RtcpCommonHeader& header) {
     ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
 
     if (length < 12) // 4 * 3, RFC 3550 6.7 APP: Application-Defined RTCP Packet
@@ -1606,7 +1620,7 @@
 
     _packetType = RTCPPacketTypes::kApp;
 
-    _packet.APP.SubType = header.IC;
+    _packet.APP.SubType = header.count_or_format;
     _packet.APP.Name = name;
 
     _state = ParseState::State_AppItem;
@@ -1651,37 +1665,31 @@
 RTCPUtility::RTCPPacketIterator::~RTCPPacketIterator() {
 }
 
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Begin()
-{
+const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Begin() {
     _ptrBlock = _ptrBegin;
 
     return Iterate();
 }
 
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Iterate()
-{
-    const bool success = RTCPParseCommonHeader(_ptrBlock, _ptrEnd, _header);
-    if (!success)
-    {
-        _ptrBlock = NULL;
-        return NULL;
-    }
-    _ptrBlock += _header.LengthInOctets;
+const RTCPUtility::RtcpCommonHeader*
+RTCPUtility::RTCPPacketIterator::Iterate() {
+  if ((_ptrEnd <= _ptrBlock) ||
+      !RtcpParseCommonHeader(_ptrBlock, _ptrEnd - _ptrBlock, &_header)) {
+    _ptrBlock = nullptr;
+    return nullptr;
+  }
+  _ptrBlock += _header.BlockSize();
 
-    if (_ptrBlock > _ptrEnd)
-    {
-        _ptrBlock = NULL;
-        return  NULL;
-    }
+  if (_ptrBlock > _ptrEnd) {
+    _ptrBlock = nullptr;
+    return nullptr;
+  }
 
-    return &_header;
+  return &_header;
 }
 
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Current()
-{
+const RTCPUtility::RtcpCommonHeader*
+RTCPUtility::RTCPPacketIterator::Current() {
     if (!_ptrBlock)
     {
         return NULL;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
index fcafe59..73658a0 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
@@ -306,12 +306,24 @@
   uint8_t* _ptrPacketEnd;
 };
 
-struct RTCPCommonHeader {
-  uint8_t V;   // Version
-  bool P;      // Padding
-  uint8_t IC;  // Item count/subtype
-  uint8_t PT;  // Packet Type
-  uint16_t LengthInOctets;
+struct RtcpCommonHeader {
+  static const uint8_t kHeaderSizeBytes = 4;
+  RtcpCommonHeader()
+      : version(2),
+        count_or_format(0),
+        packet_type(0),
+        payload_size_bytes(0),
+        padding_bytes(0) {}
+
+  uint32_t BlockSize() const {
+    return kHeaderSizeBytes + payload_size_bytes + padding_bytes;
+  }
+
+  uint8_t version;
+  uint8_t count_or_format;
+  uint8_t packet_type;
+  uint32_t payload_size_bytes;
+  uint8_t padding_bytes;
 };
 
 enum RTCPPT : uint8_t {
@@ -333,9 +345,9 @@
   kBtVoipMetric = 7
 };
 
-bool RTCPParseCommonHeader(const uint8_t* ptrDataBegin,
-                           const uint8_t* ptrDataEnd,
-                           RTCPCommonHeader& parsedHeader);
+bool RtcpParseCommonHeader(const uint8_t* buffer,
+                           size_t size_bytes,
+                           RtcpCommonHeader* parsed_header);
 
 class RTCPParserV2 {
  public:
@@ -418,7 +430,7 @@
   bool ParseXrVoipMetricItem(int block_length_4bytes);
   bool ParseXrUnsupportedBlockType(int block_length_4bytes);
 
-  bool ParseFBCommon(const RTCPCommonHeader& header);
+  bool ParseFBCommon(const RtcpCommonHeader& header);
   bool ParseNACKItem();
   bool ParseTMMBRItem();
   bool ParseTMMBNItem();
@@ -428,7 +440,7 @@
   bool ParsePsfbAppItem();
   bool ParsePsfbREMBItem();
 
-  bool ParseAPP(const RTCPCommonHeader& header);
+  bool ParseAPP(const RtcpCommonHeader& header);
   bool ParseAPPItem();
 
  private:
@@ -452,9 +464,9 @@
   RTCPPacketIterator(uint8_t* rtcpData, size_t rtcpDataLength);
   ~RTCPPacketIterator();
 
-  const RTCPCommonHeader* Begin();
-  const RTCPCommonHeader* Iterate();
-  const RTCPCommonHeader* Current();
+  const RtcpCommonHeader* Begin();
+  const RtcpCommonHeader* Iterate();
+  const RtcpCommonHeader* Current();
 
  private:
   uint8_t* const _ptrBegin;
@@ -462,7 +474,7 @@
 
   uint8_t* _ptrBlock;
 
-  RTCPCommonHeader _header;
+  RtcpCommonHeader _header;
 };
 }  // RTCPUtility
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
index 275b007..1a13812 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
@@ -10,10 +10,16 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 
 namespace webrtc {
 
+using RTCPUtility::RtcpCommonHeader;
+
+namespace rtcp {
+
 TEST(RtcpUtilityTest, MidNtp) {
   const uint32_t kNtpSec = 0x12345678;
   const uint32_t kNtpFrac = 0x23456789;
@@ -68,5 +74,88 @@
   EXPECT_EQ(8U, stats.requests());
 }
 
+class RtcpParseCommonHeaderTest : public ::testing::Test {
+ public:
+  RtcpParseCommonHeaderTest() { memset(buffer, 0, kBufferCapacityBytes); }
+  virtual ~RtcpParseCommonHeaderTest() {}
+
+ protected:
+  static const size_t kBufferCapacityBytes = 40;
+  uint8_t buffer[kBufferCapacityBytes];
+  RtcpCommonHeader header;
+};
+
+TEST_F(RtcpParseCommonHeaderTest, TooSmallBuffer) {
+  // Buffer needs to be able to hold the header.
+  for (size_t i = 0; i < RtcpCommonHeader::kHeaderSizeBytes; ++i)
+    EXPECT_FALSE(RtcpParseCommonHeader(buffer, i, &header));
+}
+
+TEST_F(RtcpParseCommonHeaderTest, Version) {
+  // Version 2 is the only allowed for now.
+  for (int v = 0; v < 4; ++v) {
+    buffer[0] = v << 6;
+    EXPECT_EQ(v == 2, RtcpParseCommonHeader(
+                          buffer, RtcpCommonHeader::kHeaderSizeBytes, &header));
+  }
+}
+
+TEST_F(RtcpParseCommonHeaderTest, PacketSize) {
+  // Set v = 2, leave p, fmt, pt as 0.
+  buffer[0] = 2 << 6;
+
+  const size_t kBlockSize = 3;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockSize);
+  const size_t kSizeInBytes = (kBlockSize + 1) * 4;
+
+  EXPECT_FALSE(RtcpParseCommonHeader(buffer, kSizeInBytes - 1, &header));
+  EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+}
+
+TEST_F(RtcpParseCommonHeaderTest, PayloadSize) {
+  // Set v = 2, p = 1, but leave fmt, pt as 0.
+  buffer[0] = (2 << 6) | (1 << 5);
+
+  // Padding bit set, but no byte for padding (can't specify padding length).
+  EXPECT_FALSE(RtcpParseCommonHeader(buffer, 4, &header));
+
+  const size_t kBlockSize = 3;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockSize);
+  const size_t kSizeInBytes = (kBlockSize + 1) * 4;
+  const size_t kPayloadSizeBytes =
+      kSizeInBytes - RtcpCommonHeader::kHeaderSizeBytes;
+
+  // Padding one byte larger than possible.
+  buffer[kSizeInBytes - 1] = kPayloadSizeBytes + 1;
+  EXPECT_FALSE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+
+  // Pure padding packet?
+  buffer[kSizeInBytes - 1] = kPayloadSizeBytes;
+  EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+  EXPECT_EQ(kPayloadSizeBytes, header.padding_bytes);
+  EXPECT_EQ(0u, header.payload_size_bytes);
+
+  // Single byte of actual data.
+  buffer[kSizeInBytes - 1] = kPayloadSizeBytes - 1;
+  EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+  EXPECT_EQ(kPayloadSizeBytes - 1, header.padding_bytes);
+  EXPECT_EQ(1u, header.payload_size_bytes);
+}
+
+TEST_F(RtcpParseCommonHeaderTest, FormatAndPayloadType) {
+  // Format/count and packet type both set to max values.
+  const uint8_t kCountOrFormat = 0x1F;
+  const uint8_t kPacketType = 0xFF;
+  buffer[0] = 2 << 6;  // V = 2.
+  buffer[0] |= kCountOrFormat;
+  buffer[1] = kPacketType;
+
+  EXPECT_TRUE(RtcpParseCommonHeader(buffer, RtcpCommonHeader::kHeaderSizeBytes,
+                                    &header));
+  EXPECT_EQ(kCountOrFormat, header.count_or_format);
+  EXPECT_EQ(kPacketType, header.packet_type);
+}
+
+}  // namespace rtcp
 }  // namespace webrtc