Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / rtp_rtcp / source / rtp_format_vp8.cc
index 360176b..a3d673b 100644 (file)
 
 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
 
-#include <assert.h>   // assert
+#include <assert.h>  // assert
 #include <string.h>  // memcpy
 
 #include <vector>
 
 #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
+#include "webrtc/system_wrappers/interface/logging.h"
 
 namespace webrtc {
+namespace {
+struct ParsedPayload {
+  ParsedPayload() : data(NULL), data_length(0) {}
+
+  const uint8_t* data;  // Start address of parsed payload data.
+  int data_length;      // Length of parsed payload data.
+};
+
+int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
+                      const uint8_t** data,
+                      int* data_length,
+                      int* parsed_bytes) {
+  assert(vp8 != NULL);
+  if (*data_length <= 0)
+    return -1;
+
+  vp8->pictureId = (**data & 0x7F);
+  if (**data & 0x80) {
+    (*data)++;
+    (*parsed_bytes)++;
+    if (--(*data_length) <= 0)
+      return -1;
+    // PictureId is 15 bits
+    vp8->pictureId = (vp8->pictureId << 8) + **data;
+  }
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8,
+                      const uint8_t** data,
+                      int* data_length,
+                      int* parsed_bytes) {
+  assert(vp8 != NULL);
+  if (*data_length <= 0)
+    return -1;
+
+  vp8->tl0PicIdx = **data;
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8,
+                         const uint8_t** data,
+                         int* data_length,
+                         int* parsed_bytes,
+                         bool has_tid,
+                         bool has_key_idx) {
+  assert(vp8 != NULL);
+  if (*data_length <= 0)
+    return -1;
+
+  if (has_tid) {
+    vp8->temporalIdx = ((**data >> 6) & 0x03);
+    vp8->layerSync = (**data & 0x20) ? true : false;  // Y bit
+  }
+  if (has_key_idx) {
+    vp8->keyIdx = (**data & 0x1F);
+  }
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8Extension(RTPVideoHeaderVP8* vp8,
+                      const uint8_t* data,
+                      int data_length) {
+  assert(vp8 != NULL);
+  int parsed_bytes = 0;
+  if (data_length <= 0)
+    return -1;
+  // Optional X field is present.
+  bool has_picture_id = (*data & 0x80) ? true : false;   // I bit
+  bool has_tl0_pic_idx = (*data & 0x40) ? true : false;  // L bit
+  bool has_tid = (*data & 0x20) ? true : false;          // T bit
+  bool has_key_idx = (*data & 0x10) ? true : false;      // K bit
+
+  // Advance data and decrease remaining payload size.
+  data++;
+  parsed_bytes++;
+  data_length--;
+
+  if (has_picture_id) {
+    if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) {
+      return -1;
+    }
+  }
+
+  if (has_tl0_pic_idx) {
+    if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) {
+      return -1;
+    }
+  }
+
+  if (has_tid || has_key_idx) {
+    if (ParseVP8TIDAndKeyIdx(
+            vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) !=
+        0) {
+      return -1;
+    }
+  }
+  return parsed_bytes;
+}
+
+int ParseVP8FrameSize(WebRtcRTPHeader* rtp_header,
+                      const uint8_t* data,
+                      int data_length) {
+  assert(rtp_header != NULL);
+  if (rtp_header->frameType != kVideoFrameKey) {
+    // Included in payload header for I-frames.
+    return 0;
+  }
+  if (data_length < 10) {
+    // For an I-frame we should always have the uncompressed VP8 header
+    // in the beginning of the partition.
+    return -1;
+  }
+  rtp_header->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF;
+  rtp_header->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF;
+  return 0;
+}
+
+//
+// VP8 format:
+//
+// Payload descriptor
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |X|R|N|S|PartID | (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// X:   |I|L|T|K|  RSV  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// I:   |   PictureID   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// L:   |   TL0PICIDX   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// T/K: |TID:Y| KEYIDX  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+//
+// Payload header (considered part of the actual payload, sent to decoder)
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |Size0|H| VER |P|
+//      +-+-+-+-+-+-+-+-+
+//      |      ...      |
+//      +               +
+bool ParseVP8(WebRtcRTPHeader* rtp_header,
+              const uint8_t* data,
+              int data_length,
+              ParsedPayload* payload) {
+  assert(rtp_header != NULL);
+  // Parse mandatory first byte of payload descriptor.
+  bool extension = (*data & 0x80) ? true : false;               // X bit
+  bool beginning_of_partition = (*data & 0x10) ? true : false;  // S bit
+  int partition_id = (*data & 0x0F);                            // PartID field
+
+  rtp_header->type.Video.isFirstPacket =
+      beginning_of_partition && (partition_id == 0);
+
+  rtp_header->type.Video.codecHeader.VP8.nonReference =
+      (*data & 0x20) ? true : false;  // N bit
+  rtp_header->type.Video.codecHeader.VP8.partitionId = partition_id;
+  rtp_header->type.Video.codecHeader.VP8.beginningOfPartition =
+      beginning_of_partition;
+  rtp_header->type.Video.codecHeader.VP8.pictureId = kNoPictureId;
+  rtp_header->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx;
+  rtp_header->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx;
+  rtp_header->type.Video.codecHeader.VP8.layerSync = false;
+  rtp_header->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx;
+
+  if (partition_id > 8) {
+    // Weak check for corrupt data: PartID MUST NOT be larger than 8.
+    return false;
+  }
+
+  // Advance data and decrease remaining payload size.
+  data++;
+  data_length--;
+
+  if (extension) {
+    const int parsed_bytes = ParseVP8Extension(
+        &rtp_header->type.Video.codecHeader.VP8, data, data_length);
+    if (parsed_bytes < 0)
+      return false;
+    data += parsed_bytes;
+    data_length -= parsed_bytes;
+  }
+
+  if (data_length <= 0) {
+    LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
+    return false;
+  }
+
+  // Read P bit from payload header (only at beginning of first partition).
+  if (data_length > 0 && beginning_of_partition && partition_id == 0) {
+    rtp_header->frameType = (*data & 0x01) ? kVideoFrameDelta : kVideoFrameKey;
+  } else {
+    rtp_header->frameType = kVideoFrameDelta;
+  }
+
+  if (0 != ParseVP8FrameSize(rtp_header, data, data_length)) {
+    return false;
+  }
+  payload->data = data;
+  payload->data_length = data_length;
+  return true;
+}
+}  // namespace
 
 // Define how the VP8PacketizerModes are implemented.
 // Modes are: kStrict, kAggregate, kEqualSize.
-const RtpFormatVp8::AggregationMode RtpFormatVp8::aggr_modes_[kNumModes] =
-    { kAggrNone, kAggrPartitions, kAggrFragments };
-const bool RtpFormatVp8::balance_modes_[kNumModes] =
-    { true, true, true };
-const bool RtpFormatVp8::separate_first_modes_[kNumModes] =
-    { true, false, false };
-
-RtpFormatVp8::RtpFormatVp8(const uint8_t* payload_data,
-                           uint32_t payload_size,
-                           const RTPVideoHeaderVP8& hdr_info,
-                           int max_payload_len,
-                           const RTPFragmentationHeader& fragmentation,
-                           VP8PacketizerMode mode)
-    : payload_data_(payload_data),
-      payload_size_(static_cast<int>(payload_size)),
+const RtpPacketizerVp8::AggregationMode RtpPacketizerVp8::aggr_modes_
+    [kNumModes] = {kAggrNone, kAggrPartitions, kAggrFragments};
+const bool RtpPacketizerVp8::balance_modes_[kNumModes] = {true, true, true};
+const bool RtpPacketizerVp8::separate_first_modes_[kNumModes] = {true, false,
+                                                                 false};
+
+RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
+                                   int max_payload_len,
+                                   VP8PacketizerMode mode)
+    : payload_data_(NULL),
+      payload_size_(0),
       vp8_fixed_payload_descriptor_bytes_(1),
       aggr_mode_(aggr_modes_[mode]),
       balance_(balance_modes_[mode]),
       separate_first_(separate_first_modes_[mode]),
       hdr_info_(hdr_info),
-      num_partitions_(fragmentation.fragmentationVectorSize),
+      num_partitions_(0),
       max_payload_len_(max_payload_len),
       packets_calculated_(false) {
-  part_info_.CopyFrom(fragmentation);
 }
 
-RtpFormatVp8::RtpFormatVp8(const uint8_t* payload_data,
-                           uint32_t payload_size,
-                           const RTPVideoHeaderVP8& hdr_info,
-                           int max_payload_len)
-    : payload_data_(payload_data),
-      payload_size_(static_cast<int>(payload_size)),
+RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
+                                   int max_payload_len)
+    : payload_data_(NULL),
+      payload_size_(0),
       part_info_(),
       vp8_fixed_payload_descriptor_bytes_(1),
       aggr_mode_(aggr_modes_[kEqualSize]),
       balance_(balance_modes_[kEqualSize]),
       separate_first_(separate_first_modes_[kEqualSize]),
       hdr_info_(hdr_info),
-      num_partitions_(1),
+      num_partitions_(0),
       max_payload_len_(max_payload_len),
       packets_calculated_(false) {
+}
+
+RtpPacketizerVp8::~RtpPacketizerVp8() {
+}
+
+void RtpPacketizerVp8::SetPayloadData(
+    const uint8_t* payload_data,
+    size_t payload_size,
+    const RTPFragmentationHeader* fragmentation) {
+  payload_data_ = payload_data;
+  payload_size_ = payload_size;
+  if (fragmentation) {
+    part_info_.CopyFrom(*fragmentation);
+    num_partitions_ = fragmentation->fragmentationVectorSize;
+  } else {
     part_info_.VerifyAndAllocateFragmentationHeader(1);
     part_info_.fragmentationLength[0] = payload_size;
     part_info_.fragmentationOffset[0] = 0;
+    num_partitions_ = part_info_.fragmentationVectorSize;
+  }
 }
 
-RtpFormatVp8::~RtpFormatVp8() {}
-
-int RtpFormatVp8::NextPacket(uint8_t* buffer,
-                             int* bytes_to_send,
-                             bool* last_packet) {
+bool RtpPacketizerVp8::NextPacket(uint8_t* buffer,
+                                  size_t* bytes_to_send,
+                                  bool* last_packet) {
   if (!packets_calculated_) {
     int ret = 0;
     if (aggr_mode_ == kAggrPartitions && balance_) {
@@ -80,26 +302,51 @@ int RtpFormatVp8::NextPacket(uint8_t* buffer,
       ret = GeneratePackets();
     }
     if (ret < 0) {
-      return ret;
+      return false;
     }
   }
   if (packets_.empty()) {
-    return -1;
+    return false;
   }
   InfoStruct packet_info = packets_.front();
   packets_.pop();
 
-  *bytes_to_send = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
-  if (*bytes_to_send < 0) {
-    return -1;
+  int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
+  if (bytes < 0) {
+    return false;
   }
+  *bytes_to_send = bytes;
 
   *last_packet = packets_.empty();
-  return packet_info.first_partition_ix;
+  return true;
+}
+
+ProtectionType RtpPacketizerVp8::GetProtectionType() {
+  bool protect =
+      hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx;
+  return protect ? kProtectedPacket : kUnprotectedPacket;
+}
+
+StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) {
+  StorageType storage = kAllowRetransmission;
+  if (hdr_info_.temporalIdx == 0 &&
+      !(retransmission_settings & kRetransmitBaseLayer)) {
+    storage = kDontRetransmit;
+  } else if (hdr_info_.temporalIdx != kNoTemporalIdx &&
+             hdr_info_.temporalIdx > 0 &&
+             !(retransmission_settings & kRetransmitHigherLayers)) {
+    storage = kDontRetransmit;
+  }
+  return storage;
+}
+
+std::string RtpPacketizerVp8::ToString() {
+  return "RtpPacketizerVp8";
 }
 
-int RtpFormatVp8::CalcNextSize(int max_payload_len, int remaining_bytes,
-                               bool split_payload) const {
+int RtpPacketizerVp8::CalcNextSize(int max_payload_len,
+                                   int remaining_bytes,
+                                   bool split_payload) const {
   if (max_payload_len == 0 || remaining_bytes == 0) {
     return 0;
   }
@@ -113,17 +360,17 @@ int RtpFormatVp8::CalcNextSize(int max_payload_len, int remaining_bytes,
     // Number of fragments for remaining_bytes:
     int num_frags = remaining_bytes / max_payload_len + 1;
     // Number of bytes in this fragment:
-    return static_cast<int>(static_cast<double>(remaining_bytes)
-                            / num_frags + 0.5);
+    return static_cast<int>(static_cast<double>(remaining_bytes) / num_frags +
+                            0.5);
   } else {
     return max_payload_len >= remaining_bytes ? remaining_bytes
-        : max_payload_len;
+                                              : max_payload_len;
   }
 }
 
-int RtpFormatVp8::GeneratePackets() {
-  if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_
-      + PayloadDescriptorExtraLength() + 1) {
+int RtpPacketizerVp8::GeneratePackets() {
+  if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
+                             PayloadDescriptorExtraLength() + 1) {
     // The provided payload length is not long enough for the payload
     // descriptor and one payload byte. Return an error.
     return -1;
@@ -133,16 +380,18 @@ int RtpFormatVp8::GeneratePackets() {
   bool beginning = true;
   int part_ix = 0;
   while (total_bytes_processed < payload_size_) {
-    int packet_bytes = 0;  // How much data to send in this packet.
+    int packet_bytes = 0;       // How much data to send in this packet.
     bool split_payload = true;  // Splitting of partitions is initially allowed.
     int remaining_in_partition = part_info_.fragmentationOffset[part_ix] -
-        total_bytes_processed + part_info_.fragmentationLength[part_ix];
-    int rem_payload_len = max_payload_len_ -
+                                 total_bytes_processed +
+                                 part_info_.fragmentationLength[part_ix];
+    int rem_payload_len =
+        max_payload_len_ -
         (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
     int first_partition_in_packet = part_ix;
 
-    while (int next_size = CalcNextSize(rem_payload_len, remaining_in_partition,
-                                        split_payload)) {
+    while (int next_size = CalcNextSize(
+               rem_payload_len, remaining_in_partition, split_payload)) {
       packet_bytes += next_size;
       rem_payload_len -= next_size;
       remaining_in_partition -= next_size;
@@ -155,7 +404,7 @@ int RtpFormatVp8::GeneratePackets() {
         // with an intact partition (indicated by first_fragment_ == true).
         if (part_ix + 1 < num_partitions_ &&
             ((aggr_mode_ == kAggrFragments) ||
-                (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) {
+             (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) {
           assert(part_ix < num_partitions_);
           remaining_in_partition = part_info_.fragmentationLength[++part_ix];
           // Disallow splitting unless kAggrFragments. In kAggrPartitions,
@@ -171,7 +420,9 @@ int RtpFormatVp8::GeneratePackets() {
     }
     assert(packet_bytes > 0);
 
-    QueuePacket(total_bytes_processed, packet_bytes, first_partition_in_packet,
+    QueuePacket(total_bytes_processed,
+                packet_bytes,
+                first_partition_in_packet,
                 start_on_new_fragment);
     total_bytes_processed += packet_bytes;
     start_on_new_fragment = (remaining_in_partition == 0);
@@ -182,16 +433,16 @@ int RtpFormatVp8::GeneratePackets() {
   return 0;
 }
 
-int RtpFormatVp8::GeneratePacketsBalancedAggregates() {
-  if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_
-      + PayloadDescriptorExtraLength() + 1) {
+int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
+  if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
+                             PayloadDescriptorExtraLength() + 1) {
     // The provided payload length is not long enough for the payload
     // descriptor and one payload byte. Return an error.
     return -1;
   }
   std::vector<int> partition_decision;
-  const int overhead = vp8_fixed_payload_descriptor_bytes_ +
-      PayloadDescriptorExtraLength();
+  const int overhead =
+      vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
   const uint32_t max_payload_len = max_payload_len_ - overhead;
   int min_size, max_size;
   AggregateSmallPartitions(&partition_decision, &min_size, &max_size);
@@ -207,10 +458,11 @@ int RtpFormatVp8::GeneratePacketsBalancedAggregates() {
       const int packet_bytes =
           (remaining_partition + num_fragments - 1) / num_fragments;
       for (int n = 0; n < num_fragments; ++n) {
-        const int this_packet_bytes = packet_bytes < remaining_partition ?
-            packet_bytes : remaining_partition;
-        QueuePacket(total_bytes_processed, this_packet_bytes, part_ix,
-                    (n == 0));
+        const int this_packet_bytes = packet_bytes < remaining_partition
+                                          ? packet_bytes
+                                          : remaining_partition;
+        QueuePacket(
+            total_bytes_processed, this_packet_bytes, part_ix, (n == 0));
         remaining_partition -= this_packet_bytes;
         total_bytes_processed += this_packet_bytes;
         if (this_packet_bytes < min_size) {
@@ -227,13 +479,15 @@ int RtpFormatVp8::GeneratePacketsBalancedAggregates() {
       const int first_partition_in_packet = part_ix;
       const int aggregation_index = partition_decision[part_ix];
       while (static_cast<size_t>(part_ix) < partition_decision.size() &&
-          partition_decision[part_ix] == aggregation_index) {
+             partition_decision[part_ix] == aggregation_index) {
         // Collect all partitions that were aggregated into the same packet.
         this_packet_bytes += part_info_.fragmentationLength[part_ix];
         ++part_ix;
       }
-      QueuePacket(total_bytes_processed, this_packet_bytes,
-                  first_partition_in_packet, true);
+      QueuePacket(total_bytes_processed,
+                  this_packet_bytes,
+                  first_partition_in_packet,
+                  true);
       total_bytes_processed += this_packet_bytes;
     }
   }
@@ -241,16 +495,16 @@ int RtpFormatVp8::GeneratePacketsBalancedAggregates() {
   return 0;
 }
 
-void RtpFormatVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
-                                            int* min_size,
-                                            int* max_size) {
+void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
+                                                int* min_size,
+                                                int* max_size) {
   assert(min_size && max_size);
   *min_size = -1;
   *max_size = -1;
   assert(partition_vec);
   partition_vec->assign(num_partitions_, -1);
-  const int overhead = vp8_fixed_payload_descriptor_bytes_ +
-      PayloadDescriptorExtraLength();
+  const int overhead =
+      vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
   const uint32_t max_payload_len = max_payload_len_ - overhead;
   int first_in_set = 0;
   int last_in_set = 0;
@@ -261,12 +515,12 @@ void RtpFormatVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
       // Found start of a set.
       last_in_set = first_in_set;
       while (last_in_set + 1 < num_partitions_ &&
-          part_info_.fragmentationLength[last_in_set + 1] < max_payload_len) {
+             part_info_.fragmentationLength[last_in_set + 1] <
+                 max_payload_len) {
         ++last_in_set;
       }
       // Found end of a set. Run optimized aggregator. It is ok if start == end.
-      Vp8PartitionAggregator aggregator(part_info_, first_in_set,
-                                        last_in_set);
+      Vp8PartitionAggregator aggregator(part_info_, first_in_set, last_in_set);
       if (*min_size >= 0 && *max_size >= 0) {
         aggregator.SetPriorMinMax(*min_size, *max_size);
       }
@@ -285,10 +539,10 @@ void RtpFormatVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
   }
 }
 
-void RtpFormatVp8::QueuePacket(int start_pos,
-                               int packet_size,
-                               int first_partition_in_packet,
-                               bool start_on_new_fragment) {
+void RtpPacketizerVp8::QueuePacket(int start_pos,
+                                   int packet_size,
+                                   int first_partition_in_packet,
+                                   bool start_on_new_fragment) {
   // Write info to packet info struct and store in packet info queue.
   InfoStruct packet_info;
   packet_info.payload_start_pos = start_pos;
@@ -298,9 +552,9 @@ void RtpFormatVp8::QueuePacket(int start_pos,
   packets_.push(packet_info);
 }
 
-int RtpFormatVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
-                                        uint8_t* buffer,
-                                        int buffer_length) const {
+int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
+                                            uint8_t* buffer,
+                                            int buffer_length) const {
   // Write the VP8 payload descriptor.
   //       0
   //       0 1 2 3 4 5 6 7 8
@@ -318,43 +572,47 @@ int RtpFormatVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
 
   assert(packet_info.size > 0);
   buffer[0] = 0;
-  if (XFieldPresent())            buffer[0] |= kXBit;
-  if (hdr_info_.nonReference)     buffer[0] |= kNBit;
-  if (packet_info.first_fragment) buffer[0] |= kSBit;
+  if (XFieldPresent())
+    buffer[0] |= kXBit;
+  if (hdr_info_.nonReference)
+    buffer[0] |= kNBit;
+  if (packet_info.first_fragment)
+    buffer[0] |= kSBit;
   buffer[0] |= (packet_info.first_partition_ix & kPartIdField);
 
   const int extension_length = WriteExtensionFields(buffer, buffer_length);
 
   memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
-         &payload_data_[packet_info.payload_start_pos], packet_info.size);
+         &payload_data_[packet_info.payload_start_pos],
+         packet_info.size);
 
   // Return total length of written data.
-  return packet_info.size + vp8_fixed_payload_descriptor_bytes_
-      + extension_length;
+  return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
+         extension_length;
 }
 
-int RtpFormatVp8::WriteExtensionFields(uint8_t* buffer,
-                                       int buffer_length) const {
+int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
+                                           int buffer_length) const {
   int extension_length = 0;
   if (XFieldPresent()) {
     uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_;
     *x_field = 0;
     extension_length = 1;  // One octet for the X field.
     if (PictureIdPresent()) {
-      if (WritePictureIDFields(x_field, buffer, buffer_length,
-                               &extension_length) < 0) {
+      if (WritePictureIDFields(
+              x_field, buffer, buffer_length, &extension_length) < 0) {
         return -1;
       }
     }
     if (TL0PicIdxFieldPresent()) {
-      if (WriteTl0PicIdxFields(x_field, buffer, buffer_length,
-                               &extension_length) < 0) {
+      if (WriteTl0PicIdxFields(
+              x_field, buffer, buffer_length, &extension_length) < 0) {
         return -1;
       }
     }
     if (TIDFieldPresent() || KeyIdxFieldPresent()) {
-      if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
-                                  &extension_length) < 0) {
+      if (WriteTIDAndKeyIdxFields(
+              x_field, buffer, buffer_length, &extension_length) < 0) {
         return -1;
       }
     }
@@ -363,26 +621,25 @@ int RtpFormatVp8::WriteExtensionFields(uint8_t* buffer,
   return extension_length;
 }
 
-int RtpFormatVp8::WritePictureIDFields(uint8_t* x_field,
-                                       uint8_t* buffer,
-                                       int buffer_length,
-                                       int* extension_length) const {
+int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
+                                           uint8_t* buffer,
+                                           int buffer_length,
+                                           int* extension_length) const {
   *x_field |= kIBit;
   const int pic_id_length = WritePictureID(
       buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
-      buffer_length - vp8_fixed_payload_descriptor_bytes_
-      - *extension_length);
-  if (pic_id_length < 0) return -1;
+      buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length);
+  if (pic_id_length < 0)
+    return -1;
   *extension_length += pic_id_length;
   return 0;
 }
 
-int RtpFormatVp8::WritePictureID(uint8_t* buffer,
-                                 int buffer_length) const {
-  const uint16_t pic_id =
-      static_cast<uint16_t> (hdr_info_.pictureId);
+int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, int buffer_length) const {
+  const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
   int picture_id_len = PictureIdLength();
-  if (picture_id_len > buffer_length) return -1;
+  if (picture_id_len > buffer_length)
+    return -1;
   if (picture_id_len == 2) {
     buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
     buffer[1] = pic_id & 0xFF;
@@ -392,27 +649,27 @@ int RtpFormatVp8::WritePictureID(uint8_t* buffer,
   return picture_id_len;
 }
 
-int RtpFormatVp8::WriteTl0PicIdxFields(uint8_t* x_field,
-                                       uint8_t* buffer,
-                                       int buffer_length,
-                                       int* extension_length) const {
-  if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length
-      + 1) {
+int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
+                                           uint8_t* buffer,
+                                           int buffer_length,
+                                           int* extension_length) const {
+  if (buffer_length <
+      vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
     return -1;
   }
   *x_field |= kLBit;
-  buffer[vp8_fixed_payload_descriptor_bytes_
-         + *extension_length] = hdr_info_.tl0PicIdx;
+  buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
+      hdr_info_.tl0PicIdx;
   ++*extension_length;
   return 0;
 }
 
-int RtpFormatVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
-                                          uint8_t* buffer,
-                                          int buffer_length,
-                                          int* extension_length) const {
-  if (buffer_length < vp8_fixed_payload_descriptor_bytes_ + *extension_length
-      + 1) {
+int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
+                                              uint8_t* buffer,
+                                              int buffer_length,
+                                              int* extension_length) const {
+  if (buffer_length <
+      vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
     return -1;
   }
   uint8_t* data_field =
@@ -420,7 +677,7 @@ int RtpFormatVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
   *data_field = 0;
   if (TIDFieldPresent()) {
     *x_field |= kTBit;
-    assert(hdr_info_.temporalIdx >= 0 && hdr_info_.temporalIdx <= 3);
+    assert(hdr_info_.temporalIdx <= 3);
     *data_field |= hdr_info_.temporalIdx << 6;
     *data_field |= hdr_info_.layerSync ? kYBit : 0;
   }
@@ -432,15 +689,18 @@ int RtpFormatVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
   return 0;
 }
 
-int RtpFormatVp8::PayloadDescriptorExtraLength() const {
+int RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
   int length_bytes = PictureIdLength();
-  if (TL0PicIdxFieldPresent()) ++length_bytes;
-  if (TIDFieldPresent() || KeyIdxFieldPresent()) ++length_bytes;
-  if (length_bytes > 0) ++length_bytes;  // Include the extension field.
+  if (TL0PicIdxFieldPresent())
+    ++length_bytes;
+  if (TIDFieldPresent() || KeyIdxFieldPresent())
+    ++length_bytes;
+  if (length_bytes > 0)
+    ++length_bytes;  // Include the extension field.
   return length_bytes;
 }
 
-int RtpFormatVp8::PictureIdLength() const {
+int RtpPacketizerVp8::PictureIdLength() const {
   if (hdr_info_.pictureId == kNoPictureId) {
     return 0;
   }
@@ -450,22 +710,43 @@ int RtpFormatVp8::PictureIdLength() const {
   return 2;
 }
 
-bool RtpFormatVp8::XFieldPresent() const {
-  return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent()
-      || KeyIdxFieldPresent());
+bool RtpPacketizerVp8::XFieldPresent() const {
+  return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
+          KeyIdxFieldPresent());
 }
 
-bool RtpFormatVp8::TIDFieldPresent() const {
+bool RtpPacketizerVp8::TIDFieldPresent() const {
   assert((hdr_info_.layerSync == false) ||
          (hdr_info_.temporalIdx != kNoTemporalIdx));
   return (hdr_info_.temporalIdx != kNoTemporalIdx);
 }
 
-bool RtpFormatVp8::KeyIdxFieldPresent() const {
+bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
   return (hdr_info_.keyIdx != kNoKeyIdx);
 }
 
-bool RtpFormatVp8::TL0PicIdxFieldPresent() const {
+bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
   return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
 }
+
+RtpDepacketizerVp8::RtpDepacketizerVp8(RtpData* const callback)
+    : callback_(callback) {
+}
+
+bool RtpDepacketizerVp8::Parse(WebRtcRTPHeader* rtp_header,
+                               const uint8_t* payload_data,
+                               size_t payload_data_length) {
+  ParsedPayload payload;
+  if (!ParseVP8(rtp_header, payload_data, payload_data_length, &payload))
+    return false;
+
+  if (payload.data_length == 0)
+    return true;
+
+  if (callback_->OnReceivedPayloadData(
+          payload.data, payload.data_length, rtp_header) != 0) {
+    return false;
+  }
+  return true;
+}
 }  // namespace webrtc