LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/rtp_rtcp/source - rtp_format_vp8.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 414 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
      12             : 
      13             : #include <assert.h>  // assert
      14             : #include <string.h>  // memcpy
      15             : 
      16             : #include <vector>
      17             : 
      18             : #include "webrtc/base/logging.h"
      19             : #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
      20             : #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
      21             : 
      22             : namespace webrtc {
      23             : namespace {
      24           0 : int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
      25             :                       const uint8_t** data,
      26             :                       size_t* data_length,
      27             :                       size_t* parsed_bytes) {
      28           0 :   assert(vp8 != NULL);
      29           0 :   if (*data_length == 0)
      30           0 :     return -1;
      31             : 
      32           0 :   vp8->pictureId = (**data & 0x7F);
      33           0 :   if (**data & 0x80) {
      34           0 :     (*data)++;
      35           0 :     (*parsed_bytes)++;
      36           0 :     if (--(*data_length) == 0)
      37           0 :       return -1;
      38             :     // PictureId is 15 bits
      39           0 :     vp8->pictureId = (vp8->pictureId << 8) + **data;
      40             :   }
      41           0 :   (*data)++;
      42           0 :   (*parsed_bytes)++;
      43           0 :   (*data_length)--;
      44           0 :   return 0;
      45             : }
      46             : 
      47           0 : int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8,
      48             :                       const uint8_t** data,
      49             :                       size_t* data_length,
      50             :                       size_t* parsed_bytes) {
      51           0 :   assert(vp8 != NULL);
      52           0 :   if (*data_length == 0)
      53           0 :     return -1;
      54             : 
      55           0 :   vp8->tl0PicIdx = **data;
      56           0 :   (*data)++;
      57           0 :   (*parsed_bytes)++;
      58           0 :   (*data_length)--;
      59           0 :   return 0;
      60             : }
      61             : 
      62           0 : int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8,
      63             :                          const uint8_t** data,
      64             :                          size_t* data_length,
      65             :                          size_t* parsed_bytes,
      66             :                          bool has_tid,
      67             :                          bool has_key_idx) {
      68           0 :   assert(vp8 != NULL);
      69           0 :   if (*data_length == 0)
      70           0 :     return -1;
      71             : 
      72           0 :   if (has_tid) {
      73           0 :     vp8->temporalIdx = ((**data >> 6) & 0x03);
      74           0 :     vp8->layerSync = (**data & 0x20) ? true : false;  // Y bit
      75             :   }
      76           0 :   if (has_key_idx) {
      77           0 :     vp8->keyIdx = (**data & 0x1F);
      78             :   }
      79           0 :   (*data)++;
      80           0 :   (*parsed_bytes)++;
      81           0 :   (*data_length)--;
      82           0 :   return 0;
      83             : }
      84             : 
      85           0 : int ParseVP8Extension(RTPVideoHeaderVP8* vp8,
      86             :                       const uint8_t* data,
      87             :                       size_t data_length) {
      88           0 :   assert(vp8 != NULL);
      89           0 :   assert(data_length > 0);
      90           0 :   size_t parsed_bytes = 0;
      91             :   // Optional X field is present.
      92           0 :   bool has_picture_id = (*data & 0x80) ? true : false;   // I bit
      93           0 :   bool has_tl0_pic_idx = (*data & 0x40) ? true : false;  // L bit
      94           0 :   bool has_tid = (*data & 0x20) ? true : false;          // T bit
      95           0 :   bool has_key_idx = (*data & 0x10) ? true : false;      // K bit
      96             : 
      97             :   // Advance data and decrease remaining payload size.
      98           0 :   data++;
      99           0 :   parsed_bytes++;
     100           0 :   data_length--;
     101             : 
     102           0 :   if (has_picture_id) {
     103           0 :     if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) {
     104           0 :       return -1;
     105             :     }
     106             :   }
     107             : 
     108           0 :   if (has_tl0_pic_idx) {
     109           0 :     if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) {
     110           0 :       return -1;
     111             :     }
     112             :   }
     113             : 
     114           0 :   if (has_tid || has_key_idx) {
     115           0 :     if (ParseVP8TIDAndKeyIdx(
     116             :             vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) !=
     117             :         0) {
     118           0 :       return -1;
     119             :     }
     120             :   }
     121           0 :   return static_cast<int>(parsed_bytes);
     122             : }
     123             : 
     124           0 : int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload,
     125             :                       const uint8_t* data,
     126             :                       size_t data_length) {
     127           0 :   assert(parsed_payload != NULL);
     128           0 :   if (parsed_payload->frame_type != kVideoFrameKey) {
     129             :     // Included in payload header for I-frames.
     130           0 :     return 0;
     131             :   }
     132           0 :   if (data_length < 10) {
     133             :     // For an I-frame we should always have the uncompressed VP8 header
     134             :     // in the beginning of the partition.
     135           0 :     return -1;
     136             :   }
     137           0 :   parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF;
     138           0 :   parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF;
     139           0 :   return 0;
     140             : }
     141             : }  // namespace
     142             : 
     143             : // Define how the VP8PacketizerModes are implemented.
     144             : // Modes are: kStrict, kAggregate, kEqualSize.
     145             : const RtpPacketizerVp8::AggregationMode RtpPacketizerVp8::aggr_modes_
     146             :     [kNumModes] = {kAggrNone, kAggrPartitions, kAggrFragments};
     147             : const bool RtpPacketizerVp8::balance_modes_[kNumModes] = {true, true, true};
     148             : const bool RtpPacketizerVp8::separate_first_modes_[kNumModes] = {true, false,
     149             :                                                                  false};
     150             : 
     151           0 : RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
     152             :                                    size_t max_payload_len,
     153           0 :                                    VP8PacketizerMode mode)
     154             :     : payload_data_(NULL),
     155             :       payload_size_(0),
     156             :       vp8_fixed_payload_descriptor_bytes_(1),
     157           0 :       aggr_mode_(aggr_modes_[mode]),
     158           0 :       balance_(balance_modes_[mode]),
     159           0 :       separate_first_(separate_first_modes_[mode]),
     160             :       hdr_info_(hdr_info),
     161             :       num_partitions_(0),
     162             :       max_payload_len_(max_payload_len),
     163           0 :       packets_calculated_(false) {
     164           0 : }
     165             : 
     166           0 : RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
     167           0 :                                    size_t max_payload_len)
     168             :     : payload_data_(NULL),
     169             :       payload_size_(0),
     170             :       part_info_(),
     171             :       vp8_fixed_payload_descriptor_bytes_(1),
     172           0 :       aggr_mode_(aggr_modes_[kEqualSize]),
     173           0 :       balance_(balance_modes_[kEqualSize]),
     174           0 :       separate_first_(separate_first_modes_[kEqualSize]),
     175             :       hdr_info_(hdr_info),
     176             :       num_partitions_(0),
     177             :       max_payload_len_(max_payload_len),
     178           0 :       packets_calculated_(false) {
     179           0 : }
     180             : 
     181           0 : RtpPacketizerVp8::~RtpPacketizerVp8() {
     182           0 : }
     183             : 
     184           0 : void RtpPacketizerVp8::SetPayloadData(
     185             :     const uint8_t* payload_data,
     186             :     size_t payload_size,
     187             :     const RTPFragmentationHeader* fragmentation) {
     188           0 :   payload_data_ = payload_data;
     189           0 :   payload_size_ = payload_size;
     190           0 :   if (fragmentation) {
     191           0 :     part_info_.CopyFrom(*fragmentation);
     192           0 :     num_partitions_ = fragmentation->fragmentationVectorSize;
     193             :   } else {
     194           0 :     part_info_.VerifyAndAllocateFragmentationHeader(1);
     195           0 :     part_info_.fragmentationLength[0] = payload_size;
     196           0 :     part_info_.fragmentationOffset[0] = 0;
     197           0 :     num_partitions_ = part_info_.fragmentationVectorSize;
     198             :   }
     199           0 : }
     200             : 
     201           0 : bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet, bool* last_packet) {
     202           0 :   RTC_DCHECK(packet);
     203           0 :   RTC_DCHECK(last_packet);
     204           0 :   if (!packets_calculated_) {
     205           0 :     int ret = 0;
     206           0 :     if (aggr_mode_ == kAggrPartitions && balance_) {
     207           0 :       ret = GeneratePacketsBalancedAggregates();
     208             :     } else {
     209           0 :       ret = GeneratePackets();
     210             :     }
     211           0 :     if (ret < 0) {
     212           0 :       return false;
     213             :     }
     214             :   }
     215           0 :   if (packets_.empty()) {
     216           0 :     return false;
     217             :   }
     218           0 :   InfoStruct packet_info = packets_.front();
     219           0 :   packets_.pop();
     220             : 
     221           0 :   uint8_t* buffer = packet->AllocatePayload(max_payload_len_);
     222           0 :   int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
     223           0 :   if (bytes < 0) {
     224           0 :     return false;
     225             :   }
     226           0 :   packet->SetPayloadSize(bytes);
     227           0 :   *last_packet = packets_.empty();
     228           0 :   packet->SetMarker(*last_packet);
     229           0 :   return true;
     230             : }
     231             : 
     232           0 : ProtectionType RtpPacketizerVp8::GetProtectionType() {
     233             :   bool protect =
     234           0 :       hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx;
     235           0 :   return protect ? kProtectedPacket : kUnprotectedPacket;
     236             : }
     237             : 
     238           0 : StorageType RtpPacketizerVp8::GetStorageType(uint32_t retransmission_settings) {
     239           0 :   if (hdr_info_.temporalIdx == 0 &&
     240           0 :       !(retransmission_settings & kRetransmitBaseLayer)) {
     241           0 :     return kDontRetransmit;
     242             :   }
     243           0 :   if (hdr_info_.temporalIdx != kNoTemporalIdx &&
     244           0 :              hdr_info_.temporalIdx > 0 &&
     245           0 :              !(retransmission_settings & kRetransmitHigherLayers)) {
     246           0 :     return kDontRetransmit;
     247             :   }
     248           0 :   return kAllowRetransmission;
     249             : }
     250             : 
     251           0 : std::string RtpPacketizerVp8::ToString() {
     252           0 :   return "RtpPacketizerVp8";
     253             : }
     254             : 
     255           0 : size_t RtpPacketizerVp8::CalcNextSize(size_t max_payload_len,
     256             :                                       size_t remaining_bytes,
     257             :                                       bool split_payload) const {
     258           0 :   if (max_payload_len == 0 || remaining_bytes == 0) {
     259           0 :     return 0;
     260             :   }
     261           0 :   if (!split_payload) {
     262           0 :     return max_payload_len >= remaining_bytes ? remaining_bytes : 0;
     263             :   }
     264             : 
     265           0 :   if (balance_) {
     266             :     // Balance payload sizes to produce (almost) equal size
     267             :     // fragments.
     268             :     // Number of fragments for remaining_bytes:
     269           0 :     size_t num_frags = remaining_bytes / max_payload_len + 1;
     270             :     // Number of bytes in this fragment:
     271             :     return static_cast<size_t>(
     272           0 :         static_cast<double>(remaining_bytes) / num_frags + 0.5);
     273             :   } else {
     274           0 :     return max_payload_len >= remaining_bytes ? remaining_bytes
     275           0 :                                               : max_payload_len;
     276             :   }
     277             : }
     278             : 
     279           0 : int RtpPacketizerVp8::GeneratePackets() {
     280           0 :   if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
     281           0 :                              PayloadDescriptorExtraLength() + 1) {
     282             :     // The provided payload length is not long enough for the payload
     283             :     // descriptor and one payload byte. Return an error.
     284           0 :     return -1;
     285             :   }
     286           0 :   size_t total_bytes_processed = 0;
     287           0 :   bool start_on_new_fragment = true;
     288           0 :   bool beginning = true;
     289           0 :   size_t part_ix = 0;
     290           0 :   while (total_bytes_processed < payload_size_) {
     291           0 :     size_t packet_bytes = 0;    // How much data to send in this packet.
     292           0 :     bool split_payload = true;  // Splitting of partitions is initially allowed.
     293           0 :     size_t remaining_in_partition = part_info_.fragmentationOffset[part_ix] -
     294             :                                  total_bytes_processed +
     295           0 :                                  part_info_.fragmentationLength[part_ix];
     296             :     size_t rem_payload_len =
     297           0 :         max_payload_len_ -
     298           0 :         (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
     299           0 :     size_t first_partition_in_packet = part_ix;
     300             : 
     301           0 :     while (size_t next_size = CalcNextSize(
     302           0 :                rem_payload_len, remaining_in_partition, split_payload)) {
     303           0 :       packet_bytes += next_size;
     304           0 :       rem_payload_len -= next_size;
     305           0 :       remaining_in_partition -= next_size;
     306             : 
     307           0 :       if (remaining_in_partition == 0 && !(beginning && separate_first_)) {
     308             :         // Advance to next partition?
     309             :         // Check that there are more partitions; verify that we are either
     310             :         // allowed to aggregate fragments, or that we are allowed to
     311             :         // aggregate intact partitions and that we started this packet
     312             :         // with an intact partition (indicated by first_fragment_ == true).
     313           0 :         if (part_ix + 1 < num_partitions_ &&
     314           0 :             ((aggr_mode_ == kAggrFragments) ||
     315           0 :              (aggr_mode_ == kAggrPartitions && start_on_new_fragment))) {
     316           0 :           assert(part_ix < num_partitions_);
     317           0 :           remaining_in_partition = part_info_.fragmentationLength[++part_ix];
     318             :           // Disallow splitting unless kAggrFragments. In kAggrPartitions,
     319             :           // we can only aggregate intact partitions.
     320           0 :           split_payload = (aggr_mode_ == kAggrFragments);
     321             :         }
     322           0 :       } else if (balance_ && remaining_in_partition > 0) {
     323           0 :         break;
     324             :       }
     325           0 :     }
     326           0 :     if (remaining_in_partition == 0) {
     327           0 :       ++part_ix;  // Advance to next partition.
     328             :     }
     329           0 :     assert(packet_bytes > 0);
     330             : 
     331           0 :     QueuePacket(total_bytes_processed,
     332             :                 packet_bytes,
     333             :                 first_partition_in_packet,
     334           0 :                 start_on_new_fragment);
     335           0 :     total_bytes_processed += packet_bytes;
     336           0 :     start_on_new_fragment = (remaining_in_partition == 0);
     337           0 :     beginning = false;  // Next packet cannot be first packet in frame.
     338             :   }
     339           0 :   packets_calculated_ = true;
     340           0 :   assert(total_bytes_processed == payload_size_);
     341           0 :   return 0;
     342             : }
     343             : 
     344           0 : int RtpPacketizerVp8::GeneratePacketsBalancedAggregates() {
     345           0 :   if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
     346           0 :                              PayloadDescriptorExtraLength() + 1) {
     347             :     // The provided payload length is not long enough for the payload
     348             :     // descriptor and one payload byte. Return an error.
     349           0 :     return -1;
     350             :   }
     351           0 :   std::vector<int> partition_decision;
     352             :   const size_t overhead =
     353           0 :       vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
     354           0 :   const size_t max_payload_len = max_payload_len_ - overhead;
     355             :   int min_size, max_size;
     356           0 :   AggregateSmallPartitions(&partition_decision, &min_size, &max_size);
     357             : 
     358           0 :   size_t total_bytes_processed = 0;
     359           0 :   size_t part_ix = 0;
     360           0 :   while (part_ix < num_partitions_) {
     361           0 :     if (partition_decision[part_ix] == -1) {
     362             :       // Split large partitions.
     363           0 :       size_t remaining_partition = part_info_.fragmentationLength[part_ix];
     364           0 :       size_t num_fragments = Vp8PartitionAggregator::CalcNumberOfFragments(
     365           0 :           remaining_partition, max_payload_len, overhead, min_size, max_size);
     366             :       const size_t packet_bytes =
     367           0 :           (remaining_partition + num_fragments - 1) / num_fragments;
     368           0 :       for (size_t n = 0; n < num_fragments; ++n) {
     369           0 :         const size_t this_packet_bytes = packet_bytes < remaining_partition
     370           0 :                                              ? packet_bytes
     371           0 :                                              : remaining_partition;
     372           0 :         QueuePacket(
     373           0 :             total_bytes_processed, this_packet_bytes, part_ix, (n == 0));
     374           0 :         remaining_partition -= this_packet_bytes;
     375           0 :         total_bytes_processed += this_packet_bytes;
     376           0 :         if (static_cast<int>(this_packet_bytes) < min_size) {
     377           0 :           min_size = this_packet_bytes;
     378             :         }
     379           0 :         if (static_cast<int>(this_packet_bytes) > max_size) {
     380           0 :           max_size = this_packet_bytes;
     381             :         }
     382             :       }
     383           0 :       assert(remaining_partition == 0);
     384           0 :       ++part_ix;
     385             :     } else {
     386           0 :       size_t this_packet_bytes = 0;
     387           0 :       const size_t first_partition_in_packet = part_ix;
     388           0 :       const int aggregation_index = partition_decision[part_ix];
     389           0 :       while (part_ix < partition_decision.size() &&
     390           0 :              partition_decision[part_ix] == aggregation_index) {
     391             :         // Collect all partitions that were aggregated into the same packet.
     392           0 :         this_packet_bytes += part_info_.fragmentationLength[part_ix];
     393           0 :         ++part_ix;
     394             :       }
     395             :       QueuePacket(total_bytes_processed,
     396             :                   this_packet_bytes,
     397             :                   first_partition_in_packet,
     398           0 :                   true);
     399           0 :       total_bytes_processed += this_packet_bytes;
     400             :     }
     401             :   }
     402           0 :   packets_calculated_ = true;
     403           0 :   return 0;
     404             : }
     405             : 
     406           0 : void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
     407             :                                                 int* min_size,
     408             :                                                 int* max_size) {
     409           0 :   assert(min_size && max_size);
     410           0 :   *min_size = -1;
     411           0 :   *max_size = -1;
     412           0 :   assert(partition_vec);
     413           0 :   partition_vec->assign(num_partitions_, -1);
     414             :   const size_t overhead =
     415           0 :       vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
     416           0 :   const size_t max_payload_len = max_payload_len_ - overhead;
     417           0 :   size_t first_in_set = 0;
     418           0 :   size_t last_in_set = 0;
     419           0 :   int num_aggregate_packets = 0;
     420             :   // Find sets of partitions smaller than max_payload_len_.
     421           0 :   while (first_in_set < num_partitions_) {
     422           0 :     if (part_info_.fragmentationLength[first_in_set] < max_payload_len) {
     423             :       // Found start of a set.
     424           0 :       last_in_set = first_in_set;
     425           0 :       while (last_in_set + 1 < num_partitions_ &&
     426           0 :              part_info_.fragmentationLength[last_in_set + 1] <
     427             :                  max_payload_len) {
     428           0 :         ++last_in_set;
     429             :       }
     430             :       // Found end of a set. Run optimized aggregator. It is ok if start == end.
     431           0 :       Vp8PartitionAggregator aggregator(part_info_, first_in_set, last_in_set);
     432           0 :       if (*min_size >= 0 && *max_size >= 0) {
     433           0 :         aggregator.SetPriorMinMax(*min_size, *max_size);
     434             :       }
     435             :       Vp8PartitionAggregator::ConfigVec optimal_config =
     436           0 :           aggregator.FindOptimalConfiguration(max_payload_len, overhead);
     437           0 :       aggregator.CalcMinMax(optimal_config, min_size, max_size);
     438           0 :       for (size_t i = first_in_set, j = 0; i <= last_in_set; ++i, ++j) {
     439             :         // Transfer configuration for this set of partitions to the joint
     440             :         // partition vector representing all partitions in the frame.
     441           0 :         (*partition_vec)[i] = num_aggregate_packets + optimal_config[j];
     442             :       }
     443           0 :       num_aggregate_packets += optimal_config.back() + 1;
     444           0 :       first_in_set = last_in_set;
     445             :     }
     446           0 :     ++first_in_set;
     447             :   }
     448           0 : }
     449             : 
     450           0 : void RtpPacketizerVp8::QueuePacket(size_t start_pos,
     451             :                                    size_t packet_size,
     452             :                                    size_t first_partition_in_packet,
     453             :                                    bool start_on_new_fragment) {
     454             :   // Write info to packet info struct and store in packet info queue.
     455             :   InfoStruct packet_info;
     456           0 :   packet_info.payload_start_pos = start_pos;
     457           0 :   packet_info.size = packet_size;
     458           0 :   packet_info.first_partition_ix = first_partition_in_packet;
     459           0 :   packet_info.first_fragment = start_on_new_fragment;
     460           0 :   packets_.push(packet_info);
     461           0 : }
     462             : 
     463           0 : int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
     464             :                                             uint8_t* buffer,
     465             :                                             size_t buffer_length) const {
     466             :   // Write the VP8 payload descriptor.
     467             :   //       0
     468             :   //       0 1 2 3 4 5 6 7 8
     469             :   //      +-+-+-+-+-+-+-+-+-+
     470             :   //      |X| |N|S| PART_ID |
     471             :   //      +-+-+-+-+-+-+-+-+-+
     472             :   // X:   |I|L|T|K|         | (mandatory if any of the below are used)
     473             :   //      +-+-+-+-+-+-+-+-+-+
     474             :   // I:   |PictureID (8/16b)| (optional)
     475             :   //      +-+-+-+-+-+-+-+-+-+
     476             :   // L:   |   TL0PIC_IDX    | (optional)
     477             :   //      +-+-+-+-+-+-+-+-+-+
     478             :   // T/K: |TID:Y|  KEYIDX   | (optional)
     479             :   //      +-+-+-+-+-+-+-+-+-+
     480             : 
     481           0 :   assert(packet_info.size > 0);
     482           0 :   buffer[0] = 0;
     483           0 :   if (XFieldPresent())
     484           0 :     buffer[0] |= kXBit;
     485           0 :   if (hdr_info_.nonReference)
     486           0 :     buffer[0] |= kNBit;
     487           0 :   if (packet_info.first_fragment)
     488           0 :     buffer[0] |= kSBit;
     489           0 :   buffer[0] |= (packet_info.first_partition_ix & kPartIdField);
     490             : 
     491           0 :   const int extension_length = WriteExtensionFields(buffer, buffer_length);
     492           0 :   if (extension_length < 0)
     493           0 :     return -1;
     494             : 
     495           0 :   memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
     496           0 :          &payload_data_[packet_info.payload_start_pos],
     497           0 :          packet_info.size);
     498             : 
     499             :   // Return total length of written data.
     500           0 :   return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
     501           0 :          extension_length;
     502             : }
     503             : 
     504           0 : int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
     505             :                                            size_t buffer_length) const {
     506           0 :   size_t extension_length = 0;
     507           0 :   if (XFieldPresent()) {
     508           0 :     uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_;
     509           0 :     *x_field = 0;
     510           0 :     extension_length = 1;  // One octet for the X field.
     511           0 :     if (PictureIdPresent()) {
     512           0 :       if (WritePictureIDFields(
     513             :               x_field, buffer, buffer_length, &extension_length) < 0) {
     514           0 :         return -1;
     515             :       }
     516             :     }
     517           0 :     if (TL0PicIdxFieldPresent()) {
     518           0 :       if (WriteTl0PicIdxFields(
     519             :               x_field, buffer, buffer_length, &extension_length) < 0) {
     520           0 :         return -1;
     521             :       }
     522             :     }
     523           0 :     if (TIDFieldPresent() || KeyIdxFieldPresent()) {
     524           0 :       if (WriteTIDAndKeyIdxFields(
     525             :               x_field, buffer, buffer_length, &extension_length) < 0) {
     526           0 :         return -1;
     527             :       }
     528             :     }
     529           0 :     assert(extension_length == PayloadDescriptorExtraLength());
     530             :   }
     531           0 :   return static_cast<int>(extension_length);
     532             : }
     533             : 
     534           0 : int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
     535             :                                            uint8_t* buffer,
     536             :                                            size_t buffer_length,
     537             :                                            size_t* extension_length) const {
     538           0 :   *x_field |= kIBit;
     539           0 :   assert(buffer_length >=
     540           0 :       vp8_fixed_payload_descriptor_bytes_ + *extension_length);
     541           0 :   const int pic_id_length = WritePictureID(
     542           0 :       buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
     543           0 :       buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length);
     544           0 :   if (pic_id_length < 0)
     545           0 :     return -1;
     546           0 :   *extension_length += pic_id_length;
     547           0 :   return 0;
     548             : }
     549             : 
     550           0 : int RtpPacketizerVp8::WritePictureID(uint8_t* buffer,
     551             :                                      size_t buffer_length) const {
     552           0 :   const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
     553           0 :   size_t picture_id_len = PictureIdLength();
     554           0 :   if (picture_id_len > buffer_length)
     555           0 :     return -1;
     556           0 :   if (picture_id_len == 2) {
     557           0 :     buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
     558           0 :     buffer[1] = pic_id & 0xFF;
     559           0 :   } else if (picture_id_len == 1) {
     560           0 :     buffer[0] = pic_id & 0x7F;
     561             :   }
     562           0 :   return static_cast<int>(picture_id_len);
     563             : }
     564             : 
     565           0 : int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
     566             :                                            uint8_t* buffer,
     567             :                                            size_t buffer_length,
     568             :                                            size_t* extension_length) const {
     569           0 :   if (buffer_length <
     570           0 :       vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
     571           0 :     return -1;
     572             :   }
     573           0 :   *x_field |= kLBit;
     574           0 :   buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
     575           0 :       hdr_info_.tl0PicIdx;
     576           0 :   ++*extension_length;
     577           0 :   return 0;
     578             : }
     579             : 
     580           0 : int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
     581             :                                               uint8_t* buffer,
     582             :                                               size_t buffer_length,
     583             :                                               size_t* extension_length) const {
     584           0 :   if (buffer_length <
     585           0 :       vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
     586           0 :     return -1;
     587             :   }
     588             :   uint8_t* data_field =
     589           0 :       &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length];
     590           0 :   *data_field = 0;
     591           0 :   if (TIDFieldPresent()) {
     592           0 :     *x_field |= kTBit;
     593           0 :     assert(hdr_info_.temporalIdx <= 3);
     594           0 :     *data_field |= hdr_info_.temporalIdx << 6;
     595           0 :     *data_field |= hdr_info_.layerSync ? kYBit : 0;
     596             :   }
     597           0 :   if (KeyIdxFieldPresent()) {
     598           0 :     *x_field |= kKBit;
     599           0 :     *data_field |= (hdr_info_.keyIdx & kKeyIdxField);
     600             :   }
     601           0 :   ++*extension_length;
     602           0 :   return 0;
     603             : }
     604             : 
     605           0 : size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
     606           0 :   size_t length_bytes = PictureIdLength();
     607           0 :   if (TL0PicIdxFieldPresent())
     608           0 :     ++length_bytes;
     609           0 :   if (TIDFieldPresent() || KeyIdxFieldPresent())
     610           0 :     ++length_bytes;
     611           0 :   if (length_bytes > 0)
     612           0 :     ++length_bytes;  // Include the extension field.
     613           0 :   return length_bytes;
     614             : }
     615             : 
     616           0 : size_t RtpPacketizerVp8::PictureIdLength() const {
     617           0 :   if (hdr_info_.pictureId == kNoPictureId) {
     618           0 :     return 0;
     619             :   }
     620           0 :   if (hdr_info_.pictureId <= 0x7F) {
     621           0 :     return 1;
     622             :   }
     623           0 :   return 2;
     624             : }
     625             : 
     626           0 : bool RtpPacketizerVp8::XFieldPresent() const {
     627           0 :   return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
     628           0 :           KeyIdxFieldPresent());
     629             : }
     630             : 
     631           0 : bool RtpPacketizerVp8::TIDFieldPresent() const {
     632           0 :   assert((hdr_info_.layerSync == false) ||
     633             :          (hdr_info_.temporalIdx != kNoTemporalIdx));
     634           0 :   return (hdr_info_.temporalIdx != kNoTemporalIdx);
     635             : }
     636             : 
     637           0 : bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
     638           0 :   return (hdr_info_.keyIdx != kNoKeyIdx);
     639             : }
     640             : 
     641           0 : bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
     642           0 :   return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
     643             : }
     644             : 
     645             : //
     646             : // VP8 format:
     647             : //
     648             : // Payload descriptor
     649             : //       0 1 2 3 4 5 6 7
     650             : //      +-+-+-+-+-+-+-+-+
     651             : //      |X|R|N|S|PartID | (REQUIRED)
     652             : //      +-+-+-+-+-+-+-+-+
     653             : // X:   |I|L|T|K|  RSV  | (OPTIONAL)
     654             : //      +-+-+-+-+-+-+-+-+
     655             : // I:   |   PictureID   | (OPTIONAL)
     656             : //      +-+-+-+-+-+-+-+-+
     657             : // L:   |   TL0PICIDX   | (OPTIONAL)
     658             : //      +-+-+-+-+-+-+-+-+
     659             : // T/K: |TID:Y| KEYIDX  | (OPTIONAL)
     660             : //      +-+-+-+-+-+-+-+-+
     661             : //
     662             : // Payload header (considered part of the actual payload, sent to decoder)
     663             : //       0 1 2 3 4 5 6 7
     664             : //      +-+-+-+-+-+-+-+-+
     665             : //      |Size0|H| VER |P|
     666             : //      +-+-+-+-+-+-+-+-+
     667             : //      |      ...      |
     668             : //      +               +
     669           0 : bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload,
     670             :                                const uint8_t* payload_data,
     671             :                                size_t payload_data_length) {
     672           0 :   assert(parsed_payload != NULL);
     673           0 :   if (payload_data_length == 0) {
     674           0 :     LOG(LS_ERROR) << "Empty payload.";
     675           0 :     return false;
     676             :   }
     677             : 
     678             :   // Parse mandatory first byte of payload descriptor.
     679           0 :   bool extension = (*payload_data & 0x80) ? true : false;               // X bit
     680           0 :   bool beginning_of_partition = (*payload_data & 0x10) ? true : false;  // S bit
     681           0 :   int partition_id = (*payload_data & 0x0F);  // PartID field
     682             : 
     683           0 :   parsed_payload->type.Video.width = 0;
     684           0 :   parsed_payload->type.Video.height = 0;
     685           0 :   parsed_payload->type.Video.is_first_packet_in_frame =
     686           0 :       beginning_of_partition && (partition_id == 0);
     687           0 :   parsed_payload->type.Video.simulcastIdx = 0;
     688           0 :   parsed_payload->type.Video.codec = kRtpVideoVp8;
     689           0 :   parsed_payload->type.Video.codecHeader.VP8.nonReference =
     690           0 :       (*payload_data & 0x20) ? true : false;  // N bit
     691           0 :   parsed_payload->type.Video.codecHeader.VP8.partitionId = partition_id;
     692           0 :   parsed_payload->type.Video.codecHeader.VP8.beginningOfPartition =
     693             :       beginning_of_partition;
     694           0 :   parsed_payload->type.Video.codecHeader.VP8.pictureId = kNoPictureId;
     695           0 :   parsed_payload->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx;
     696           0 :   parsed_payload->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx;
     697           0 :   parsed_payload->type.Video.codecHeader.VP8.layerSync = false;
     698           0 :   parsed_payload->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx;
     699             : 
     700           0 :   if (partition_id > 8) {
     701             :     // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8.
     702           0 :     return false;
     703             :   }
     704             : 
     705             :   // Advance payload_data and decrease remaining payload size.
     706           0 :   payload_data++;
     707           0 :   if (payload_data_length <= 1) {
     708           0 :     LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
     709           0 :     return false;
     710             :   }
     711           0 :   payload_data_length--;
     712             : 
     713           0 :   if (extension) {
     714             :     const int parsed_bytes =
     715           0 :         ParseVP8Extension(&parsed_payload->type.Video.codecHeader.VP8,
     716             :                           payload_data,
     717           0 :                           payload_data_length);
     718           0 :     if (parsed_bytes < 0)
     719           0 :       return false;
     720           0 :     payload_data += parsed_bytes;
     721           0 :     payload_data_length -= parsed_bytes;
     722           0 :     if (payload_data_length == 0) {
     723           0 :       LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
     724           0 :       return false;
     725             :     }
     726             :   }
     727             : 
     728             :   // Read P bit from payload header (only at beginning of first partition).
     729           0 :   if (beginning_of_partition && partition_id == 0) {
     730           0 :     parsed_payload->frame_type =
     731           0 :         (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey;
     732             :   } else {
     733           0 :     parsed_payload->frame_type = kVideoFrameDelta;
     734             :   }
     735             : 
     736           0 :   if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) !=
     737             :       0) {
     738           0 :     return false;
     739             :   }
     740             : 
     741           0 :   parsed_payload->payload = payload_data;
     742           0 :   parsed_payload->payload_length = payload_data_length;
     743           0 :   return true;
     744             : }
     745             : }  // namespace webrtc

Generated by: LCOV version 1.13