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 "modules/rtp_rtcp/source/rtp_format_vp8.h"
12 
13 #include <string.h>  // memcpy
14 
15 #include <limits>
16 #include <utility>
17 #include <vector>
18 
19 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 
23 namespace webrtc {
24 namespace {
ParseVP8PictureID(RTPVideoHeaderVP8 * vp8,const uint8_t ** data,size_t * data_length,size_t * parsed_bytes)25 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
26                       const uint8_t** data,
27                       size_t* data_length,
28                       size_t* parsed_bytes) {
29   if (*data_length == 0)
30     return -1;
31 
32   vp8->pictureId = (**data & 0x7F);
33   if (**data & 0x80) {
34     (*data)++;
35     (*parsed_bytes)++;
36     if (--(*data_length) == 0)
37       return -1;
38     // PictureId is 15 bits
39     vp8->pictureId = (vp8->pictureId << 8) + **data;
40   }
41   (*data)++;
42   (*parsed_bytes)++;
43   (*data_length)--;
44   return 0;
45 }
46 
ParseVP8Tl0PicIdx(RTPVideoHeaderVP8 * vp8,const uint8_t ** data,size_t * data_length,size_t * parsed_bytes)47 int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8,
48                       const uint8_t** data,
49                       size_t* data_length,
50                       size_t* parsed_bytes) {
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 
ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8 * vp8,const uint8_t ** data,size_t * data_length,size_t * parsed_bytes,bool has_tid,bool has_key_idx)61 int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8,
62                          const uint8_t** data,
63                          size_t* data_length,
64                          size_t* parsed_bytes,
65                          bool has_tid,
66                          bool has_key_idx) {
67   if (*data_length == 0)
68     return -1;
69 
70   if (has_tid) {
71     vp8->temporalIdx = ((**data >> 6) & 0x03);
72     vp8->layerSync = (**data & 0x20) ? true : false;  // Y bit
73   }
74   if (has_key_idx) {
75     vp8->keyIdx = (**data & 0x1F);
76   }
77   (*data)++;
78   (*parsed_bytes)++;
79   (*data_length)--;
80   return 0;
81 }
82 
ParseVP8Extension(RTPVideoHeaderVP8 * vp8,const uint8_t * data,size_t data_length)83 int ParseVP8Extension(RTPVideoHeaderVP8* vp8,
84                       const uint8_t* data,
85                       size_t data_length) {
86   RTC_DCHECK_GT(data_length, 0);
87   size_t parsed_bytes = 0;
88   // Optional X field is present.
89   bool has_picture_id = (*data & 0x80) ? true : false;   // I bit
90   bool has_tl0_pic_idx = (*data & 0x40) ? true : false;  // L bit
91   bool has_tid = (*data & 0x20) ? true : false;          // T bit
92   bool has_key_idx = (*data & 0x10) ? true : false;      // K bit
93 
94   // Advance data and decrease remaining payload size.
95   data++;
96   parsed_bytes++;
97   data_length--;
98 
99   if (has_picture_id) {
100     if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) {
101       return -1;
102     }
103   }
104 
105   if (has_tl0_pic_idx) {
106     if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) {
107       return -1;
108     }
109   }
110 
111   if (has_tid || has_key_idx) {
112     if (ParseVP8TIDAndKeyIdx(
113             vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) !=
114         0) {
115       return -1;
116     }
117   }
118   return static_cast<int>(parsed_bytes);
119 }
120 
ParseVP8FrameSize(RtpDepacketizer::ParsedPayload * parsed_payload,const uint8_t * data,size_t data_length)121 int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload,
122                       const uint8_t* data,
123                       size_t data_length) {
124   if (parsed_payload->frame_type != kVideoFrameKey) {
125     // Included in payload header for I-frames.
126     return 0;
127   }
128   if (data_length < 10) {
129     // For an I-frame we should always have the uncompressed VP8 header
130     // in the beginning of the partition.
131     return -1;
132   }
133   parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF;
134   parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF;
135   return 0;
136 }
137 
ValidateHeader(const RTPVideoHeaderVP8 & hdr_info)138 bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) {
139   if (hdr_info.pictureId != kNoPictureId) {
140     RTC_DCHECK_GE(hdr_info.pictureId, 0);
141     RTC_DCHECK_LE(hdr_info.pictureId, 0x7FFF);
142   }
143   if (hdr_info.tl0PicIdx != kNoTl0PicIdx) {
144     RTC_DCHECK_GE(hdr_info.tl0PicIdx, 0);
145     RTC_DCHECK_LE(hdr_info.tl0PicIdx, 0xFF);
146   }
147   if (hdr_info.temporalIdx != kNoTemporalIdx) {
148     RTC_DCHECK_GE(hdr_info.temporalIdx, 0);
149     RTC_DCHECK_LE(hdr_info.temporalIdx, 3);
150   } else {
151     RTC_DCHECK(!hdr_info.layerSync);
152   }
153   if (hdr_info.keyIdx != kNoKeyIdx) {
154     RTC_DCHECK_GE(hdr_info.keyIdx, 0);
155     RTC_DCHECK_LE(hdr_info.keyIdx, 0x1F);
156   }
157   return true;
158 }
159 
160 }  // namespace
161 
RtpPacketizerVp8(const RTPVideoHeaderVP8 & hdr_info,size_t max_payload_len,size_t last_packet_reduction_len)162 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
163                                    size_t max_payload_len,
164                                    size_t last_packet_reduction_len)
165     : payload_data_(NULL),
166       payload_size_(0),
167       vp8_fixed_payload_descriptor_bytes_(1),
168       hdr_info_(hdr_info),
169       max_payload_len_(max_payload_len),
170       last_packet_reduction_len_(last_packet_reduction_len) {
171   RTC_DCHECK(ValidateHeader(hdr_info));
172 }
173 
~RtpPacketizerVp8()174 RtpPacketizerVp8::~RtpPacketizerVp8() {
175 }
176 
SetPayloadData(const uint8_t * payload_data,size_t payload_size,const RTPFragmentationHeader *)177 size_t RtpPacketizerVp8::SetPayloadData(
178     const uint8_t* payload_data,
179     size_t payload_size,
180     const RTPFragmentationHeader* /* fragmentation */) {
181   payload_data_ = payload_data;
182   payload_size_ = payload_size;
183   if (GeneratePackets() < 0) {
184     return 0;
185   }
186   return packets_.size();
187 }
188 
NextPacket(RtpPacketToSend * packet)189 bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) {
190   RTC_DCHECK(packet);
191   if (packets_.empty()) {
192     return false;
193   }
194   InfoStruct packet_info = packets_.front();
195   packets_.pop();
196 
197   uint8_t* buffer = packet->AllocatePayload(
198       packets_.empty() ? max_payload_len_ - last_packet_reduction_len_
199                        : max_payload_len_);
200   int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
201   if (bytes < 0) {
202     return false;
203   }
204   packet->SetPayloadSize(bytes);
205   packet->SetMarker(packets_.empty());
206   return true;
207 }
208 
ToString()209 std::string RtpPacketizerVp8::ToString() {
210   return "RtpPacketizerVp8";
211 }
212 
GeneratePackets()213 int RtpPacketizerVp8::GeneratePackets() {
214   if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
215                              PayloadDescriptorExtraLength() + 1 +
216                              last_packet_reduction_len_) {
217     // The provided payload length is not long enough for the payload
218     // descriptor and one payload byte in the last packet.
219     // Return an error.
220     return -1;
221   }
222 
223   size_t per_packet_capacity =
224       max_payload_len_ -
225       (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
226 
227   GeneratePacketsSplitPayloadBalanced(payload_size_, per_packet_capacity);
228   return 0;
229 }
230 
GeneratePacketsSplitPayloadBalanced(size_t payload_len,size_t capacity)231 void RtpPacketizerVp8::GeneratePacketsSplitPayloadBalanced(size_t payload_len,
232                                                            size_t capacity) {
233   // Last packet of the last partition is smaller. Pretend that it's the same
234   // size, but we must write more payload to it.
235   size_t total_bytes = payload_len + last_packet_reduction_len_;
236   // Integer divisions with rounding up.
237   size_t num_packets_left = (total_bytes + capacity - 1) / capacity;
238   size_t bytes_per_packet = total_bytes / num_packets_left;
239   size_t num_larger_packets = total_bytes % num_packets_left;
240   size_t remaining_data = payload_len;
241   while (remaining_data > 0) {
242     // Last num_larger_packets are 1 byte wider than the rest. Increase
243     // per-packet payload size when needed.
244     if (num_packets_left == num_larger_packets)
245       ++bytes_per_packet;
246     size_t current_packet_bytes = bytes_per_packet;
247     if (current_packet_bytes > remaining_data) {
248       current_packet_bytes = remaining_data;
249     }
250     // This is not the last packet in the whole payload, but there's no data
251     // left for the last packet. Leave at least one byte for the last packet.
252     if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
253       --current_packet_bytes;
254     }
255     QueuePacket(payload_len - remaining_data,
256                 current_packet_bytes, remaining_data == payload_len);
257     remaining_data -= current_packet_bytes;
258     --num_packets_left;
259   }
260 }
261 
QueuePacket(size_t start_pos,size_t packet_size,bool first_packet)262 void RtpPacketizerVp8::QueuePacket(size_t start_pos,
263                                    size_t packet_size,
264                                    bool first_packet) {
265   // Write info to packet info struct and store in packet info queue.
266   InfoStruct packet_info;
267   packet_info.payload_start_pos = start_pos;
268   packet_info.size = packet_size;
269   packet_info.first_packet = first_packet;
270   packets_.push(packet_info);
271 }
272 
WriteHeaderAndPayload(const InfoStruct & packet_info,uint8_t * buffer,size_t buffer_length) const273 int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
274                                             uint8_t* buffer,
275                                             size_t buffer_length) const {
276   // Write the VP8 payload descriptor.
277   //       0
278   //       0 1 2 3 4 5 6 7 8
279   //      +-+-+-+-+-+-+-+-+-+
280   //      |X| |N|S| PART_ID |
281   //      +-+-+-+-+-+-+-+-+-+
282   // X:   |I|L|T|K|         | (mandatory if any of the below are used)
283   //      +-+-+-+-+-+-+-+-+-+
284   // I:   |PictureID (8/16b)| (optional)
285   //      +-+-+-+-+-+-+-+-+-+
286   // L:   |   TL0PIC_IDX    | (optional)
287   //      +-+-+-+-+-+-+-+-+-+
288   // T/K: |TID:Y|  KEYIDX   | (optional)
289   //      +-+-+-+-+-+-+-+-+-+
290 
291   RTC_DCHECK_GT(packet_info.size, 0);
292   buffer[0] = 0;
293   if (XFieldPresent())
294     buffer[0] |= kXBit;
295   if (hdr_info_.nonReference)
296     buffer[0] |= kNBit;
297   if (packet_info.first_packet)
298     buffer[0] |= kSBit;
299 
300   const int extension_length = WriteExtensionFields(buffer, buffer_length);
301   if (extension_length < 0)
302     return -1;
303 
304   memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
305          &payload_data_[packet_info.payload_start_pos],
306          packet_info.size);
307 
308   // Return total length of written data.
309   return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
310          extension_length;
311 }
312 
WriteExtensionFields(uint8_t * buffer,size_t buffer_length) const313 int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
314                                            size_t buffer_length) const {
315   size_t extension_length = 0;
316   if (XFieldPresent()) {
317     uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_;
318     *x_field = 0;
319     extension_length = 1;  // One octet for the X field.
320     if (PictureIdPresent()) {
321       if (WritePictureIDFields(
322               x_field, buffer, buffer_length, &extension_length) < 0) {
323         return -1;
324       }
325     }
326     if (TL0PicIdxFieldPresent()) {
327       if (WriteTl0PicIdxFields(
328               x_field, buffer, buffer_length, &extension_length) < 0) {
329         return -1;
330       }
331     }
332     if (TIDFieldPresent() || KeyIdxFieldPresent()) {
333       if (WriteTIDAndKeyIdxFields(
334               x_field, buffer, buffer_length, &extension_length) < 0) {
335         return -1;
336       }
337     }
338     RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength());
339   }
340   return static_cast<int>(extension_length);
341 }
342 
WritePictureIDFields(uint8_t * x_field,uint8_t * buffer,size_t buffer_length,size_t * extension_length) const343 int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
344                                            uint8_t* buffer,
345                                            size_t buffer_length,
346                                            size_t* extension_length) const {
347   *x_field |= kIBit;
348   RTC_DCHECK_GE(buffer_length,
349                 vp8_fixed_payload_descriptor_bytes_ + *extension_length);
350   const int pic_id_length = WritePictureID(
351       buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
352       buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length);
353   if (pic_id_length < 0)
354     return -1;
355   *extension_length += pic_id_length;
356   return 0;
357 }
358 
WritePictureID(uint8_t * buffer,size_t buffer_length) const359 int RtpPacketizerVp8::WritePictureID(uint8_t* buffer,
360                                      size_t buffer_length) const {
361   const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
362   size_t picture_id_len = PictureIdLength();
363   if (picture_id_len > buffer_length)
364     return -1;
365   if (picture_id_len == 2) {
366     buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
367     buffer[1] = pic_id & 0xFF;
368   } else if (picture_id_len == 1) {
369     buffer[0] = pic_id & 0x7F;
370   }
371   return static_cast<int>(picture_id_len);
372 }
373 
WriteTl0PicIdxFields(uint8_t * x_field,uint8_t * buffer,size_t buffer_length,size_t * extension_length) const374 int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
375                                            uint8_t* buffer,
376                                            size_t buffer_length,
377                                            size_t* extension_length) const {
378   if (buffer_length <
379       vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
380     return -1;
381   }
382   *x_field |= kLBit;
383   buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
384       hdr_info_.tl0PicIdx;
385   ++*extension_length;
386   return 0;
387 }
388 
WriteTIDAndKeyIdxFields(uint8_t * x_field,uint8_t * buffer,size_t buffer_length,size_t * extension_length) const389 int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
390                                               uint8_t* buffer,
391                                               size_t buffer_length,
392                                               size_t* extension_length) const {
393   if (buffer_length <
394       vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
395     return -1;
396   }
397   uint8_t* data_field =
398       &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length];
399   *data_field = 0;
400   if (TIDFieldPresent()) {
401     *x_field |= kTBit;
402     *data_field |= hdr_info_.temporalIdx << 6;
403     *data_field |= hdr_info_.layerSync ? kYBit : 0;
404   }
405   if (KeyIdxFieldPresent()) {
406     *x_field |= kKBit;
407     *data_field |= (hdr_info_.keyIdx & kKeyIdxField);
408   }
409   ++*extension_length;
410   return 0;
411 }
412 
PayloadDescriptorExtraLength() const413 size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
414   size_t length_bytes = PictureIdLength();
415   if (TL0PicIdxFieldPresent())
416     ++length_bytes;
417   if (TIDFieldPresent() || KeyIdxFieldPresent())
418     ++length_bytes;
419   if (length_bytes > 0)
420     ++length_bytes;  // Include the extension field.
421   return length_bytes;
422 }
423 
PictureIdLength() const424 size_t RtpPacketizerVp8::PictureIdLength() const {
425   if (hdr_info_.pictureId == kNoPictureId) {
426     return 0;
427   }
428   return 2;
429 }
430 
XFieldPresent() const431 bool RtpPacketizerVp8::XFieldPresent() const {
432   return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
433           KeyIdxFieldPresent());
434 }
435 
TIDFieldPresent() const436 bool RtpPacketizerVp8::TIDFieldPresent() const {
437   return (hdr_info_.temporalIdx != kNoTemporalIdx);
438 }
439 
KeyIdxFieldPresent() const440 bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
441   return (hdr_info_.keyIdx != kNoKeyIdx);
442 }
443 
TL0PicIdxFieldPresent() const444 bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
445   return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
446 }
447 
448 //
449 // VP8 format:
450 //
451 // Payload descriptor
452 //       0 1 2 3 4 5 6 7
453 //      +-+-+-+-+-+-+-+-+
454 //      |X|R|N|S|PartID | (REQUIRED)
455 //      +-+-+-+-+-+-+-+-+
456 // X:   |I|L|T|K|  RSV  | (OPTIONAL)
457 //      +-+-+-+-+-+-+-+-+
458 // I:   |   PictureID   | (OPTIONAL)
459 //      +-+-+-+-+-+-+-+-+
460 // L:   |   TL0PICIDX   | (OPTIONAL)
461 //      +-+-+-+-+-+-+-+-+
462 // T/K: |TID:Y| KEYIDX  | (OPTIONAL)
463 //      +-+-+-+-+-+-+-+-+
464 //
465 // Payload header (considered part of the actual payload, sent to decoder)
466 //       0 1 2 3 4 5 6 7
467 //      +-+-+-+-+-+-+-+-+
468 //      |Size0|H| VER |P|
469 //      +-+-+-+-+-+-+-+-+
470 //      |      ...      |
471 //      +               +
Parse(ParsedPayload * parsed_payload,const uint8_t * payload_data,size_t payload_data_length)472 bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload,
473                                const uint8_t* payload_data,
474                                size_t payload_data_length) {
475   RTC_DCHECK(parsed_payload);
476   if (payload_data_length == 0) {
477     RTC_LOG(LS_ERROR) << "Empty payload.";
478     return false;
479   }
480 
481   // Parse mandatory first byte of payload descriptor.
482   bool extension = (*payload_data & 0x80) ? true : false;               // X bit
483   bool beginning_of_partition = (*payload_data & 0x10) ? true : false;  // S bit
484   int partition_id = (*payload_data & 0x0F);  // PartID field
485 
486   parsed_payload->type.Video.width = 0;
487   parsed_payload->type.Video.height = 0;
488   parsed_payload->type.Video.is_first_packet_in_frame =
489       beginning_of_partition && (partition_id == 0);
490   parsed_payload->type.Video.simulcastIdx = 0;
491   parsed_payload->type.Video.codec = kRtpVideoVp8;
492   parsed_payload->type.Video.codecHeader.VP8.nonReference =
493       (*payload_data & 0x20) ? true : false;  // N bit
494   parsed_payload->type.Video.codecHeader.VP8.partitionId = partition_id;
495   parsed_payload->type.Video.codecHeader.VP8.beginningOfPartition =
496       beginning_of_partition;
497   parsed_payload->type.Video.codecHeader.VP8.pictureId = kNoPictureId;
498   parsed_payload->type.Video.codecHeader.VP8.tl0PicIdx = kNoTl0PicIdx;
499   parsed_payload->type.Video.codecHeader.VP8.temporalIdx = kNoTemporalIdx;
500   parsed_payload->type.Video.codecHeader.VP8.layerSync = false;
501   parsed_payload->type.Video.codecHeader.VP8.keyIdx = kNoKeyIdx;
502 
503   if (partition_id > 8) {
504     // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8.
505     return false;
506   }
507 
508   // Advance payload_data and decrease remaining payload size.
509   payload_data++;
510   if (payload_data_length <= 1) {
511     RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
512     return false;
513   }
514   payload_data_length--;
515 
516   if (extension) {
517     const int parsed_bytes =
518         ParseVP8Extension(&parsed_payload->type.Video.codecHeader.VP8,
519                           payload_data,
520                           payload_data_length);
521     if (parsed_bytes < 0)
522       return false;
523     payload_data += parsed_bytes;
524     payload_data_length -= parsed_bytes;
525     if (payload_data_length == 0) {
526       RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
527       return false;
528     }
529   }
530 
531   // Read P bit from payload header (only at beginning of first partition).
532   if (beginning_of_partition && partition_id == 0) {
533     parsed_payload->frame_type =
534         (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey;
535   } else {
536     parsed_payload->frame_type = kVideoFrameDelta;
537   }
538 
539   if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) !=
540       0) {
541     return false;
542   }
543 
544   parsed_payload->payload = payload_data;
545   parsed_payload->payload_length = payload_data_length;
546   return true;
547 }
548 }  // namespace webrtc
549