Prepare WebRtcVideoReceiveStream for configuration changes.

This is a step in the direction of being able to make configuration
changes without having to tear down and reconstruct the object
during renegotiation.

Bug: none
Change-Id: If594fd41f3a561060f64212c479a25d19adf8598
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/223740
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34402}
diff --git a/call/video_receive_stream.cc b/call/video_receive_stream.cc
index 0b95d66..d0518b6 100644
--- a/call/video_receive_stream.cc
+++ b/call/video_receive_stream.cc
@@ -14,10 +14,18 @@
 
 namespace webrtc {
 
+VideoReceiveStream::Decoder::Decoder(SdpVideoFormat video_format,
+                                     int payload_type)
+    : video_format(std::move(video_format)), payload_type(payload_type) {}
 VideoReceiveStream::Decoder::Decoder() : video_format("Unset") {}
 VideoReceiveStream::Decoder::Decoder(const Decoder&) = default;
 VideoReceiveStream::Decoder::~Decoder() = default;
 
+bool VideoReceiveStream::Decoder::operator==(const Decoder& other) const {
+  return payload_type == other.payload_type &&
+         video_format == other.video_format;
+}
+
 std::string VideoReceiveStream::Decoder::ToString() const {
   char buf[1024];
   rtc::SimpleStringBuilder ss(buf);
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 61edc88..86e5052 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -59,9 +59,13 @@
   // TODO(mflodman) Move all these settings to VideoDecoder and move the
   // declaration to common_types.h.
   struct Decoder {
+    Decoder(SdpVideoFormat video_format, int payload_type);
     Decoder();
     Decoder(const Decoder&);
     ~Decoder();
+
+    bool operator==(const Decoder& other) const;
+
     std::string ToString() const;
 
     SdpVideoFormat video_format;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 897aa77..38a210e 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2875,43 +2875,84 @@
   return rtp_parameters;
 }
 
-void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
+bool WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
     const std::vector<VideoCodecSettings>& recv_codecs) {
   RTC_DCHECK(!recv_codecs.empty());
 
-  config_.decoders.clear();
-  config_.rtp.rtx_associated_payload_types.clear();
-  config_.rtp.raw_payload_types.clear();
+  std::map<int, int> rtx_associated_payload_types;
+  std::set<int> raw_payload_types;
+  std::vector<webrtc::VideoReceiveStream::Decoder> decoders;
   for (const auto& recv_codec : recv_codecs) {
-    webrtc::VideoReceiveStream::Decoder decoder;
-    decoder.payload_type = recv_codec.codec.id;
-    decoder.video_format =
-        webrtc::SdpVideoFormat(recv_codec.codec.name, recv_codec.codec.params);
-    config_.decoders.push_back(decoder);
-    config_.rtp.rtx_associated_payload_types[recv_codec.rtx_payload_type] =
-        recv_codec.codec.id;
+    decoders.emplace_back(
+        webrtc::SdpVideoFormat(recv_codec.codec.name, recv_codec.codec.params),
+        recv_codec.codec.id);
+    rtx_associated_payload_types.insert(
+        {recv_codec.rtx_payload_type, recv_codec.codec.id});
     if (recv_codec.codec.packetization == kPacketizationParamRaw) {
-      config_.rtp.raw_payload_types.insert(recv_codec.codec.id);
+      raw_payload_types.insert(recv_codec.codec.id);
     }
   }
 
-  const auto& codec = recv_codecs.front();
-  config_.rtp.ulpfec_payload_type = codec.ulpfec.ulpfec_payload_type;
-  config_.rtp.red_payload_type = codec.ulpfec.red_payload_type;
+  bool recreate_needed = (stream_ == nullptr);
 
-  config_.rtp.lntf.enabled = HasLntf(codec.codec);
-  config_.rtp.nack.rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
+  const auto& codec = recv_codecs.front();
+  if (config_.rtp.ulpfec_payload_type != codec.ulpfec.ulpfec_payload_type) {
+    config_.rtp.ulpfec_payload_type = codec.ulpfec.ulpfec_payload_type;
+    recreate_needed = true;
+  }
+
+  if (config_.rtp.red_payload_type != codec.ulpfec.red_payload_type) {
+    config_.rtp.red_payload_type = codec.ulpfec.red_payload_type;
+    recreate_needed = true;
+  }
+
+  const bool has_lntf = HasLntf(codec.codec);
+  if (config_.rtp.lntf.enabled != has_lntf) {
+    config_.rtp.lntf.enabled = has_lntf;
+    recreate_needed = true;
+  }
+
+  const int rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
+  if (rtp_history_ms != config_.rtp.nack.rtp_history_ms) {
+    config_.rtp.nack.rtp_history_ms = rtp_history_ms;
+    recreate_needed = true;
+  }
+
   // The rtx-time parameter can be used to override the hardcoded default for
   // the NACK buffer length.
   if (codec.rtx_time != -1 && config_.rtp.nack.rtp_history_ms != 0) {
     config_.rtp.nack.rtp_history_ms = codec.rtx_time;
+    recreate_needed = true;
   }
-  config_.rtp.rtcp_xr.receiver_reference_time_report = HasRrtr(codec.codec);
+
+  const bool has_rtr = HasRrtr(codec.codec);
+  if (has_rtr != config_.rtp.rtcp_xr.receiver_reference_time_report) {
+    config_.rtp.rtcp_xr.receiver_reference_time_report = has_rtr;
+    recreate_needed = true;
+  }
+
   if (codec.ulpfec.red_rtx_payload_type != -1) {
-    config_.rtp
-        .rtx_associated_payload_types[codec.ulpfec.red_rtx_payload_type] =
+    rtx_associated_payload_types[codec.ulpfec.red_rtx_payload_type] =
         codec.ulpfec.red_payload_type;
   }
+
+  if (config_.rtp.rtx_associated_payload_types !=
+      rtx_associated_payload_types) {
+    rtx_associated_payload_types.swap(config_.rtp.rtx_associated_payload_types);
+    recreate_needed = true;
+  }
+
+  if (raw_payload_types != config_.rtp.raw_payload_types) {
+    raw_payload_types.swap(config_.rtp.raw_payload_types);
+    recreate_needed = true;
+  }
+
+  if (decoders != config_.decoders) {
+    decoders.swap(config_.decoders);
+    recreate_needed = true;
+  }
+
+  return recreate_needed;
 }
 
 void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetLocalSsrc(
@@ -2973,8 +3014,7 @@
     const ChangedRecvParameters& params) {
   bool video_needs_recreation = false;
   if (params.codec_settings) {
-    ConfigureCodecs(*params.codec_settings);
-    video_needs_recreation = true;
+    video_needs_recreation = ConfigureCodecs(*params.codec_settings);
   }
 
   if (params.rtp_header_extensions) {
diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h
index e79ebbf..a67a010 100644
--- a/media/engine/webrtc_video_engine.h
+++ b/media/engine/webrtc_video_engine.h
@@ -483,7 +483,10 @@
    private:
     void RecreateWebRtcVideoStream();
 
-    void ConfigureCodecs(const std::vector<VideoCodecSettings>& recv_codecs);
+    // Applies a new receive codecs configration to `config_`. Returns true
+    // if the internal stream needs to be reconstructed, or false if no changes
+    // were applied.
+    bool ConfigureCodecs(const std::vector<VideoCodecSettings>& recv_codecs);
 
     std::string GetCodecNameFromPayloadType(int payload_type);