summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc')
-rw-r--r--third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc583
1 files changed, 583 insertions, 0 deletions
diff --git a/third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc b/third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc
new file mode 100644
index 0000000000..82defb8399
--- /dev/null
+++ b/third_party/libwebrtc/api/video/rtp_video_frame_assembler_unittests.cc
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2021 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 <vector>
+
+#include "api/array_view.h"
+#include "api/video/rtp_video_frame_assembler.h"
+#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "modules/rtp_rtcp/source/rtp_packetizer_av1_test_helper.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::Matches;
+using ::testing::SizeIs;
+using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
+using PayloadFormat = RtpVideoFrameAssembler::PayloadFormat;
+
+class PacketBuilder {
+ public:
+ explicit PacketBuilder(PayloadFormat format)
+ : format_(format), packet_to_send_(&extension_manager_) {}
+
+ PacketBuilder& WithSeqNum(uint16_t seq_num) {
+ seq_num_ = seq_num;
+ return *this;
+ }
+
+ PacketBuilder& WithPayload(rtc::ArrayView<const uint8_t> payload) {
+ payload_.assign(payload.begin(), payload.end());
+ return *this;
+ }
+
+ PacketBuilder& WithVideoHeader(const RTPVideoHeader& video_header) {
+ video_header_ = video_header;
+ return *this;
+ }
+
+ template <typename T, typename... Args>
+ PacketBuilder& WithExtension(int id, const Args&... args) {
+ extension_manager_.Register<T>(id);
+ packet_to_send_.IdentifyExtensions(extension_manager_);
+ packet_to_send_.SetExtension<T>(std::forward<const Args>(args)...);
+ return *this;
+ }
+
+ RtpPacketReceived Build() {
+ auto packetizer =
+ RtpPacketizer::Create(GetVideoCodecType(), payload_, {}, video_header_);
+ packetizer->NextPacket(&packet_to_send_);
+ packet_to_send_.SetSequenceNumber(seq_num_);
+
+ RtpPacketReceived received(&extension_manager_);
+ received.Parse(packet_to_send_.Buffer());
+ return received;
+ }
+
+ private:
+ absl::optional<VideoCodecType> GetVideoCodecType() {
+ switch (format_) {
+ case PayloadFormat::kRaw: {
+ return absl::nullopt;
+ }
+ case PayloadFormat::kH264: {
+ return kVideoCodecH264;
+ }
+ case PayloadFormat::kVp8: {
+ return kVideoCodecVP8;
+ }
+ case PayloadFormat::kVp9: {
+ return kVideoCodecVP9;
+ }
+ case PayloadFormat::kAv1: {
+ return kVideoCodecAV1;
+ }
+ case PayloadFormat::kGeneric: {
+ return kVideoCodecGeneric;
+ }
+ }
+ RTC_DCHECK_NOTREACHED();
+ return absl::nullopt;
+ }
+
+ const RtpVideoFrameAssembler::PayloadFormat format_;
+ uint16_t seq_num_ = 0;
+ std::vector<uint8_t> payload_;
+ RTPVideoHeader video_header_;
+ RtpPacketReceived::ExtensionManager extension_manager_;
+ RtpPacketToSend packet_to_send_;
+};
+
+RtpPacketReceived PaddingPacket(uint16_t seq_num) {
+ RtpPacketReceived padding_packet;
+ padding_packet.SetSequenceNumber(seq_num);
+ padding_packet.SetPadding(224);
+ return padding_packet;
+}
+
+void AppendFrames(RtpVideoFrameAssembler::FrameVector from,
+ RtpVideoFrameAssembler::FrameVector& to) {
+ to.insert(to.end(), std::make_move_iterator(from.begin()),
+ std::make_move_iterator(from.end()));
+}
+
+rtc::ArrayView<int64_t> References(const std::unique_ptr<EncodedFrame>& frame) {
+ return rtc::MakeArrayView(frame->references, frame->num_references);
+}
+
+rtc::ArrayView<uint8_t> Payload(const std::unique_ptr<EncodedFrame>& frame) {
+ return rtc::ArrayView<uint8_t>(*frame->GetEncodedData());
+}
+
+TEST(RtpVideoFrameAssembler, Vp8Packetization) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kVp8);
+
+ // When sending VP8 over RTP parts of the payload is actually inspected at the
+ // RTP level. It just so happen that the initial 'V' sets the keyframe bit
+ // (0x01) to the correct value.
+ uint8_t kKeyframePayload[] = "Vp8Keyframe";
+ ASSERT_EQ(kKeyframePayload[0] & 0x01, 0);
+
+ uint8_t kDeltaframePayload[] = "SomeFrame";
+ ASSERT_EQ(kDeltaframePayload[0] & 0x01, 1);
+
+ RtpVideoFrameAssembler::FrameVector frames;
+
+ RTPVideoHeader video_header;
+ auto& vp8_header =
+ video_header.video_type_header.emplace<RTPVideoHeaderVP8>();
+
+ vp8_header.pictureId = 10;
+ vp8_header.tl0PicIdx = 0;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kVp8)
+ .WithPayload(kKeyframePayload)
+ .WithVideoHeader(video_header)
+ .Build()),
+ frames);
+
+ vp8_header.pictureId = 11;
+ vp8_header.tl0PicIdx = 1;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kVp8)
+ .WithPayload(kDeltaframePayload)
+ .WithVideoHeader(video_header)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(10));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kKeyframePayload));
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(11));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(10));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kDeltaframePayload));
+}
+
+TEST(RtpVideoFrameAssembler, Vp9Packetization) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kVp9);
+ RtpVideoFrameAssembler::FrameVector frames;
+
+ uint8_t kPayload[] = "SomePayload";
+
+ RTPVideoHeader video_header;
+ auto& vp9_header =
+ video_header.video_type_header.emplace<RTPVideoHeaderVP9>();
+ vp9_header.InitRTPVideoHeaderVP9();
+
+ vp9_header.picture_id = 10;
+ vp9_header.tl0_pic_idx = 0;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kVp9)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .Build()),
+ frames);
+
+ vp9_header.picture_id = 11;
+ vp9_header.tl0_pic_idx = 1;
+ vp9_header.inter_pic_predicted = true;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kVp9)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(10));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(11));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(10));
+}
+
+TEST(RtpVideoFrameAssembler, Av1Packetization) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kAv1);
+ RtpVideoFrameAssembler::FrameVector frames;
+
+ auto kKeyframePayload =
+ BuildAv1Frame({Av1Obu(kAv1ObuTypeSequenceHeader).WithPayload({1, 2, 3}),
+ Av1Obu(kAv1ObuTypeFrame).WithPayload({4, 5, 6})});
+
+ auto kDeltaframePayload =
+ BuildAv1Frame({Av1Obu(kAv1ObuTypeFrame).WithPayload({7, 8, 9})});
+
+ RTPVideoHeader video_header;
+
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kAv1)
+ .WithPayload(kKeyframePayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(20)
+ .Build()),
+ frames);
+
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kAv1)
+ .WithPayload(kDeltaframePayload)
+ .WithSeqNum(21)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(20));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kKeyframePayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(21));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kDeltaframePayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(20));
+}
+
+TEST(RtpVideoFrameAssembler, RawPacketizationDependencyDescriptorExtension) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kRaw);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] = "SomePayload";
+
+ FrameDependencyStructure dependency_structure;
+ dependency_structure.num_decode_targets = 1;
+ dependency_structure.num_chains = 1;
+ dependency_structure.decode_target_protected_by_chain.push_back(0);
+ dependency_structure.templates.push_back(
+ FrameDependencyTemplate().S(0).T(0).Dtis("S").ChainDiffs({0}));
+ dependency_structure.templates.push_back(
+ FrameDependencyTemplate().S(0).T(0).Dtis("S").ChainDiffs({10}).FrameDiffs(
+ {10}));
+
+ DependencyDescriptor dependency_descriptor;
+
+ dependency_descriptor.frame_number = 10;
+ dependency_descriptor.frame_dependencies = dependency_structure.templates[0];
+ dependency_descriptor.attached_structure =
+ std::make_unique<FrameDependencyStructure>(dependency_structure);
+ AppendFrames(assembler.InsertPacket(
+ PacketBuilder(PayloadFormat::kRaw)
+ .WithPayload(kPayload)
+ .WithExtension<RtpDependencyDescriptorExtension>(
+ 1, dependency_structure, dependency_descriptor)
+ .Build()),
+ frames);
+
+ dependency_descriptor.frame_number = 20;
+ dependency_descriptor.frame_dependencies = dependency_structure.templates[1];
+ dependency_descriptor.attached_structure.reset();
+ AppendFrames(assembler.InsertPacket(
+ PacketBuilder(PayloadFormat::kRaw)
+ .WithPayload(kPayload)
+ .WithExtension<RtpDependencyDescriptorExtension>(
+ 1, dependency_structure, dependency_descriptor)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(10));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(20));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(10));
+}
+
+TEST(RtpVideoFrameAssembler, RawPacketizationGenericDescriptor00Extension) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kRaw);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] = "SomePayload";
+
+ RtpGenericFrameDescriptor generic;
+
+ generic.SetFirstPacketInSubFrame(true);
+ generic.SetLastPacketInSubFrame(true);
+ generic.SetFrameId(100);
+ AppendFrames(
+ assembler.InsertPacket(
+ PacketBuilder(PayloadFormat::kRaw)
+ .WithPayload(kPayload)
+ .WithExtension<RtpGenericFrameDescriptorExtension00>(1, generic)
+ .Build()),
+ frames);
+
+ generic.SetFrameId(102);
+ generic.AddFrameDependencyDiff(2);
+ AppendFrames(
+ assembler.InsertPacket(
+ PacketBuilder(PayloadFormat::kRaw)
+ .WithPayload(kPayload)
+ .WithExtension<RtpGenericFrameDescriptorExtension00>(1, generic)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(100));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(102));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(100));
+}
+
+TEST(RtpVideoFrameAssembler, RawPacketizationGenericPayloadDescriptor) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] = "SomePayload";
+
+ RTPVideoHeader video_header;
+
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(123)
+ .Build()),
+ frames);
+
+ video_header.frame_type = VideoFrameType::kVideoFrameDelta;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(124)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(123));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(124));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(123));
+}
+
+TEST(RtpVideoFrameAssembler, Padding) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] = "SomePayload";
+
+ RTPVideoHeader video_header;
+
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(123)
+ .Build()),
+ frames);
+
+ video_header.frame_type = VideoFrameType::kVideoFrameDelta;
+ AppendFrames(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(125)
+ .Build()),
+ frames);
+
+ ASSERT_THAT(frames, SizeIs(1));
+ auto first_frame = frames[0].ExtractFrame();
+ EXPECT_THAT(first_frame->Id(), Eq(123));
+ EXPECT_THAT(Payload(first_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(first_frame), IsEmpty());
+
+ AppendFrames(assembler.InsertPacket(PaddingPacket(/*seq_num=*/124)), frames);
+
+ ASSERT_THAT(frames, SizeIs(2));
+ auto second_frame = frames[1].ExtractFrame();
+ EXPECT_THAT(second_frame->Id(), Eq(125));
+ EXPECT_THAT(Payload(second_frame), ElementsAreArray(kPayload));
+ EXPECT_THAT(References(second_frame), UnorderedElementsAre(123));
+}
+
+TEST(RtpVideoFrameAssembler, ClearOldPackets) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+
+ // If we don't have a payload the packet will be counted as a padding packet.
+ uint8_t kPayload[] = "DontCare";
+
+ RTPVideoHeader video_header;
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(0)
+ .Build()),
+ SizeIs(1));
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(2000)
+ .Build()),
+ SizeIs(1));
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(0)
+ .Build()),
+ SizeIs(0));
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(1)
+ .Build()),
+ SizeIs(1));
+}
+
+TEST(RtpVideoFrameAssembler, ClearOldPacketsWithPadding) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+ uint8_t kPayload[] = "DontCare";
+
+ RTPVideoHeader video_header;
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(0)
+ .Build()),
+ SizeIs(1));
+
+ EXPECT_THAT(assembler.InsertPacket(PaddingPacket(/*seq_num=*/2000)),
+ SizeIs(0));
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(0)
+ .Build()),
+ SizeIs(0));
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(1)
+ .Build()),
+ SizeIs(1));
+}
+
+TEST(RtpVideoFrameAssembler, SeqNumStartAndSeqNumEndSet) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] =
+ "Some payload that will get split into two when packetized.";
+
+ RTPVideoHeader video_header;
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ RtpPacketizer::PayloadSizeLimits limits;
+ limits.max_payload_len = sizeof(kPayload) - 1;
+
+ auto packetizer =
+ RtpPacketizer::Create(kVideoCodecGeneric, kPayload, limits, video_header);
+ ASSERT_THAT(packetizer->NumPackets(), Eq(2U));
+
+ RtpPacketReceived::ExtensionManager extension_manager;
+ {
+ RtpPacketToSend send_packet(&extension_manager);
+ packetizer->NextPacket(&send_packet);
+ send_packet.SetSequenceNumber(123);
+ RtpPacketReceived received_packet(&extension_manager);
+ received_packet.Parse(send_packet.Buffer());
+ assembler.InsertPacket(received_packet);
+ }
+
+ {
+ RtpPacketToSend send_packet(&extension_manager);
+ packetizer->NextPacket(&send_packet);
+ send_packet.SetSequenceNumber(124);
+ RtpPacketReceived received_packet(&extension_manager);
+ received_packet.Parse(send_packet.Buffer());
+ AppendFrames(assembler.InsertPacket(received_packet), frames);
+ }
+
+ ASSERT_THAT(frames, SizeIs(1));
+ EXPECT_THAT(frames[0].RtpSeqNumStart(), Eq(123));
+ EXPECT_THAT(frames[0].RtpSeqNumEnd(), Eq(124));
+}
+
+TEST(RtpVideoFrameAssembler, SeqNumStartAndSeqNumEndSetWhenPaddingReceived) {
+ RtpVideoFrameAssembler assembler(RtpVideoFrameAssembler::kGeneric);
+ RtpVideoFrameAssembler::FrameVector frames;
+ uint8_t kPayload[] =
+ "Some payload that will get split into two when packetized.";
+
+ RTPVideoHeader video_header;
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+
+ EXPECT_THAT(assembler.InsertPacket(PacketBuilder(PayloadFormat::kGeneric)
+ .WithPayload(kPayload)
+ .WithVideoHeader(video_header)
+ .WithSeqNum(121)
+ .Build()),
+ SizeIs(1));
+
+ video_header.frame_type = VideoFrameType::kVideoFrameDelta;
+ RtpPacketReceived::ExtensionManager extension_manager;
+ RtpPacketizer::PayloadSizeLimits limits;
+ limits.max_payload_len = sizeof(kPayload) - 1;
+
+ auto packetizer =
+ RtpPacketizer::Create(kVideoCodecGeneric, kPayload, limits, video_header);
+ ASSERT_THAT(packetizer->NumPackets(), Eq(2U));
+
+ {
+ RtpPacketToSend send_packet(&extension_manager);
+ packetizer->NextPacket(&send_packet);
+ send_packet.SetSequenceNumber(123);
+ RtpPacketReceived received_packet(&extension_manager);
+ received_packet.Parse(send_packet.Buffer());
+ assembler.InsertPacket(received_packet);
+ }
+
+ {
+ RtpPacketToSend send_packet(&extension_manager);
+ packetizer->NextPacket(&send_packet);
+ send_packet.SetSequenceNumber(124);
+ RtpPacketReceived received_packet(&extension_manager);
+ received_packet.Parse(send_packet.Buffer());
+ assembler.InsertPacket(received_packet);
+ }
+
+ AppendFrames(assembler.InsertPacket(PaddingPacket(/*seq_num=*/122)), frames);
+
+ ASSERT_THAT(frames, SizeIs(1));
+ EXPECT_THAT(frames[0].RtpSeqNumStart(), Eq(123));
+ EXPECT_THAT(frames[0].RtpSeqNumEnd(), Eq(124));
+}
+
+} // namespace
+} // namespace webrtc