Move RtpSenderVideo tests to separate file.

Also refactor most of the RtpSender tests to not use the frame-level
method RTPSender::SendOutgoingData.

Bug: webrtc:7135
Change-Id: I9b0af6aa45e9b908d8197e48b143fede7e2804c7
Reviewed-on: https://webrtc-review.googlesource.com/c/121461
Commit-Queue: Niels Moller <nisse@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26577}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index cda54dd..6f641eb 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -413,6 +413,7 @@
       "source/rtp_rtcp_impl_unittest.cc",
       "source/rtp_sender_audio_unittest.cc",
       "source/rtp_sender_unittest.cc",
+      "source/rtp_sender_video_unittest.cc",
       "source/rtp_utility_unittest.cc",
       "source/time_util_unittest.cc",
       "source/ulpfec_generator_unittest.cc",
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 0529d89..b13875a 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -55,11 +55,9 @@
 const uint32_t kTimestamp = 10;
 const uint16_t kSeqNum = 33;
 const uint32_t kSsrc = 725242;
-const int kMaxPacketLength = 1500;
 const uint16_t kTransportSequenceNumber = 0xaabbu;
 const uint64_t kStartTime = 123456789;
 const size_t kMaxPaddingSize = 224u;
-const size_t kGenericHeaderLength = 1;
 const uint8_t kPayloadData[] = {47, 11, 32, 93, 89};
 const int64_t kDefaultExpectedRetransmissionTimeMs = 125;
 const char kNoRid[] = "";
@@ -232,19 +230,9 @@
                                            RtpPacketSender::kNormalPriority));
   }
 
-  void SendGenericPayload() {
-    const uint32_t kTimestamp = 1234;
-    const uint8_t kPayloadType = 127;
+  void SendGenericPacket() {
     const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
-    const char payload_name[] = "GENERIC";
-    EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
-                                              0, 1500));
-
-    RTPVideoHeader video_header;
-    EXPECT_TRUE(rtp_sender_->SendOutgoingData(
-        kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
-        sizeof(kPayloadData), nullptr, &video_header, nullptr,
-        kDefaultExpectedRetransmissionTimeMs));
+    SendPacket(kCaptureTimeMs, sizeof(kPayloadData));
   }
 };
 
@@ -255,35 +243,6 @@
   void SetUp() override { SetUpRtpSender(false, false); }
 };
 
-class TestRtpSenderVideo : public RTPSenderVideo {
- public:
-  TestRtpSenderVideo(Clock* clock,
-                     RTPSender* rtp_sender,
-                     FlexfecSender* flexfec_sender)
-      : RTPSenderVideo(clock, rtp_sender, flexfec_sender, nullptr, false) {}
-  ~TestRtpSenderVideo() override {}
-
-  StorageType GetStorageType(const RTPVideoHeader& header,
-                             int32_t retransmission_settings,
-                             int64_t expected_retransmission_time_ms) {
-    return RTPSenderVideo::GetStorageType(GetTemporalId(header),
-                                          retransmission_settings,
-                                          expected_retransmission_time_ms);
-  }
-};
-
-class RtpSenderVideoTest : public RtpSenderTest {
- protected:
-  void SetUp() override {
-    // TODO(pbos): Set up to use pacer.
-    SetUpRtpSender(false, false);
-    rtp_sender_video_.reset(
-        new TestRtpSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr));
-    rtp_sender_video_->RegisterPayloadType(kPayload, "generic");
-  }
-  std::unique_ptr<TestRtpSenderVideo> rtp_sender_video_;
-};
-
 TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) {
   // Configure rtp_sender with csrc.
   std::vector<uint32_t> csrcs;
@@ -423,9 +382,8 @@
       .WillOnce(testing::Return(kTransportSequenceNumber));
 
   const size_t expected_bytes =
-      GetParam() ? sizeof(kPayloadData) + kGenericHeaderLength +
-                       kRtpOverheadBytesPerPacket
-                 : sizeof(kPayloadData) + kGenericHeaderLength;
+      GetParam() ? sizeof(kPayloadData) + kRtpOverheadBytesPerPacket
+                 : sizeof(kPayloadData);
 
   EXPECT_CALL(feedback_observer_,
               AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
@@ -434,7 +392,7 @@
   EXPECT_CALL(mock_overhead_observer,
               OnOverheadChanged(kRtpOverheadBytesPerPacket))
       .Times(1);
-  SendGenericPayload();
+  SendGenericPacket();
 }
 
 TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
@@ -459,7 +417,7 @@
                         PacedPacketInfo()))
       .Times(1);
 
-  SendGenericPayload();
+  SendGenericPacket();
 
   const auto& packet = transport_.last_sent_packet();
   uint16_t transport_seq_no;
@@ -477,7 +435,7 @@
       nullptr, false, false));
   rtp_sender_->SetSSRC(kSsrc);
 
-  SendGenericPayload();
+  SendGenericPacket();
 
   EXPECT_FALSE(transport_.last_options_.is_retransmit);
 }
@@ -490,7 +448,7 @@
   EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
       .WillOnce(testing::Return(kTransportSequenceNumber));
   EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1);
-  SendGenericPayload();
+  SendGenericPacket();
   EXPECT_TRUE(transport_.last_options_.included_in_feedback);
 }
 
@@ -503,7 +461,7 @@
   EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
       .WillOnce(testing::Return(kTransportSequenceNumber));
   EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1);
-  SendGenericPayload();
+  SendGenericPacket();
   EXPECT_TRUE(transport_.last_options_.included_in_allocation);
 }
 
@@ -511,14 +469,14 @@
        SetsIncludedInAllocationWhenForcedAsPartOfAllocation) {
   SetUpRtpSender(false, false);
   rtp_sender_->SetAsPartOfAllocation(true);
-  SendGenericPayload();
+  SendGenericPacket();
   EXPECT_FALSE(transport_.last_options_.included_in_feedback);
   EXPECT_TRUE(transport_.last_options_.included_in_allocation);
 }
 
 TEST_P(RtpSenderTestWithoutPacer, DoesnSetIncludedInAllocationByDefault) {
   SetUpRtpSender(false, false);
-  SendGenericPayload();
+  SendGenericPacket();
   EXPECT_FALSE(transport_.last_options_.included_in_feedback);
   EXPECT_FALSE(transport_.last_options_.included_in_allocation);
 }
@@ -598,7 +556,7 @@
               OnSendPacket(kTransportSequenceNumber, _, _))
       .Times(1);
 
-  SendGenericPayload();
+  SendGenericPacket();
 }
 
 TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
@@ -625,7 +583,7 @@
                         PacedPacketInfo()))
       .Times(1);
 
-  SendGenericPayload();
+  SendGenericPacket();
   rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
                                 fake_clock_.TimeInMilliseconds(), false,
                                 PacedPacketInfo());
@@ -957,7 +915,7 @@
   EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
       .Times(1);
 
-  SendGenericPayload();  // Packet passed to pacer.
+  SendGenericPacket();  // Packet passed to pacer.
   const bool kIsRetransmit = false;
   rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
                                 fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -977,7 +935,7 @@
   EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
       .Times(1);
 
-  SendGenericPayload();  // Packet passed to pacer.
+  SendGenericPacket();  // Packet passed to pacer.
   const bool kIsRetransmit = true;
   rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
                                 fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -1004,7 +962,7 @@
   EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
       .Times(1);
 
-  SendGenericPayload();  // Packet passed to pacer.
+  SendGenericPacket();  // Packet passed to pacer.
   const bool kIsRetransmit = false;
   rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
                                 fake_clock_.TimeInMilliseconds(), kIsRetransmit,
@@ -1125,6 +1083,7 @@
 }
 
 TEST_P(RtpSenderTest, SendFlexfecPackets) {
+  constexpr uint32_t kTimestamp = 1234;
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
@@ -1145,12 +1104,16 @@
   rtp_sender_->SetSequenceNumber(kSeqNum);
   rtp_sender_->SetStorePacketsStatus(true, 10);
 
+  RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+                                  &flexfec_sender, nullptr, false);
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
   params.fec_rate = 15;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
-  rtp_sender_->SetFecParameters(params, params);
+  rtp_sender_video.SetFecParameters(params, params);
 
   EXPECT_CALL(mock_paced_sender_,
               InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
@@ -1159,7 +1122,13 @@
   EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
                                                kFlexfecSsrc, _, _, _, false))
       .WillOnce(testing::SaveArg<2>(&flexfec_seq_num));
-  SendGenericPayload();
+
+  RTPVideoHeader video_header;
+  EXPECT_TRUE(rtp_sender_video.SendVideo(
+      kVideoFrameKey, kMediaPayloadType, kTimestamp,
+      fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+      nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
   EXPECT_CALL(mock_rtc_event_log_,
               LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
       .Times(2);
@@ -1183,6 +1152,8 @@
 // TODO(ilnik): because of webrtc:7859. Once FEC moved below pacer, this test
 // should be removed.
 TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
+  constexpr uint32_t kTimestamp = 1234;
+  const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
@@ -1204,6 +1175,10 @@
   rtp_sender_->SetSequenceNumber(kSeqNum);
   rtp_sender_->SetStorePacketsStatus(true, 10);
 
+  RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+                                  &flexfec_sender, nullptr, false);
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
   // Need extension to be registered for timing frames to be sent.
   ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
                    kRtpExtensionVideoTiming, kVideoTimingExtensionId));
@@ -1213,7 +1188,7 @@
   params.fec_rate = 15;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
-  rtp_sender_->SetFecParameters(params, params);
+  rtp_sender_video.SetFecParameters(params, params);
 
   EXPECT_CALL(mock_paced_sender_,
               InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
@@ -1222,17 +1197,11 @@
                                                kFlexfecSsrc, _, _, _, false))
       .Times(0);  // Not called because packet should not be protected.
 
-  const uint32_t kTimestamp = 1234;
-  const uint8_t kPayloadType = 127;
-  const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
-  const char payload_name[] = "GENERIC";
-  EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
-                                            0, 1500));
   RTPVideoHeader video_header;
   video_header.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
-  EXPECT_TRUE(rtp_sender_->SendOutgoingData(
-      kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
-      sizeof(kPayloadData), nullptr, &video_header, nullptr,
+  EXPECT_TRUE(rtp_sender_video.SendVideo(
+      kVideoFrameKey, kMediaPayloadType, kTimestamp, kCaptureTimeMs,
+      kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
       kDefaultExpectedRetransmissionTimeMs));
 
   EXPECT_CALL(mock_rtc_event_log_,
@@ -1256,9 +1225,9 @@
               InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc,
                            kSeqNum + 1, _, _, false));
   video_header.video_timing.flags = VideoSendTiming::kInvalid;
-  EXPECT_TRUE(rtp_sender_->SendOutgoingData(
-      kVideoFrameKey, kPayloadType, kTimestamp + 1, kCaptureTimeMs + 1,
-      kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+  EXPECT_TRUE(rtp_sender_video.SendVideo(
+      kVideoFrameKey, kMediaPayloadType, kTimestamp + 1, kCaptureTimeMs + 1,
+      kPayloadData, sizeof(kPayloadData), nullptr, &video_header,
       kDefaultExpectedRetransmissionTimeMs));
 
   EXPECT_CALL(mock_rtc_event_log_,
@@ -1282,6 +1251,7 @@
 }
 
 TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
+  constexpr uint32_t kTimestamp = 1234;
   constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
@@ -1301,17 +1271,26 @@
   rtp_sender_->SetSSRC(kMediaSsrc);
   rtp_sender_->SetSequenceNumber(kSeqNum);
 
+  RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+                                  &flexfec_sender, nullptr, false);
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
+
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
   params.fec_rate = 15;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
-  rtp_sender_->SetFecParameters(params, params);
+  rtp_sender_video.SetFecParameters(params, params);
 
   EXPECT_CALL(mock_rtc_event_log_,
               LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
       .Times(2);
-  SendGenericPayload();
+  RTPVideoHeader video_header;
+  EXPECT_TRUE(rtp_sender_video.SendVideo(
+      kVideoFrameKey, kMediaPayloadType, kTimestamp,
+      fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+      nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
   ASSERT_EQ(2, transport_.packets_sent());
   const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
   EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
@@ -1333,8 +1312,8 @@
   rtp_sender_->SetSendingMediaStatus(true);
 
   // Send a couple packets.
-  SendGenericPayload();
-  SendGenericPayload();
+  SendGenericPacket();
+  SendGenericPacket();
 
   // Expect both packets to have the MID set.
   ASSERT_EQ(2u, transport_.sent_packets_.size());
@@ -1354,7 +1333,7 @@
   rtp_sender_->SetRid(kRid);
   rtp_sender_->SetSendingMediaStatus(true);
 
-  SendGenericPayload();
+  SendGenericPacket();
 
   ASSERT_EQ(1u, transport_.sent_packets_.size());
   const RtpPacketReceived& packet = transport_.sent_packets_[0];
@@ -1365,7 +1344,6 @@
 
 TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnRtxSentPackets) {
   const char kRid[] = "f";
-  const uint8_t kPayloadType = 127;
 
   rtp_sender_->SetSendingMediaStatus(false);
   rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId,
@@ -1377,11 +1355,11 @@
 
   rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
   rtp_sender_->SetRtxSsrc(1234);
-  rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayloadType);
+  rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
 
   rtp_sender_->SetStorePacketsStatus(true, 10);
 
-  SendGenericPayload();
+  SendGenericPacket();
   ASSERT_EQ(1u, transport_.sent_packets_.size());
   const RtpPacketReceived& packet = transport_.sent_packets_[0];
   std::string rid;
@@ -1400,6 +1378,8 @@
 }
 
 TEST_P(RtpSenderTest, FecOverheadRate) {
+  constexpr uint32_t kTimestamp = 1234;
+  constexpr int kMediaPayloadType = 127;
   constexpr int kFlexfecPayloadType = 118;
   constexpr uint32_t kMediaSsrc = 1234;
   constexpr uint32_t kFlexfecSsrc = 5678;
@@ -1418,12 +1398,15 @@
   rtp_sender_->SetSSRC(kMediaSsrc);
   rtp_sender_->SetSequenceNumber(kSeqNum);
 
+  RTPSenderVideo rtp_sender_video(&fake_clock_, rtp_sender_.get(),
+                                  &flexfec_sender, nullptr, false);
+  rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC");
   // Parameters selected to generate a single FEC packet per media packet.
   FecProtectionParams params;
   params.fec_rate = 15;
   params.max_fec_frames = 1;
   params.fec_mask_type = kFecMaskRandom;
-  rtp_sender_->SetFecParameters(params, params);
+  rtp_sender_video.SetFecParameters(params, params);
 
   constexpr size_t kNumMediaPackets = 10;
   constexpr size_t kNumFecPackets = kNumMediaPackets;
@@ -1431,7 +1414,13 @@
   EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false))
       .Times(kNumMediaPackets + kNumFecPackets);
   for (size_t i = 0; i < kNumMediaPackets; ++i) {
-    SendGenericPayload();
+    RTPVideoHeader video_header;
+
+    EXPECT_TRUE(rtp_sender_video.SendVideo(
+        kVideoFrameKey, kMediaPayloadType, kTimestamp,
+        fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+        nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
     fake_clock_.AdvanceTimeMilliseconds(kTimeBetweenPacketsMs);
   }
   constexpr size_t kRtpHeaderLength = 12;
@@ -1442,7 +1431,7 @@
                                    kGenericCodecHeaderLength + kPayloadLength;
   EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 /
                   (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f),
-              rtp_sender_->FecOverheadRate(), 500);
+              rtp_sender_video.FecOverheadRate(), 500);
 }
 
 TEST_P(RtpSenderTest, BitrateCallbacks) {
@@ -1703,379 +1692,6 @@
   EXPECT_EQ(kNumPackets * 2, transport_.packets_sent());
 }
 
-TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) {
-  uint8_t kFrame[kMaxPacketLength];
-  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
-                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
-  RTPVideoHeader hdr;
-  hdr.rotation = kVideoRotation_0;
-  rtp_sender_video_->SendVideo(kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
-                               sizeof(kFrame), nullptr, &hdr,
-                               kDefaultExpectedRetransmissionTimeMs);
-
-  VideoRotation rotation;
-  EXPECT_TRUE(
-      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
-  EXPECT_EQ(kVideoRotation_0, rotation);
-}
-
-TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
-  uint8_t kFrame[kMaxPacketLength];
-  const int64_t kPacketizationTimeMs = 100;
-  const int64_t kEncodeStartDeltaMs = 10;
-  const int64_t kEncodeFinishDeltaMs = 50;
-  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
-                   kRtpExtensionVideoTiming, kVideoTimingExtensionId));
-
-  const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds();
-
-  RTPVideoHeader hdr;
-  hdr.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
-  hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs;
-  hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs;
-
-  fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs);
-  rtp_sender_video_->SendVideo(
-      kVideoFrameKey, kPayload, kTimestamp, kCaptureTimestamp, kFrame,
-      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs);
-  VideoSendTiming timing;
-  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
-      &timing));
-  EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms);
-  EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms);
-  EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
-}
-
-TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
-  uint8_t kFrame[kMaxPacketLength];
-  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
-                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
-  RTPVideoHeader hdr;
-  hdr.rotation = kVideoRotation_90;
-  EXPECT_TRUE(rtp_sender_video_->SendVideo(
-      kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
-      &hdr, kDefaultExpectedRetransmissionTimeMs));
-
-  hdr.rotation = kVideoRotation_0;
-  EXPECT_TRUE(rtp_sender_video_->SendVideo(
-      kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
-      nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
-  VideoRotation rotation;
-  EXPECT_TRUE(
-      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
-  EXPECT_EQ(kVideoRotation_0, rotation);
-}
-
-TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) {
-  uint8_t kFrame[kMaxPacketLength];
-  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
-                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
-
-  RTPVideoHeader hdr;
-  hdr.rotation = kVideoRotation_90;
-  EXPECT_TRUE(rtp_sender_video_->SendVideo(
-      kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
-      &hdr, kDefaultExpectedRetransmissionTimeMs));
-
-  EXPECT_TRUE(rtp_sender_video_->SendVideo(
-      kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
-      nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
-
-  VideoRotation rotation;
-  EXPECT_TRUE(
-      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
-  EXPECT_EQ(kVideoRotation_90, rotation);
-}
-
-// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits
-// are set in the CVO byte.
-TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
-  // Test extracting rotation when Camera (C) and Flip (F) bits are zero.
-  EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0));
-  EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1));
-  EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2));
-  EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3));
-  // Test extracting rotation when Camera (C) and Flip (F) bits are set.
-  const int flip_bit = 1 << 2;
-  const int camera_bit = 1 << 3;
-  EXPECT_EQ(kVideoRotation_0,
-            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0));
-  EXPECT_EQ(kVideoRotation_90,
-            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1));
-  EXPECT_EQ(kVideoRotation_180,
-            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2));
-  EXPECT_EQ(kVideoRotation_270,
-            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) {
-  RTPVideoHeader header;
-  header.codec = kVideoCodecGeneric;
-
-  EXPECT_EQ(kDontRetransmit,
-            rtp_sender_video_->GetStorageType(
-                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                      header, kRetransmitBaseLayer,
-                                      kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                      header, kRetransmitHigherLayers,
-                                      kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(
-                header, kConditionallyRetransmitHigherLayers,
-                kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) {
-  RTPVideoHeader header;
-  header.video_type_header.emplace<RTPVideoHeaderH264>().packetization_mode =
-      H264PacketizationMode::NonInterleaved;
-  header.codec = kVideoCodecH264;
-
-  EXPECT_EQ(kDontRetransmit,
-            rtp_sender_video_->GetStorageType(
-                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                      header, kRetransmitBaseLayer,
-                                      kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                      header, kRetransmitHigherLayers,
-                                      kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(
-                header, kConditionallyRetransmitHigherLayers,
-                kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) {
-  RTPVideoHeader header;
-  header.codec = kVideoCodecVP8;
-  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
-  vp8_header.temporalIdx = 0;
-
-  EXPECT_EQ(kDontRetransmit,
-            rtp_sender_video_->GetStorageType(
-                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                      header, kRetransmitBaseLayer,
-                                      kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                 header, kRetransmitHigherLayers,
-                                 kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(
-                header, kRetransmitHigherLayers | kRetransmitBaseLayer,
-                kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                 header, kConditionallyRetransmitHigherLayers,
-                                 kDefaultExpectedRetransmissionTimeMs));
-  EXPECT_EQ(
-      kAllowRetransmission,
-      rtp_sender_video_->GetStorageType(
-          header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers,
-          kDefaultExpectedRetransmissionTimeMs));
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) {
-  RTPVideoHeader header;
-  header.codec = kVideoCodecVP8;
-
-  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
-  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
-    vp8_header.temporalIdx = tid;
-
-    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                   header, kRetransmitOff,
-                                   kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                   header, kRetransmitBaseLayer,
-                                   kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                        header, kRetransmitHigherLayers,
-                                        kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kAllowRetransmission,
-              rtp_sender_video_->GetStorageType(
-                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
-                  kDefaultExpectedRetransmissionTimeMs));
-  }
-}
-
-TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) {
-  RTPVideoHeader header;
-  header.codec = kVideoCodecVP9;
-
-  auto& vp9_header = header.video_type_header.emplace<RTPVideoHeaderVP9>();
-  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
-    vp9_header.temporal_idx = tid;
-
-    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                   header, kRetransmitOff,
-                                   kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
-                                   header, kRetransmitBaseLayer,
-                                   kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
-                                        header, kRetransmitHigherLayers,
-                                        kDefaultExpectedRetransmissionTimeMs));
-    EXPECT_EQ(kAllowRetransmission,
-              rtp_sender_video_->GetStorageType(
-                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
-                  kDefaultExpectedRetransmissionTimeMs));
-  }
-}
-
-TEST_P(RtpSenderVideoTest, ConditionalRetransmit) {
-  const int64_t kFrameIntervalMs = 33;
-  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
-  const uint8_t kSettings =
-      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
-
-  // Insert VP8 frames for all temporal layers, but stop before the final index.
-  RTPVideoHeader header;
-  header.codec = kVideoCodecVP8;
-
-  // Fill averaging window to prevent rounding errors.
-  constexpr int kNumRepetitions =
-      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
-      kFrameIntervalMs;
-  constexpr int kPattern[] = {0, 2, 1, 2};
-  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
-  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
-    vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
-    rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
-    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-  }
-
-  // Since we're at the start of the pattern, the next expected frame in TL0 is
-  // right now. We will wait at most one expected retransmission time before
-  // acknowledging that it did not arrive, which means this frame and the next
-  // will not be retransmitted.
-  vp8_header.temporalIdx = 1;
-  EXPECT_EQ(StorageType::kDontRetransmit,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-  EXPECT_EQ(StorageType::kDontRetransmit,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
-  // The TL0 frame did not arrive. So allow retransmission.
-  EXPECT_EQ(StorageType::kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
-  // Insert a frame for TL2. We just had frame in TL1, so the next one there is
-  // in three frames away. TL0 is still too far in the past. So, allow
-  // retransmission.
-  vp8_header.temporalIdx = 2;
-  EXPECT_EQ(StorageType::kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
-  // Another TL2, next in TL1 is two frames away. Allow again.
-  EXPECT_EQ(StorageType::kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-
-  // Yet another TL2, next in TL1 is now only one frame away, so don't store
-  // for retransmission.
-  EXPECT_EQ(StorageType::kDontRetransmit,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-}
-
-TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
-  const int64_t kFrameIntervalMs = 200;
-  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
-  const int32_t kSettings =
-      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
-
-  // Insert VP8 frames for all temporal layers, but stop before the final index.
-  RTPVideoHeader header;
-  header.codec = kVideoCodecVP8;
-
-  // Fill averaging window to prevent rounding errors.
-  constexpr int kNumRepetitions =
-      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
-      kFrameIntervalMs;
-  constexpr int kPattern[] = {0, 2, 2, 2};
-  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
-  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
-    vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
-
-    rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
-    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
-  }
-
-  // Since we're at the start of the pattern, the next expected frame will be
-  // right now in TL0. Put it in TL1 instead. Regular rules would dictate that
-  // we don't store for retransmission because we expect a frame in a lower
-  // layer, but that last frame in TL1 was a long time ago in absolute terms,
-  // so allow retransmission anyway.
-  vp8_header.temporalIdx = 1;
-  EXPECT_EQ(StorageType::kAllowRetransmission,
-            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
-}
-
-TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
-  const int64_t kFrameId = 100000;
-  uint8_t kFrame[100];
-  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
-                   kRtpExtensionGenericFrameDescriptor, kGenericDescriptorId));
-
-  RTPVideoHeader hdr;
-  RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
-  generic.frame_id = kFrameId;
-  generic.temporal_index = 3;
-  generic.spatial_index = 2;
-  generic.higher_spatial_layers.push_back(4);
-  generic.dependencies.push_back(kFrameId - 1);
-  generic.dependencies.push_back(kFrameId - 500);
-  rtp_sender_video_->SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0,
-                               kFrame, sizeof(kFrame), nullptr, &hdr,
-                               kDefaultExpectedRetransmissionTimeMs);
-
-  RtpGenericFrameDescriptor descriptor_wire;
-  EXPECT_EQ(1U, transport_.sent_packets_.size());
-  EXPECT_TRUE(
-      transport_.last_sent_packet()
-          .GetExtension<RtpGenericFrameDescriptorExtension>(&descriptor_wire));
-  EXPECT_EQ(static_cast<uint16_t>(generic.frame_id), descriptor_wire.FrameId());
-  EXPECT_EQ(generic.temporal_index, descriptor_wire.TemporalLayer());
-  EXPECT_THAT(descriptor_wire.FrameDependenciesDiffs(), ElementsAre(1, 500));
-  uint8_t spatial_bitmask = 0x14;
-  EXPECT_EQ(spatial_bitmask, descriptor_wire.SpatialLayersBitmask());
-}
-
-TEST_P(RtpSenderVideoTest,
-       UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed) {
-  const int64_t kFrameId = 100000;
-  const size_t kFrameSize = 100;
-  uint8_t kFrame[kFrameSize];
-  ASSERT_TRUE(rtp_sender_->RegisterRtpHeaderExtension(
-      RtpGenericFrameDescriptorExtension::kUri, kGenericDescriptorId));
-
-  RTPVideoHeader hdr;
-  hdr.codec = kVideoCodecVP8;
-  RTPVideoHeaderVP8& vp8 = hdr.video_type_header.emplace<RTPVideoHeaderVP8>();
-  vp8.pictureId = kFrameId % 0X7FFF;
-  vp8.tl0PicIdx = 13;
-  vp8.temporalIdx = 1;
-  vp8.keyIdx = 2;
-  RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
-  generic.frame_id = kFrameId;
-  rtp_sender_video_->RegisterPayloadType(kPayload, "vp8");
-  rtp_sender_video_->SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0,
-                               kFrame, sizeof(kFrame), nullptr, &hdr,
-                               kDefaultExpectedRetransmissionTimeMs);
-
-  ASSERT_THAT(transport_.sent_packets_, SizeIs(1));
-  // Expect only minimal 1-byte vp8 descriptor was generated.
-  EXPECT_THAT(transport_.sent_packets_[0].payload_size(), 1 + kFrameSize);
-}
-
 TEST_P(RtpSenderTest, OnOverheadChanged) {
   MockOverheadObserver mock_overhead_observer;
   rtp_sender_.reset(new RTPSender(
@@ -2086,7 +1702,7 @@
 
   // RTP overhead is 12B.
   EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(12)).Times(1);
-  SendGenericPayload();
+  SendGenericPacket();
 
   rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
                                           kTransmissionTimeOffsetExtensionId);
@@ -2094,7 +1710,7 @@
   // TransmissionTimeOffset extension has a size of 8B.
   // 12B + 8B = 20B
   EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(20)).Times(1);
-  SendGenericPayload();
+  SendGenericPacket();
 }
 
 TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
@@ -2106,8 +1722,8 @@
   rtp_sender_->SetSSRC(kSsrc);
 
   EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
-  SendGenericPayload();
-  SendGenericPayload();
+  SendGenericPacket();
+  SendGenericPacket();
 }
 
 TEST_P(RtpSenderTest, SendsKeepAlive) {
@@ -2149,8 +1765,5 @@
 INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
                          RtpSenderTestWithoutPacer,
                          ::testing::Bool());
-INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
-                         RtpSenderVideoTest,
-                         ::testing::Bool());
 
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
new file mode 100644
index 0000000..9b155e7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc
@@ -0,0 +1,523 @@
+/*
+ *  Copyright (c) 2019 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/video/video_codec_constants.h"
+#include "api/video/video_timing.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/field_trial.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using ::testing::ElementsAre;
+
+constexpr int kTransmissionTimeOffsetExtensionId = 1;
+constexpr int kAbsoluteSendTimeExtensionId = 14;
+constexpr int kTransportSequenceNumberExtensionId = 13;
+constexpr int kVideoTimingExtensionId = 12;
+constexpr int kGenericDescriptorId = 10;
+constexpr int kVideoRotationExtensionId = 5;
+constexpr int kPayload = 100;
+constexpr uint32_t kTimestamp = 10;
+constexpr uint16_t kSeqNum = 33;
+constexpr uint32_t kSsrc = 725242;
+constexpr int kMaxPacketLength = 1500;
+constexpr uint64_t kStartTime = 123456789;
+constexpr int64_t kDefaultExpectedRetransmissionTimeMs = 125;
+
+class LoopbackTransportTest : public webrtc::Transport {
+ public:
+  LoopbackTransportTest() {
+    receivers_extensions_.Register(kRtpExtensionTransmissionTimeOffset,
+                                   kTransmissionTimeOffsetExtensionId);
+    receivers_extensions_.Register(kRtpExtensionAbsoluteSendTime,
+                                   kAbsoluteSendTimeExtensionId);
+    receivers_extensions_.Register(kRtpExtensionTransportSequenceNumber,
+                                   kTransportSequenceNumberExtensionId);
+    receivers_extensions_.Register(kRtpExtensionVideoRotation,
+                                   kVideoRotationExtensionId);
+    receivers_extensions_.Register(kRtpExtensionVideoTiming,
+                                   kVideoTimingExtensionId);
+    receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor,
+                                   kGenericDescriptorId);
+  }
+
+  bool SendRtp(const uint8_t* data,
+               size_t len,
+               const PacketOptions& options) override {
+    sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_));
+    EXPECT_TRUE(sent_packets_.back().Parse(data, len));
+    return true;
+  }
+  bool SendRtcp(const uint8_t* data, size_t len) override { return false; }
+  const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); }
+  int packets_sent() { return sent_packets_.size(); }
+
+ private:
+  RtpHeaderExtensionMap receivers_extensions_;
+  std::vector<RtpPacketReceived> sent_packets_;
+};
+
+}  // namespace
+
+class TestRtpSenderVideo : public RTPSenderVideo {
+ public:
+  TestRtpSenderVideo(Clock* clock,
+                     RTPSender* rtp_sender,
+                     FlexfecSender* flexfec_sender)
+      : RTPSenderVideo(clock, rtp_sender, flexfec_sender, nullptr, false) {}
+  ~TestRtpSenderVideo() override {}
+
+  StorageType GetStorageType(const RTPVideoHeader& header,
+                             int32_t retransmission_settings,
+                             int64_t expected_retransmission_time_ms) {
+    return RTPSenderVideo::GetStorageType(GetTemporalId(header),
+                                          retransmission_settings,
+                                          expected_retransmission_time_ms);
+  }
+};
+
+class RtpSenderVideoTest : public ::testing::TestWithParam<bool> {
+ public:
+  RtpSenderVideoTest()
+      : field_trials_(GetParam() ? "WebRTC-SendSideBwe-WithOverhead/Enabled/"
+                                 : ""),
+        fake_clock_(kStartTime),
+        retransmission_rate_limiter_(&fake_clock_, 1000),
+        // TODO(pbos): Set up to use pacer.
+        rtp_sender_(false,
+                    &fake_clock_,
+                    &transport_,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    nullptr,
+                    &retransmission_rate_limiter_,
+                    nullptr,
+                    false,
+                    nullptr,
+                    false,
+                    false),
+        rtp_sender_video_(&fake_clock_, &rtp_sender_, nullptr) {
+    rtp_sender_.SetSequenceNumber(kSeqNum);
+    rtp_sender_.SetTimestampOffset(0);
+    rtp_sender_.SetSSRC(kSsrc);
+
+    rtp_sender_video_.RegisterPayloadType(kPayload, "generic");
+  }
+
+ protected:
+  test::ScopedFieldTrials field_trials_;
+  SimulatedClock fake_clock_;
+  LoopbackTransportTest transport_;
+  RateLimiter retransmission_rate_limiter_;
+
+  RTPSender rtp_sender_;
+  TestRtpSenderVideo rtp_sender_video_;
+};
+
+TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_0;
+  rtp_sender_video_.SendVideo(kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
+                              sizeof(kFrame), nullptr, &hdr,
+                              kDefaultExpectedRetransmissionTimeMs);
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
+  uint8_t kFrame[kMaxPacketLength];
+  const int64_t kPacketizationTimeMs = 100;
+  const int64_t kEncodeStartDeltaMs = 10;
+  const int64_t kEncodeFinishDeltaMs = 50;
+  EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(kRtpExtensionVideoTiming,
+                                                      kVideoTimingExtensionId));
+
+  const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds();
+
+  RTPVideoHeader hdr;
+  hdr.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
+  hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs;
+  hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs;
+
+  fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs);
+  rtp_sender_video_.SendVideo(
+      kVideoFrameKey, kPayload, kTimestamp, kCaptureTimestamp, kFrame,
+      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs);
+  VideoSendTiming timing;
+  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
+      &timing));
+  EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms);
+  EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms);
+  EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_90;
+  EXPECT_TRUE(rtp_sender_video_.SendVideo(
+      kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
+      &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  hdr.rotation = kVideoRotation_0;
+  EXPECT_TRUE(rtp_sender_video_.SendVideo(
+      kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
+      nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_90;
+  EXPECT_TRUE(rtp_sender_video_.SendVideo(
+      kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
+      &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_TRUE(rtp_sender_video_.SendVideo(
+      kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, sizeof(kFrame),
+      nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_90, rotation);
+}
+
+// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits
+// are set in the CVO byte.
+TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
+  // Test extracting rotation when Camera (C) and Flip (F) bits are zero.
+  EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0));
+  EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1));
+  EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2));
+  EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3));
+  // Test extracting rotation when Camera (C) and Flip (F) bits are set.
+  const int flip_bit = 1 << 2;
+  const int camera_bit = 1 << 3;
+  EXPECT_EQ(kVideoRotation_0,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0));
+  EXPECT_EQ(kVideoRotation_90,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1));
+  EXPECT_EQ(kVideoRotation_180,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2));
+  EXPECT_EQ(kVideoRotation_270,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecGeneric;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_.GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                      header, kRetransmitHigherLayers,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(
+                header, kConditionallyRetransmitHigherLayers,
+                kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) {
+  RTPVideoHeader header;
+  header.video_type_header.emplace<RTPVideoHeaderH264>().packetization_mode =
+      H264PacketizationMode::NonInterleaved;
+  header.codec = kVideoCodecH264;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_.GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                      header, kRetransmitHigherLayers,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(
+                header, kConditionallyRetransmitHigherLayers,
+                kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+  vp8_header.temporalIdx = 0;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_.GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                 header, kRetransmitHigherLayers,
+                                 kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(
+                header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                 header, kConditionallyRetransmitHigherLayers,
+                                 kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(
+      kAllowRetransmission,
+      rtp_sender_video_.GetStorageType(
+          header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers,
+          kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+    vp8_header.temporalIdx = tid;
+
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                   header, kRetransmitOff,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                   header, kRetransmitBaseLayer,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                        header, kRetransmitHigherLayers,
+                                        kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission,
+              rtp_sender_video_.GetStorageType(
+                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                  kDefaultExpectedRetransmissionTimeMs));
+  }
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP9;
+
+  auto& vp9_header = header.video_type_header.emplace<RTPVideoHeaderVP9>();
+  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+    vp9_header.temporal_idx = tid;
+
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                   header, kRetransmitOff,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_.GetStorageType(
+                                   header, kRetransmitBaseLayer,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_.GetStorageType(
+                                        header, kRetransmitHigherLayers,
+                                        kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission,
+              rtp_sender_video_.GetStorageType(
+                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                  kDefaultExpectedRetransmissionTimeMs));
+  }
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmit) {
+  const int64_t kFrameIntervalMs = 33;
+  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+  const uint8_t kSettings =
+      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+  // Insert VP8 frames for all temporal layers, but stop before the final index.
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  // Fill averaging window to prevent rounding errors.
+  constexpr int kNumRepetitions =
+      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+      kFrameIntervalMs;
+  constexpr int kPattern[] = {0, 2, 1, 2};
+  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+    vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
+    rtp_sender_video_.GetStorageType(header, kSettings, kRttMs);
+    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  }
+
+  // Since we're at the start of the pattern, the next expected frame in TL0 is
+  // right now. We will wait at most one expected retransmission time before
+  // acknowledging that it did not arrive, which means this frame and the next
+  // will not be retransmitted.
+  vp8_header.temporalIdx = 1;
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // The TL0 frame did not arrive. So allow retransmission.
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Insert a frame for TL2. We just had frame in TL1, so the next one there is
+  // in three frames away. TL0 is still too far in the past. So, allow
+  // retransmission.
+  vp8_header.temporalIdx = 2;
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Another TL2, next in TL1 is two frames away. Allow again.
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Yet another TL2, next in TL1 is now only one frame away, so don't store
+  // for retransmission.
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
+  const int64_t kFrameIntervalMs = 200;
+  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+  const int32_t kSettings =
+      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+  // Insert VP8 frames for all temporal layers, but stop before the final index.
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  // Fill averaging window to prevent rounding errors.
+  constexpr int kNumRepetitions =
+      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+      kFrameIntervalMs;
+  constexpr int kPattern[] = {0, 2, 2, 2};
+  auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
+  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+    vp8_header.temporalIdx = kPattern[i % arraysize(kPattern)];
+
+    rtp_sender_video_.GetStorageType(header, kSettings, kRttMs);
+    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  }
+
+  // Since we're at the start of the pattern, the next expected frame will be
+  // right now in TL0. Put it in TL1 instead. Regular rules would dictate that
+  // we don't store for retransmission because we expect a frame in a lower
+  // layer, but that last frame in TL1 was a long time ago in absolute terms,
+  // so allow retransmission anyway.
+  vp8_header.temporalIdx = 1;
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
+}
+
+TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
+  const int64_t kFrameId = 100000;
+  uint8_t kFrame[100];
+  EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
+                   kRtpExtensionGenericFrameDescriptor, kGenericDescriptorId));
+
+  RTPVideoHeader hdr;
+  RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
+  generic.frame_id = kFrameId;
+  generic.temporal_index = 3;
+  generic.spatial_index = 2;
+  generic.higher_spatial_layers.push_back(4);
+  generic.dependencies.push_back(kFrameId - 1);
+  generic.dependencies.push_back(kFrameId - 500);
+  rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0, kFrame,
+                              sizeof(kFrame), nullptr, &hdr,
+                              kDefaultExpectedRetransmissionTimeMs);
+
+  RtpGenericFrameDescriptor descriptor_wire;
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_TRUE(
+      transport_.last_sent_packet()
+          .GetExtension<RtpGenericFrameDescriptorExtension>(&descriptor_wire));
+  EXPECT_EQ(static_cast<uint16_t>(generic.frame_id), descriptor_wire.FrameId());
+  EXPECT_EQ(generic.temporal_index, descriptor_wire.TemporalLayer());
+  EXPECT_THAT(descriptor_wire.FrameDependenciesDiffs(), ElementsAre(1, 500));
+  uint8_t spatial_bitmask = 0x14;
+  EXPECT_EQ(spatial_bitmask, descriptor_wire.SpatialLayersBitmask());
+}
+
+TEST_P(RtpSenderVideoTest,
+       UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed) {
+  const int64_t kFrameId = 100000;
+  const size_t kFrameSize = 100;
+  uint8_t kFrame[kFrameSize];
+  ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
+      RtpGenericFrameDescriptorExtension::kUri, kGenericDescriptorId));
+
+  RTPVideoHeader hdr;
+  hdr.codec = kVideoCodecVP8;
+  RTPVideoHeaderVP8& vp8 = hdr.video_type_header.emplace<RTPVideoHeaderVP8>();
+  vp8.pictureId = kFrameId % 0X7FFF;
+  vp8.tl0PicIdx = 13;
+  vp8.temporalIdx = 1;
+  vp8.keyIdx = 2;
+  RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
+  generic.frame_id = kFrameId;
+  rtp_sender_video_.RegisterPayloadType(kPayload, "vp8");
+  rtp_sender_video_.SendVideo(kVideoFrameDelta, kPayload, kTimestamp, 0, kFrame,
+                              sizeof(kFrame), nullptr, &hdr,
+                              kDefaultExpectedRetransmissionTimeMs);
+
+  ASSERT_EQ(transport_.packets_sent(), 1);
+  // Expect only minimal 1-byte vp8 descriptor was generated.
+  EXPECT_EQ(transport_.last_sent_packet().payload_size(), 1 + kFrameSize);
+}
+
+INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
+                         RtpSenderVideoTest,
+                         ::testing::Bool());
+
+}  // namespace webrtc