video_replay: add flexfec support

which is useful for validating flexfec recovers frames correctly.
This can be tested by passing a keyframe covered by flexfec along
with the fec packets and removing one packet from the frame.

BUG=None

Change-Id: Icd73eca138f62b9387bf850a6efbd7db03b4b569
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261956
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37392}
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 714d8e4..0d3f2a6 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -213,7 +213,7 @@
       // Set if the stream is protected using FlexFEC.
       bool protected_by_flexfec = false;
 
-      // Optional callback sink to support additional packet handlsers such as
+      // Optional callback sink to support additional packet handlers such as
       // FlexFec.
       RtpPacketSinkInterface* packet_sink_ = nullptr;
 
diff --git a/rtc_tools/video_replay.cc b/rtc_tools/video_replay.cc
index 416da72..346d962 100644
--- a/rtc_tools/video_replay.cc
+++ b/rtc_tools/video_replay.cc
@@ -64,6 +64,12 @@
           webrtc::test::CallTest::kUlpfecPayloadType,
           "ULPFEC payload type");
 
+// Flag for FLEXFEC payload type.
+ABSL_FLAG(int,
+          flexfec_payload_type,
+          webrtc::test::CallTest::kFlexfecPayloadType,
+          "FLEXFEC payload type");
+
 ABSL_FLAG(int,
           media_payload_type_rtx,
           webrtc::test::CallTest::kSendRtxPayloadType,
@@ -84,6 +90,11 @@
           webrtc::test::CallTest::kSendRtxSsrcs[0],
           "Incoming RTX SSRC");
 
+ABSL_FLAG(uint32_t,
+          ssrc_flexfec,
+          webrtc::test::CallTest::kFlexfecSendSsrc,
+          "Incoming FLEXFEC SSRC");
+
 // Flag for abs-send-time id.
 ABSL_FLAG(int, abs_send_time_id, -1, "RTP extension ID for abs-send-time");
 
@@ -160,6 +171,10 @@
   return absl::GetFlag(FLAGS_ulpfec_payload_type);
 }
 
+static int FlexfecPayloadType() {
+  return absl::GetFlag(FLAGS_flexfec_payload_type);
+}
+
 static int MediaPayloadTypeRtx() {
   return absl::GetFlag(FLAGS_media_payload_type_rtx);
 }
@@ -176,6 +191,10 @@
   return absl::GetFlag(FLAGS_ssrc_rtx);
 }
 
+static uint32_t SsrcFlexfec() {
+  return absl::GetFlag(FLAGS_ssrc_flexfec);
+}
+
 static int AbsSendTimeId() {
   return absl::GetFlag(FLAGS_abs_send_time_id);
 }
@@ -377,6 +396,9 @@
       for (const auto& receive_stream : stream_state->receive_streams) {
         call->DestroyVideoReceiveStream(receive_stream);
       }
+      for (const auto& flexfec_stream : stream_state->flexfec_streams) {
+        call->DestroyFlexfecReceiveStream(flexfec_stream);
+      }
       call.reset();
       sync_event.Set();
     }));
@@ -391,6 +413,7 @@
     test::NullTransport transport;
     std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
     std::vector<VideoReceiveStreamInterface*> receive_streams;
+    std::vector<FlexfecReceiveStream*> flexfec_streams;
     std::unique_ptr<VideoDecoderFactory> decoder_factory;
   };
 
@@ -469,6 +492,20 @@
     receive_config.rtp.ulpfec_payload_type = UlpfecPayloadType();
     receive_config.rtp.red_payload_type = RedPayloadType();
     receive_config.rtp.nack.rtp_history_ms = 1000;
+
+    if (FlexfecPayloadType() != -1) {
+      receive_config.rtp.protected_by_flexfec = true;
+      webrtc::FlexfecReceiveStream::Config flexfec_config(
+          &(stream_state->transport));
+      flexfec_config.payload_type = FlexfecPayloadType();
+      flexfec_config.protected_media_ssrcs.push_back(Ssrc());
+      flexfec_config.rtp.remote_ssrc = SsrcFlexfec();
+      FlexfecReceiveStream* flexfec_stream =
+          call->CreateFlexfecReceiveStream(flexfec_config);
+      receive_config.rtp.packet_sink_ = flexfec_stream;
+      stream_state->flexfec_streams.push_back(flexfec_stream);
+    }
+
     if (TransmissionOffsetId() != -1) {
       receive_config.rtp.extensions.push_back(RtpExtension(
           RtpExtension::kTimestampOffsetUri, TransmissionOffsetId()));
@@ -623,6 +660,8 @@
   RTC_CHECK(
       ValidateOptionalPayloadType(absl::GetFlag(FLAGS_ulpfec_payload_type)));
   RTC_CHECK(
+      ValidateOptionalPayloadType(absl::GetFlag(FLAGS_flexfec_payload_type)));
+  RTC_CHECK(
       ValidateRtpHeaderExtensionId(absl::GetFlag(FLAGS_abs_send_time_id)));
   RTC_CHECK(ValidateRtpHeaderExtensionId(
       absl::GetFlag(FLAGS_transmission_offset_id)));