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