2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
13 #include <assert.h> // assert
14 #include <string.h> // memcpy
18 #include "webrtc/modules/rtp_rtcp/source/vp8_partition_aggregator.h"
19 #include "webrtc/system_wrappers/interface/logging.h"
23 int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
28 if (*data_length <= 0)
31 vp8->pictureId = (**data & 0x7F);
35 if (--(*data_length) <= 0)
37 // PictureId is 15 bits
38 vp8->pictureId = (vp8->pictureId << 8) + **data;
46 int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8,
51 if (*data_length <= 0)
54 vp8->tl0PicIdx = **data;
61 int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8,
68 if (*data_length <= 0)
72 vp8->temporalIdx = ((**data >> 6) & 0x03);
73 vp8->layerSync = (**data & 0x20) ? true : false; // Y bit
76 vp8->keyIdx = (**data & 0x1F);
84 int ParseVP8Extension(RTPVideoHeaderVP8* vp8,
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
97 // Advance data and decrease remaining payload size.
102 if (has_picture_id) {
103 if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) {
108 if (has_tl0_pic_idx) {
109 if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) {
114 if (has_tid || has_key_idx) {
115 if (ParseVP8TIDAndKeyIdx(
116 vp8, &data, &data_length, &parsed_bytes, has_tid, has_key_idx) !=
124 int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload,
127 assert(parsed_payload != NULL);
128 if (parsed_payload->frame_type != kVideoFrameKey) {
129 // Included in payload header for I-frames.
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.
137 parsed_payload->type.Video.width = ((data[7] << 8) + data[6]) & 0x3FFF;
138 parsed_payload->type.Video.height = ((data[9] << 8) + data[8]) & 0x3FFF;
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,
151 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
153 VP8PacketizerMode mode)
154 : payload_data_(NULL),
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]),
162 max_payload_len_(max_payload_len),
163 packets_calculated_(false) {
166 RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
168 : payload_data_(NULL),
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]),
177 max_payload_len_(max_payload_len),
178 packets_calculated_(false) {
181 RtpPacketizerVp8::~RtpPacketizerVp8() {
184 void RtpPacketizerVp8::SetPayloadData(
185 const uint8_t* payload_data,
187 const RTPFragmentationHeader* fragmentation) {
188 payload_data_ = payload_data;
189 payload_size_ = payload_size;
191 part_info_.CopyFrom(*fragmentation);
192 num_partitions_ = fragmentation->fragmentationVectorSize;
194 part_info_.VerifyAndAllocateFragmentationHeader(1);
195 part_info_.fragmentationLength[0] = payload_size;
196 part_info_.fragmentationOffset[0] = 0;
197 num_partitions_ = part_info_.fragmentationVectorSize;
201 bool RtpPacketizerVp8::NextPacket(uint8_t* buffer,
202 size_t* bytes_to_send,
204 if (!packets_calculated_) {
206 if (aggr_mode_ == kAggrPartitions && balance_) {
207 ret = GeneratePacketsBalancedAggregates();
209 ret = GeneratePackets();
215 if (packets_.empty()) {
218 InfoStruct packet_info = packets_.front();
221 int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
225 *bytes_to_send = bytes;
227 *last_packet = packets_.empty();
231 ProtectionType RtpPacketizerVp8::GetProtectionType() {
233 hdr_info_.temporalIdx == 0 || hdr_info_.temporalIdx == kNoTemporalIdx;
234 return protect ? kProtectedPacket : kUnprotectedPacket;
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;
250 std::string RtpPacketizerVp8::ToString() {
251 return "RtpPacketizerVp8";
254 int RtpPacketizerVp8::CalcNextSize(int max_payload_len,
256 bool split_payload) const {
257 if (max_payload_len == 0 || remaining_bytes == 0) {
260 if (!split_payload) {
261 return max_payload_len >= remaining_bytes ? remaining_bytes : 0;
265 // Balance payload sizes to produce (almost) equal size
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 +
273 return max_payload_len >= remaining_bytes ? remaining_bytes
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.
285 int total_bytes_processed = 0;
286 bool start_on_new_fragment = true;
287 bool beginning = true;
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 =
297 (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
298 int first_partition_in_packet = part_ix;
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;
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);
321 } else if (balance_ && remaining_in_partition > 0) {
325 if (remaining_in_partition == 0) {
326 ++part_ix; // Advance to next partition.
328 assert(packet_bytes > 0);
330 QueuePacket(total_bytes_processed,
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.
338 packets_calculated_ = true;
339 assert(total_bytes_processed == payload_size_);
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.
350 std::vector<int> partition_decision;
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);
357 int total_bytes_processed = 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
370 : remaining_partition;
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;
378 if (this_packet_bytes > max_size) {
379 max_size = this_packet_bytes;
382 assert(remaining_partition == 0);
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];
394 QueuePacket(total_bytes_processed,
396 first_partition_in_packet,
398 total_bytes_processed += this_packet_bytes;
401 packets_calculated_ = true;
405 void RtpPacketizerVp8::AggregateSmallPartitions(std::vector<int>* partition_vec,
408 assert(min_size && max_size);
411 assert(partition_vec);
412 partition_vec->assign(num_partitions_, -1);
414 vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength();
415 const uint32_t max_payload_len = max_payload_len_ - overhead;
416 int first_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] <
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);
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];
442 num_aggregate_packets += optimal_config.back() + 1;
443 first_in_set = last_in_set;
449 void RtpPacketizerVp8::QueuePacket(int start_pos,
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);
462 int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
464 int buffer_length) const {
465 // Write the VP8 payload descriptor.
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 // +-+-+-+-+-+-+-+-+-+
480 assert(packet_info.size > 0);
484 if (hdr_info_.nonReference)
486 if (packet_info.first_fragment)
488 buffer[0] |= (packet_info.first_partition_ix & kPartIdField);
490 const int extension_length = WriteExtensionFields(buffer, buffer_length);
492 memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
493 &payload_data_[packet_info.payload_start_pos],
496 // Return total length of written data.
497 return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
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_;
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) {
514 if (TL0PicIdxFieldPresent()) {
515 if (WriteTl0PicIdxFields(
516 x_field, buffer, buffer_length, &extension_length) < 0) {
520 if (TIDFieldPresent() || KeyIdxFieldPresent()) {
521 if (WriteTIDAndKeyIdxFields(
522 x_field, buffer, buffer_length, &extension_length) < 0) {
526 assert(extension_length == PayloadDescriptorExtraLength());
528 return extension_length;
531 int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
534 int* extension_length) const {
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)
541 *extension_length += pic_id_length;
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)
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;
556 return picture_id_len;
559 int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
562 int* extension_length) const {
564 vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
568 buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
574 int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
577 int* extension_length) const {
579 vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
582 uint8_t* data_field =
583 &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length];
585 if (TIDFieldPresent()) {
587 assert(hdr_info_.temporalIdx <= 3);
588 *data_field |= hdr_info_.temporalIdx << 6;
589 *data_field |= hdr_info_.layerSync ? kYBit : 0;
591 if (KeyIdxFieldPresent()) {
593 *data_field |= (hdr_info_.keyIdx & kKeyIdxField);
599 int RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
600 int length_bytes = PictureIdLength();
601 if (TL0PicIdxFieldPresent())
603 if (TIDFieldPresent() || KeyIdxFieldPresent())
605 if (length_bytes > 0)
606 ++length_bytes; // Include the extension field.
610 int RtpPacketizerVp8::PictureIdLength() const {
611 if (hdr_info_.pictureId == kNoPictureId) {
614 if (hdr_info_.pictureId <= 0x7F) {
620 bool RtpPacketizerVp8::XFieldPresent() const {
621 return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
622 KeyIdxFieldPresent());
625 bool RtpPacketizerVp8::TIDFieldPresent() const {
626 assert((hdr_info_.layerSync == false) ||
627 (hdr_info_.temporalIdx != kNoTemporalIdx));
628 return (hdr_info_.temporalIdx != kNoTemporalIdx);
631 bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
632 return (hdr_info_.keyIdx != kNoKeyIdx);
635 bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
636 return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
642 // Payload descriptor
645 // |X|R|N|S|PartID | (REQUIRED)
647 // X: |I|L|T|K| RSV | (OPTIONAL)
649 // I: | PictureID | (OPTIONAL)
651 // L: | TL0PICIDX | (OPTIONAL)
653 // T/K: |TID:Y| KEYIDX | (OPTIONAL)
656 // Payload header (considered part of the actual payload, sent to decoder)
663 bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload,
664 const uint8_t* payload_data,
665 size_t payload_data_length) {
666 assert(parsed_payload != NULL);
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
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;
689 if (partition_id > 8) {
690 // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8.
694 // Advance payload_data and decrease remaining payload size.
696 payload_data_length--;
699 const int parsed_bytes =
700 ParseVP8Extension(&parsed_payload->type.Video.codecHeader.VP8,
702 payload_data_length);
703 if (parsed_bytes < 0)
705 payload_data += parsed_bytes;
706 payload_data_length -= parsed_bytes;
709 if (payload_data_length <= 0) {
710 LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
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;
719 parsed_payload->frame_type = kVideoFrameDelta;
722 if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) !=
727 parsed_payload->payload = payload_data;
728 parsed_payload->payload_length = payload_data_length;
731 } // namespace webrtc