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