diff --git a/call/video_receive_stream.cc b/call/video_receive_stream.cc index 0b95d66767..d0518b6e0d 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 61edc886cb..86e5052151 100644 --- a/call/video_receive_stream.h +++ b/call/video_receive_stream.h @@ -59,9 +59,13 @@ class VideoReceiveStream : public MediaReceiveStream { // 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 897aa77ac5..38a210ee7d 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -2875,43 +2875,84 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetRtpParameters() const { return rtp_parameters; } -void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs( +bool WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs( const std::vector& 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 rtx_associated_payload_types; + std::set raw_payload_types; + std::vector 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); + + 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; + } - config_.rtp.lntf.enabled = HasLntf(codec.codec); - config_.rtp.nack.rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0; // 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 @@ void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetRecvParameters( 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 e79ebbf24a..a67a010ed7 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -483,7 +483,10 @@ class WebRtcVideoChannel : public VideoMediaChannel, private: void RecreateWebRtcVideoStream(); - void ConfigureCodecs(const std::vector& 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& recv_codecs); std::string GetCodecNameFromPayloadType(int payload_type);