From 376e1147e6b7ff4842b2d8804de24a395fd96756 Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Tue, 4 Sep 2018 16:11:58 +0200 Subject: [PATCH] in RtpPacketizerVp8 factor out payload splitter function so that it can be shared between different packetizers and thus easier to extend Bug: webrtc:9680 Change-Id: Ie5e904ad27afb8dd2ed35ef9e009f7f408017b2f Reviewed-on: https://webrtc-review.googlesource.com/97661 Reviewed-by: Ilya Nikolaevskiy Commit-Queue: Danil Chapovalov Cr-Commit-Position: refs/heads/master@{#24555} --- modules/rtp_rtcp/BUILD.gn | 2 + modules/rtp_rtcp/source/rtp_format.cc | 42 +++ modules/rtp_rtcp/source/rtp_format.h | 5 + .../rtp_rtcp/source/rtp_format_unittest.cc | 168 +++++++++ modules/rtp_rtcp/source/rtp_format_vp8.cc | 333 +++++------------- modules/rtp_rtcp/source/rtp_format_vp8.h | 91 +---- 6 files changed, 323 insertions(+), 318 deletions(-) create mode 100644 modules/rtp_rtcp/source/rtp_format_unittest.cc diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index 49ccafea88..4f36a2ed85 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -225,6 +225,7 @@ rtc_static_library("rtp_rtcp") { "../../system_wrappers:metrics_api", "../audio_coding:audio_format_conversion", "../remote_bitrate_estimator", + "//third_party/abseil-cpp/absl/container:inlined_vector", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ] @@ -393,6 +394,7 @@ if (rtc_include_tests) { "source/rtcp_transceiver_unittest.cc", "source/rtp_fec_unittest.cc", "source/rtp_format_h264_unittest.cc", + "source/rtp_format_unittest.cc", "source/rtp_format_video_generic_unittest.cc", "source/rtp_format_vp8_test_helper.cc", "source/rtp_format_vp8_test_helper.h", diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc index 72beb171e5..bddec73687 100644 --- a/modules/rtp_rtcp/source/rtp_format.cc +++ b/modules/rtp_rtcp/source/rtp_format.cc @@ -17,6 +17,7 @@ #include "modules/rtp_rtcp/source/rtp_format_video_generic.h" #include "modules/rtp_rtcp/source/rtp_format_vp8.h" #include "modules/rtp_rtcp/source/rtp_format_vp9.h" +#include "rtc_base/checks.h" namespace webrtc { @@ -61,6 +62,47 @@ std::unique_ptr RtpPacketizer::Create( } } +std::vector RtpPacketizer::SplitAboutEqually( + size_t payload_len, + const PayloadSizeLimits& limits) { + RTC_CHECK_GT(limits.max_payload_len, limits.last_packet_reduction_len); + + // Last packet can be smaller. Pretend that it's the same size, but we must + // write more payload to it. + size_t total_bytes = payload_len + limits.last_packet_reduction_len; + // Integer divisions with rounding up. + size_t num_packets_left = + (total_bytes + limits.max_payload_len - 1) / limits.max_payload_len; + size_t bytes_per_packet = total_bytes / num_packets_left; + size_t num_larger_packets = total_bytes % num_packets_left; + size_t remaining_data = payload_len; + + std::vector result; + result.reserve(num_packets_left); + while (remaining_data > 0) { + // Last num_larger_packets are 1 byte wider than the rest. Increase + // per-packet payload size when needed. + if (num_packets_left == num_larger_packets) + ++bytes_per_packet; + size_t current_packet_bytes = bytes_per_packet; + if (current_packet_bytes > remaining_data) { + current_packet_bytes = remaining_data; + } + // This is not the last packet in the whole payload, but there's no data + // left for the last packet. Leave at least one byte for the last packet. + if (num_packets_left == 2 && current_packet_bytes == remaining_data) { + --current_packet_bytes; + } + + result.push_back(current_packet_bytes); + + remaining_data -= current_packet_bytes; + --num_packets_left; + } + + return result; +} + RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) { switch (type) { case kVideoCodecH264: diff --git a/modules/rtp_rtcp/source/rtp_format.h b/modules/rtp_rtcp/source/rtp_format.h index 007ddbc2a2..f945d24b0a 100644 --- a/modules/rtp_rtcp/source/rtp_format.h +++ b/modules/rtp_rtcp/source/rtp_format.h @@ -13,6 +13,7 @@ #include #include +#include #include "api/array_view.h" #include "common_types.h" // NOLINT(build/include) @@ -47,6 +48,10 @@ class RtpPacketizer { // Write payload and set marker bit of the |packet|. // Returns true on success, false otherwise. virtual bool NextPacket(RtpPacketToSend* packet) = 0; + + // Split payload_len into sum of integers with respect to |limits|. + static std::vector SplitAboutEqually(size_t payload_len, + const PayloadSizeLimits& limits); }; // TODO(sprang): Update the depacketizer to return a std::unqie_ptr with a copy diff --git a/modules/rtp_rtcp/source/rtp_format_unittest.cc b/modules/rtp_rtcp/source/rtp_format_unittest.cc new file mode 100644 index 0000000000..6b834325c8 --- /dev/null +++ b/modules/rtp_rtcp/source/rtp_format_unittest.cc @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/rtp_format.h" + +#include +#include + +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAre; +using ::testing::Le; +using ::testing::Each; +using ::testing::IsEmpty; +using ::testing::Not; +using ::testing::SizeIs; + +// Calculate difference between largest and smallest packets respecting sizes +// adjustement provided by limits, +// i.e. last packet expected to be smaller than 'average' by reduction_len. +int EffectivePacketsSizeDifference( + std::vector sizes, + const RtpPacketizer::PayloadSizeLimits& limits) { + // Account for larger last packet header. + sizes.back() += limits.last_packet_reduction_len; + + auto minmax = std::minmax_element(sizes.begin(), sizes.end()); + // MAX-MIN + return *minmax.second - *minmax.first; +} + +size_t Sum(const std::vector& sizes) { + return std::accumulate(sizes.begin(), sizes.end(), 0); +} + +TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualSumToPayloadLen) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 5; + limits.last_packet_reduction_len = 2; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(13, limits); + + EXPECT_THAT(Sum(payload_sizes), 13); +} + +TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualRespectsMaxPayloadSize) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 5; + limits.last_packet_reduction_len = 2; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(13, limits); + + EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len))); +} + +TEST(RtpPacketizerSplitAboutEqually, + AllPacketsAreEqualRespectsLastPacketReductionLength) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 5; + limits.last_packet_reduction_len = 2; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(13, limits); + + ASSERT_THAT(payload_sizes, Not(IsEmpty())); + EXPECT_LE(payload_sizes.back() + limits.last_packet_reduction_len, + limits.max_payload_len); +} + +TEST(RtpPacketizerSplitAboutEqually, AllPacketsAreEqualInSize) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 5; + limits.last_packet_reduction_len = 2; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(13, limits); + + EXPECT_EQ(EffectivePacketsSizeDifference(payload_sizes, limits), 0); +} + +TEST(RtpPacketizerSplitAboutEqually, + AllPacketsAreEqualGeneratesMinimumNumberOfPackets) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 5; + limits.last_packet_reduction_len = 2; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(13, limits); + // Computed by hand. 3 packets would have exactly capacity 3*5-2=13 + // (max length - for each packet minus last packet reduction). + EXPECT_THAT(payload_sizes, SizeIs(3)); +} + +TEST(RtpPacketizerSplitAboutEqually, SomePacketsAreSmallerSumToPayloadLen) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 7; + limits.last_packet_reduction_len = 5; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(28, limits); + + EXPECT_THAT(Sum(payload_sizes), 28); +} + +TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerRespectsMaxPayloadSize) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 7; + limits.last_packet_reduction_len = 5; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(28, limits); + + EXPECT_THAT(payload_sizes, Each(Le(limits.max_payload_len))); +} + +TEST(RtpPacketizerVideoGeneric, + SomePacketsAreSmallerRespectsLastPacketReductionLength) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 7; + limits.last_packet_reduction_len = 5; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(28, limits); + + EXPECT_LE(payload_sizes.back(), + limits.max_payload_len - limits.last_packet_reduction_len); +} + +TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmallerPacketsAlmostEqualInSize) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 7; + limits.last_packet_reduction_len = 5; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(28, limits); + + EXPECT_LE(EffectivePacketsSizeDifference(payload_sizes, limits), 1); +} + +TEST(RtpPacketizerVideoGeneric, + SomePacketsAreSmallerGeneratesMinimumNumberOfPackets) { + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 7; + limits.last_packet_reduction_len = 5; + + std::vector payload_sizes = + RtpPacketizer::SplitAboutEqually(24, limits); + // Computed by hand. 4 packets would have capacity 4*7-5=23 (max length - + // for each packet minus last packet reduction). + // 5 packets is enough for kPayloadSize. + EXPECT_THAT(payload_sizes, SizeIs(5)); +} + +} // namespace +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.cc b/modules/rtp_rtcp/source/rtp_format_vp8.cc index 4a511fcaf2..b219dace94 100644 --- a/modules/rtp_rtcp/source/rtp_format_vp8.cc +++ b/modules/rtp_rtcp/source/rtp_format_vp8.cc @@ -23,8 +23,15 @@ namespace webrtc { namespace { -// Length of VP8 payload descriptors' fixed part. -constexpr int kVp8FixedPayloadDescriptorSize = 1; +constexpr int kXBit = 0x80; +constexpr int kNBit = 0x20; +constexpr int kSBit = 0x10; +constexpr int kKeyIdxField = 0x1F; +constexpr int kIBit = 0x80; +constexpr int kLBit = 0x40; +constexpr int kTBit = 0x20; +constexpr int kKBit = 0x10; +constexpr int kYBit = 0x20; int ParseVP8PictureID(RTPVideoHeaderVP8* vp8, const uint8_t** data, @@ -165,259 +172,113 @@ bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) { RtpPacketizerVp8::RtpPacketizerVp8(rtc::ArrayView payload, PayloadSizeLimits limits, const RTPVideoHeaderVP8& hdr_info) - : payload_data_(payload.data()), hdr_info_(hdr_info), limits_(limits) { - RTC_DCHECK(ValidateHeader(hdr_info)); - GeneratePackets(payload.size()); + : hdr_(BuildHeader(hdr_info)), remaining_payload_(payload) { + if (limits.max_payload_len - limits.last_packet_reduction_len < + hdr_.size() + 1) { + // The provided payload length is not long enough for the payload + // descriptor and one payload byte in the last packet. + current_packet_ = payload_sizes_.begin(); + return; + } + limits.max_payload_len -= hdr_.size(); + payload_sizes_ = SplitAboutEqually(payload.size(), limits); + current_packet_ = payload_sizes_.begin(); } RtpPacketizerVp8::~RtpPacketizerVp8() = default; size_t RtpPacketizerVp8::NumPackets() const { - return packets_.size(); + return payload_sizes_.end() - current_packet_; } bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) { RTC_DCHECK(packet); - if (packets_.empty()) { + if (current_packet_ == payload_sizes_.end()) { return false; } - InfoStruct packet_info = packets_.front(); - packets_.pop(); - size_t packet_payload_len = - packets_.empty() - ? limits_.max_payload_len - limits_.last_packet_reduction_len - : limits_.max_payload_len; - uint8_t* buffer = packet->AllocatePayload(packet_payload_len); - int bytes = WriteHeaderAndPayload(packet_info, buffer, packet_payload_len); - if (bytes < 0) { - return false; - } - packet->SetPayloadSize(bytes); - packet->SetMarker(packets_.empty()); + size_t packet_payload_len = *current_packet_; + ++current_packet_; + + uint8_t* buffer = packet->AllocatePayload(hdr_.size() + packet_payload_len); + RTC_CHECK(buffer); + + memcpy(buffer, hdr_.data(), hdr_.size()); + memcpy(buffer + hdr_.size(), remaining_payload_.data(), packet_payload_len); + + remaining_payload_ = remaining_payload_.subview(packet_payload_len); + hdr_[0] &= (~kSBit); // Clear 'Start of partition' bit. + packet->SetMarker(current_packet_ == payload_sizes_.end()); return true; } -void RtpPacketizerVp8::GeneratePackets(size_t payload_len) { - if (limits_.max_payload_len - limits_.last_packet_reduction_len < - kVp8FixedPayloadDescriptorSize + PayloadDescriptorExtraLength() + 1) { - // The provided payload length is not long enough for the payload - // descriptor and one payload byte in the last packet. - return; +// Write the VP8 payload descriptor. +// 0 +// 0 1 2 3 4 5 6 7 8 +// +-+-+-+-+-+-+-+-+-+ +// |X| |N|S| PART_ID | +// +-+-+-+-+-+-+-+-+-+ +// X: |I|L|T|K| | (mandatory if any of the below are used) +// +-+-+-+-+-+-+-+-+-+ +// I: |PictureID (16b)| (optional) +// +-+-+-+-+-+-+-+-+-+ +// L: | TL0PIC_IDX | (optional) +// +-+-+-+-+-+-+-+-+-+ +// T/K: |TID:Y| KEYIDX | (optional) +// +-+-+-+-+-+-+-+-+-+ +RtpPacketizerVp8::RawHeader RtpPacketizerVp8::BuildHeader( + const RTPVideoHeaderVP8& header) { + RTC_DCHECK(ValidateHeader(header)); + + RawHeader result; + bool tid_present = header.temporalIdx != kNoTemporalIdx; + bool keyid_present = header.keyIdx != kNoKeyIdx; + bool tl0_pid_present = header.tl0PicIdx != kNoTl0PicIdx; + bool pid_present = header.pictureId != kNoPictureId; + uint8_t x_field = 0; + if (pid_present) + x_field |= kIBit; + if (tl0_pid_present) + x_field |= kLBit; + if (tid_present) + x_field |= kTBit; + if (keyid_present) + x_field |= kKBit; + + uint8_t flags = 0; + if (x_field != 0) + flags |= kXBit; + if (header.nonReference) + flags |= kNBit; + // Create header as first packet in the frame. NextPacket() will clear it + // after first use. + flags |= kSBit; + result.push_back(flags); + if (x_field == 0) { + return result; } - - size_t capacity = limits_.max_payload_len - (kVp8FixedPayloadDescriptorSize + - PayloadDescriptorExtraLength()); - - // Last packet of the last partition is smaller. Pretend that it's the same - // size, but we must write more payload to it. - size_t total_bytes = payload_len + limits_.last_packet_reduction_len; - // Integer divisions with rounding up. - size_t num_packets_left = (total_bytes + capacity - 1) / capacity; - size_t bytes_per_packet = total_bytes / num_packets_left; - size_t num_larger_packets = total_bytes % num_packets_left; - size_t remaining_data = payload_len; - while (remaining_data > 0) { - // Last num_larger_packets are 1 byte wider than the rest. Increase - // per-packet payload size when needed. - if (num_packets_left == num_larger_packets) - ++bytes_per_packet; - size_t current_packet_bytes = bytes_per_packet; - if (current_packet_bytes > remaining_data) { - current_packet_bytes = remaining_data; + result.push_back(x_field); + if (pid_present) { + const uint16_t pic_id = static_cast(header.pictureId); + result.push_back(0x80 | ((pic_id >> 8) & 0x7F)); + result.push_back(pic_id & 0xFF); + } + if (tl0_pid_present) { + result.push_back(header.tl0PicIdx); + } + if (tid_present || keyid_present) { + uint8_t data_field = 0; + if (tid_present) { + data_field |= header.temporalIdx << 6; + if (header.layerSync) + data_field |= kYBit; } - // This is not the last packet in the whole payload, but there's no data - // left for the last packet. Leave at least one byte for the last packet. - if (num_packets_left == 2 && current_packet_bytes == remaining_data) { - --current_packet_bytes; + if (keyid_present) { + data_field |= (header.keyIdx & kKeyIdxField); } - QueuePacket(payload_len - remaining_data, current_packet_bytes, - /*first_packet=*/remaining_data == payload_len); - remaining_data -= current_packet_bytes; - --num_packets_left; + result.push_back(data_field); } -} - -void RtpPacketizerVp8::QueuePacket(size_t start_pos, - size_t packet_size, - bool first_packet) { - // Write info to packet info struct and store in packet info queue. - InfoStruct packet_info; - packet_info.payload_start_pos = start_pos; - packet_info.size = packet_size; - packet_info.first_packet = first_packet; - packets_.push(packet_info); -} - -int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info, - uint8_t* buffer, - size_t buffer_length) const { - // Write the VP8 payload descriptor. - // 0 - // 0 1 2 3 4 5 6 7 8 - // +-+-+-+-+-+-+-+-+-+ - // |X| |N|S| PART_ID | - // +-+-+-+-+-+-+-+-+-+ - // X: |I|L|T|K| | (mandatory if any of the below are used) - // +-+-+-+-+-+-+-+-+-+ - // I: |PictureID (8/16b)| (optional) - // +-+-+-+-+-+-+-+-+-+ - // L: | TL0PIC_IDX | (optional) - // +-+-+-+-+-+-+-+-+-+ - // T/K: |TID:Y| KEYIDX | (optional) - // +-+-+-+-+-+-+-+-+-+ - - RTC_DCHECK_GT(packet_info.size, 0); - buffer[0] = 0; - if (XFieldPresent()) - buffer[0] |= kXBit; - if (hdr_info_.nonReference) - buffer[0] |= kNBit; - if (packet_info.first_packet) - buffer[0] |= kSBit; - - const int extension_length = WriteExtensionFields(buffer, buffer_length); - if (extension_length < 0) - return -1; - - memcpy(&buffer[kVp8FixedPayloadDescriptorSize + extension_length], - &payload_data_[packet_info.payload_start_pos], packet_info.size); - - // Return total length of written data. - return packet_info.size + kVp8FixedPayloadDescriptorSize + extension_length; -} - -int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer, - size_t buffer_length) const { - size_t extension_length = 0; - if (XFieldPresent()) { - uint8_t* x_field = buffer + kVp8FixedPayloadDescriptorSize; - *x_field = 0; - extension_length = 1; // One octet for the X field. - if (PictureIdPresent()) { - if (WritePictureIDFields(x_field, buffer, buffer_length, - &extension_length) < 0) { - return -1; - } - } - if (TL0PicIdxFieldPresent()) { - if (WriteTl0PicIdxFields(x_field, buffer, buffer_length, - &extension_length) < 0) { - return -1; - } - } - if (TIDFieldPresent() || KeyIdxFieldPresent()) { - if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length, - &extension_length) < 0) { - return -1; - } - } - RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength()); - } - return static_cast(extension_length); -} - -int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const { - *x_field |= kIBit; - RTC_DCHECK_GE(buffer_length, - kVp8FixedPayloadDescriptorSize + *extension_length); - const int pic_id_length = WritePictureID( - buffer + kVp8FixedPayloadDescriptorSize + *extension_length, - buffer_length - kVp8FixedPayloadDescriptorSize - *extension_length); - if (pic_id_length < 0) - return -1; - *extension_length += pic_id_length; - return 0; -} - -int RtpPacketizerVp8::WritePictureID(uint8_t* buffer, - size_t buffer_length) const { - const uint16_t pic_id = static_cast(hdr_info_.pictureId); - size_t picture_id_len = PictureIdLength(); - if (picture_id_len > buffer_length) - return -1; - if (picture_id_len == 2) { - buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F); - buffer[1] = pic_id & 0xFF; - } else if (picture_id_len == 1) { - buffer[0] = pic_id & 0x7F; - } - return static_cast(picture_id_len); -} - -int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const { - if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) { - return -1; - } - *x_field |= kLBit; - buffer[kVp8FixedPayloadDescriptorSize + *extension_length] = - hdr_info_.tl0PicIdx; - ++*extension_length; - return 0; -} - -int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const { - if (buffer_length < kVp8FixedPayloadDescriptorSize + *extension_length + 1) { - return -1; - } - uint8_t* data_field = - &buffer[kVp8FixedPayloadDescriptorSize + *extension_length]; - *data_field = 0; - if (TIDFieldPresent()) { - *x_field |= kTBit; - *data_field |= hdr_info_.temporalIdx << 6; - *data_field |= hdr_info_.layerSync ? kYBit : 0; - } - if (KeyIdxFieldPresent()) { - *x_field |= kKBit; - *data_field |= (hdr_info_.keyIdx & kKeyIdxField); - } - ++*extension_length; - return 0; -} - -size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const { - size_t length_bytes = PictureIdLength(); - if (TL0PicIdxFieldPresent()) - ++length_bytes; - if (TIDFieldPresent() || KeyIdxFieldPresent()) - ++length_bytes; - if (length_bytes > 0) - ++length_bytes; // Include the extension field. - return length_bytes; -} - -size_t RtpPacketizerVp8::PictureIdLength() const { - if (hdr_info_.pictureId == kNoPictureId) { - return 0; - } - return 2; -} - -bool RtpPacketizerVp8::XFieldPresent() const { - return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() || - KeyIdxFieldPresent()); -} - -bool RtpPacketizerVp8::TIDFieldPresent() const { - return (hdr_info_.temporalIdx != kNoTemporalIdx); -} - -bool RtpPacketizerVp8::KeyIdxFieldPresent() const { - return (hdr_info_.keyIdx != kNoKeyIdx); -} - -bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const { - return (hdr_info_.tl0PicIdx != kNoTl0PicIdx); + return result; } // diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.h b/modules/rtp_rtcp/source/rtp_format_vp8.h index dd667626d1..2fdd6c5137 100644 --- a/modules/rtp_rtcp/source/rtp_format_vp8.h +++ b/modules/rtp_rtcp/source/rtp_format_vp8.h @@ -25,10 +25,11 @@ #ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ #define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_ -#include #include #include +#include "absl/container/inlined_vector.h" +#include "api/array_view.h" #include "modules/include/module_common_types.h" #include "modules/rtp_rtcp/source/rtp_format.h" #include "rtc_base/constructormagic.h" @@ -54,88 +55,14 @@ class RtpPacketizerVp8 : public RtpPacketizer { bool NextPacket(RtpPacketToSend* packet) override; private: - typedef struct { - size_t payload_start_pos; - size_t size; - bool first_packet; - } InfoStruct; - typedef std::queue InfoQueue; + // VP8 header can use up to 6 bytes. + using RawHeader = absl::InlinedVector; + static RawHeader BuildHeader(const RTPVideoHeaderVP8& header); - static const int kXBit = 0x80; - static const int kNBit = 0x20; - static const int kSBit = 0x10; - static const int kPartIdField = 0x0F; - static const int kKeyIdxField = 0x1F; - static const int kIBit = 0x80; - static const int kLBit = 0x40; - static const int kTBit = 0x20; - static const int kKBit = 0x10; - static const int kYBit = 0x20; - - // Calculate all packet sizes and load to packet info queue. - void GeneratePackets(size_t payload_len); - - // Insert packet into packet queue. - void QueuePacket(size_t start_pos, size_t packet_size, bool first_packet); - - // Write the payload header and copy the payload to the buffer. - // The info in packet_info determines which part of the payload is written - // and what to write in the header fields. - int WriteHeaderAndPayload(const InfoStruct& packet_info, - uint8_t* buffer, - size_t buffer_length) const; - - // Write the X field and the appropriate extension fields to buffer. - // The function returns the extension length (including X field), or -1 - // on error. - int WriteExtensionFields(uint8_t* buffer, size_t buffer_length) const; - - // Set the I bit in the x_field, and write PictureID to the appropriate - // position in buffer. The function returns 0 on success, -1 otherwise. - int WritePictureIDFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const; - - // Set the L bit in the x_field, and write Tl0PicIdx to the appropriate - // position in buffer. The function returns 0 on success, -1 otherwise. - int WriteTl0PicIdxFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const; - - // Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the - // appropriate position in buffer. The function returns 0 on success, - // -1 otherwise. - int WriteTIDAndKeyIdxFields(uint8_t* x_field, - uint8_t* buffer, - size_t buffer_length, - size_t* extension_length) const; - - // Write the PictureID from codec_specific_info_ to buffer. One or two - // bytes are written, depending on magnitude of PictureID. The function - // returns the number of bytes written. - int WritePictureID(uint8_t* buffer, size_t buffer_length) const; - - // Calculate and return length (octets) of the variable header fields in - // the next header (i.e., header length in addition to vp8_header_bytes_). - size_t PayloadDescriptorExtraLength() const; - - // Calculate and return length (octets) of PictureID field in the next - // header. Can be 0, 1, or 2. - size_t PictureIdLength() const; - - // Check whether each of the optional fields will be included in the header. - bool XFieldPresent() const; - bool TIDFieldPresent() const; - bool KeyIdxFieldPresent() const; - bool TL0PicIdxFieldPresent() const; - bool PictureIdPresent() const { return (PictureIdLength() > 0); } - - const uint8_t* payload_data_; - const RTPVideoHeaderVP8 hdr_info_; - const PayloadSizeLimits limits_; - InfoQueue packets_; + RawHeader hdr_; + rtc::ArrayView remaining_payload_; + std::vector payload_sizes_; + std::vector::const_iterator current_packet_; RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8); };