diff options
Diffstat (limited to '')
19 files changed, 300 insertions, 186 deletions
diff --git a/third_party/libwebrtc/media/BUILD.gn b/third_party/libwebrtc/media/BUILD.gn index 055bf75a19..44638d562e 100644 --- a/third_party/libwebrtc/media/BUILD.gn +++ b/third_party/libwebrtc/media/BUILD.gn @@ -549,7 +549,6 @@ rtc_library("rtc_audio_video") { "../rtc_base:macromagic", "../rtc_base:network_route", "../rtc_base:race_checker", - "../rtc_base:rtc_task_queue", "../rtc_base:safe_conversions", "../rtc_base:socket", "../rtc_base:ssl", diff --git a/third_party/libwebrtc/media/base/codec.cc b/third_party/libwebrtc/media/base/codec.cc index c4e1c6f1f3..d18baf7132 100644 --- a/third_party/libwebrtc/media/base/codec.cc +++ b/third_party/libwebrtc/media/base/codec.cc @@ -15,6 +15,9 @@ #include "api/audio_codecs/audio_format.h" #include "api/video_codecs/av1_profile.h" #include "api/video_codecs/h264_profile_level_id.h" +#ifdef RTC_ENABLE_H265 +#include "api/video_codecs/h265_profile_tier_level.h" +#endif #include "api/video_codecs/vp9_profile.h" #include "media/base/media_constants.h" #include "rtc_base/checks.h" @@ -25,7 +28,8 @@ namespace cricket { namespace { -std::string GetH264PacketizationModeOrDefault(const CodecParameterMap& params) { +std::string GetH264PacketizationModeOrDefault( + const webrtc::CodecParameterMap& params) { auto it = params.find(kH264FmtpPacketizationMode); if (it != params.end()) { return it->second; @@ -35,18 +39,36 @@ std::string GetH264PacketizationModeOrDefault(const CodecParameterMap& params) { return "0"; } -bool IsSameH264PacketizationMode(const CodecParameterMap& left, - const CodecParameterMap& right) { +bool IsSameH264PacketizationMode(const webrtc::CodecParameterMap& left, + const webrtc::CodecParameterMap& right) { return GetH264PacketizationModeOrDefault(left) == GetH264PacketizationModeOrDefault(right); } +#ifdef RTC_ENABLE_H265 +std::string GetH265TxModeOrDefault(const webrtc::CodecParameterMap& params) { + auto it = params.find(kH265FmtpTxMode); + if (it != params.end()) { + return it->second; + } + // If TxMode is not present, a value of "SRST" must be inferred. + // https://tools.ietf.org/html/rfc7798@section-7.1 + return "SRST"; +} + +bool IsSameH265TxMode(const webrtc::CodecParameterMap& left, + const webrtc::CodecParameterMap& right) { + return absl::EqualsIgnoreCase(GetH265TxModeOrDefault(left), + GetH265TxModeOrDefault(right)); +} +#endif + // Some (video) codecs are actually families of codecs and rely on parameters // to distinguish different incompatible family members. bool IsSameCodecSpecific(const std::string& name1, - const CodecParameterMap& params1, + const webrtc::CodecParameterMap& params1, const std::string& name2, - const CodecParameterMap& params2) { + const webrtc::CodecParameterMap& params2) { // The names might not necessarily match, so check both. auto either_name_matches = [&](const std::string name) { return absl::EqualsIgnoreCase(name, name1) || @@ -59,6 +81,12 @@ bool IsSameCodecSpecific(const std::string& name1, return webrtc::VP9IsSameProfile(params1, params2); if (either_name_matches(kAv1CodecName)) return webrtc::AV1IsSameProfile(params1, params2); +#ifdef RTC_ENABLE_H265 + if (either_name_matches(kH265CodecName)) { + return webrtc::H265IsSameProfileTierLevel(params1, params2) && + IsSameH265TxMode(params1, params2); + } +#endif return true; } @@ -222,7 +250,7 @@ bool Codec::MatchesRtpCodec(const webrtc::RtpCodec& codec_capability) const { } bool Codec::GetParam(const std::string& name, std::string* out) const { - CodecParameterMap::const_iterator iter = params.find(name); + webrtc::CodecParameterMap::const_iterator iter = params.find(name); if (iter == params.end()) return false; *out = iter->second; @@ -230,7 +258,7 @@ bool Codec::GetParam(const std::string& name, std::string* out) const { } bool Codec::GetParam(const std::string& name, int* out) const { - CodecParameterMap::const_iterator iter = params.find(name); + webrtc::CodecParameterMap::const_iterator iter = params.find(name); if (iter == params.end()) return false; return rtc::FromString(iter->second, out); @@ -283,7 +311,8 @@ webrtc::RtpCodecParameters Codec::ToCodecParameters() const { } bool Codec::IsMediaCodec() const { - return !IsResiliencyCodec(); + return !IsResiliencyCodec() && + !absl::EqualsIgnoreCase(name, kComfortNoiseCodecName); } bool Codec::IsResiliencyCodec() const { diff --git a/third_party/libwebrtc/media/base/codec.h b/third_party/libwebrtc/media/base/codec.h index bd4239b251..f586f78973 100644 --- a/third_party/libwebrtc/media/base/codec.h +++ b/third_party/libwebrtc/media/base/codec.h @@ -27,8 +27,6 @@ namespace cricket { -using CodecParameterMap = std::map<std::string, std::string>; - class FeedbackParam { public: FeedbackParam() = default; @@ -98,9 +96,12 @@ struct RTC_EXPORT Codec { absl::InlinedVector<webrtc::ScalabilityMode, webrtc::kScalabilityModeCount> scalability_modes; + // H.265 only + absl::optional<std::string> tx_mode; + // Non key-value parameters such as the telephone-event "0‐15" are // represented using an empty string as key, i.e. {"": "0-15"}. - CodecParameterMap params; + webrtc::CodecParameterMap params; FeedbackParams feedback_params; Codec(const Codec& c); @@ -110,7 +111,9 @@ struct RTC_EXPORT Codec { // Indicates if this codec is compatible with the specified codec by // checking the assigned id and profile values for the relevant video codecs. - // H264 levels are not compared. + // For H.264, packetization modes will be compared; If H.265 is enabled, + // TxModes will be compared. + // H.264(and H.265, if enabled) levels are not compared. bool Matches(const Codec& codec) const; bool MatchesRtpCodec(const webrtc::RtpCodec& capability) const; diff --git a/third_party/libwebrtc/media/base/codec_unittest.cc b/third_party/libwebrtc/media/base/codec_unittest.cc index eb34530c38..4dc3b18c21 100644 --- a/third_party/libwebrtc/media/base/codec_unittest.cc +++ b/third_party/libwebrtc/media/base/codec_unittest.cc @@ -342,6 +342,67 @@ TEST(CodecTest, TestH264CodecMatches) { } } +#ifdef RTC_ENABLE_H265 +// Matching H.265 codecs should have matching profile/tier/level and tx-mode. +TEST(CodecTest, TestH265CodecMatches) { + constexpr char kProfile1[] = "1"; + constexpr char kTier1[] = "1"; + constexpr char kLevel3_1[] = "93"; + constexpr char kLevel4[] = "120"; + constexpr char kTxMrst[] = "MRST"; + + VideoCodec c_ptl_blank = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + + { + VideoCodec c_profile_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_profile_1.params[cricket::kH265FmtpProfileId] = kProfile1; + + // Matches since profile-id unspecified defaults to "1". + EXPECT_TRUE(c_ptl_blank.Matches(c_profile_1)); + } + + { + VideoCodec c_tier_flag_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_tier_flag_1.params[cricket::kH265FmtpTierFlag] = kTier1; + + // Does not match since profile-space unspecified defaults to "0". + EXPECT_FALSE(c_ptl_blank.Matches(c_tier_flag_1)); + } + + { + VideoCodec c_level_id_3_1 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_level_id_3_1.params[cricket::kH265FmtpLevelId] = kLevel3_1; + + // Matches since level-id unspecified defautls to "93". + EXPECT_TRUE(c_ptl_blank.Matches(c_level_id_3_1)); + } + + { + VideoCodec c_level_id_4 = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_level_id_4.params[cricket::kH265FmtpLevelId] = kLevel4; + + // Does not match since different level-ids are specified. + EXPECT_FALSE(c_ptl_blank.Matches(c_level_id_4)); + } + + { + VideoCodec c_tx_mode_mrst = + cricket::CreateVideoCodec(95, cricket::kH265CodecName); + c_tx_mode_mrst.params[cricket::kH265FmtpTxMode] = kTxMrst; + + // Does not match since tx-mode implies to "SRST" and must be not specified + // when it is the only mode supported: + // https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-hevc-webrtc + EXPECT_FALSE(c_ptl_blank.Matches(c_tx_mode_mrst)); + } +} +#endif + TEST(CodecTest, TestSetParamGetParamAndRemoveParam) { AudioCodec codec = cricket::CreateAudioCodec(0, "foo", 22222, 2); codec.SetParam("a", "1"); diff --git a/third_party/libwebrtc/media/base/media_channel_impl.cc b/third_party/libwebrtc/media/base/media_channel_impl.cc index 5b41a9ccda..ff69ea62dc 100644 --- a/third_party/libwebrtc/media/base/media_channel_impl.cc +++ b/third_party/libwebrtc/media/base/media_channel_impl.cc @@ -58,18 +58,6 @@ int MediaChannelUtil::GetRtpSendTimeExtnId() const { return -1; } -void MediaChannelUtil::SetFrameEncryptor( - uint32_t ssrc, - rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) { - // Placeholder should be pure virtual once internal supports it. -} - -void MediaChannelUtil::SetFrameDecryptor( - uint32_t ssrc, - rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) { - // Placeholder should be pure virtual once internal supports it. -} - bool MediaChannelUtil::SendPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options) { return transport_.DoSendPacket(packet, false, options); @@ -102,14 +90,6 @@ bool MediaChannelUtil::HasNetworkInterface() const { return transport_.HasNetworkInterface(); } -void MediaChannelUtil::SetEncoderToPacketizerFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr<FrameTransformerInterface> frame_transformer) {} - -void MediaChannelUtil::SetDepacketizerToDecoderFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr<FrameTransformerInterface> frame_transformer) {} - bool MediaChannelUtil::DscpEnabled() const { return transport_.DscpEnabled(); } diff --git a/third_party/libwebrtc/media/base/media_channel_impl.h b/third_party/libwebrtc/media/base/media_channel_impl.h index f8c8174efa..eda47af568 100644 --- a/third_party/libwebrtc/media/base/media_channel_impl.h +++ b/third_party/libwebrtc/media/base/media_channel_impl.h @@ -106,20 +106,6 @@ class MediaChannelUtil { // Must be called on the network thread. bool HasNetworkInterface() const; - void SetFrameEncryptor( - uint32_t ssrc, - rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor); - void SetFrameDecryptor( - uint32_t ssrc, - rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor); - - void SetEncoderToPacketizerFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer); - void SetDepacketizerToDecoderFrameTransformer( - uint32_t ssrc, - rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer); - protected: bool DscpEnabled() const; diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils.cc b/third_party/libwebrtc/media/base/sdp_video_format_utils.cc index a156afdc02..2b756ba734 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils.cc +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils.cc @@ -15,6 +15,9 @@ #include <utility> #include "api/video_codecs/h264_profile_level_id.h" +#ifdef RTC_ENABLE_H265 +#include "api/video_codecs/h265_profile_tier_level.h" +#endif #include "rtc_base/checks.h" #include "rtc_base/string_to_number.h" @@ -27,8 +30,13 @@ const char kVPxFmtpMaxFrameRate[] = "max-fr"; // Max frame size for VP8 and VP9 video. const char kVPxFmtpMaxFrameSize[] = "max-fs"; const int kVPxFmtpFrameSizeSubBlockPixels = 256; +#ifdef RTC_ENABLE_H265 +constexpr char kH265ProfileId[] = "profile-id"; +constexpr char kH265TierFlag[] = "tier-flag"; +constexpr char kH265LevelId[] = "level-id"; +#endif -bool IsH264LevelAsymmetryAllowed(const SdpVideoFormat::Parameters& params) { +bool IsH264LevelAsymmetryAllowed(const CodecParameterMap& params) { const auto it = params.find(kH264LevelAsymmetryAllowed); return it != params.end() && strcmp(it->second.c_str(), "1") == 0; } @@ -47,7 +55,7 @@ H264Level H264LevelMin(H264Level a, H264Level b) { } absl::optional<int> ParsePositiveNumberFromParams( - const SdpVideoFormat::Parameters& params, + const CodecParameterMap& params, const char* parameter_name) { const auto max_frame_rate_it = params.find(parameter_name); if (max_frame_rate_it == params.end()) @@ -60,13 +68,64 @@ absl::optional<int> ParsePositiveNumberFromParams( return i; } +#ifdef RTC_ENABLE_H265 +// Compares two H265Level and return the smaller. +H265Level H265LevelMin(H265Level a, H265Level b) { + return a <= b ? a : b; +} + +// Returns true if none of profile-id/tier-flag/level-id is specified +// explicitly in the param. +bool IsDefaultH265PTL(const CodecParameterMap& params) { + return !params.count(kH265ProfileId) && !params.count(kH265TierFlag) && + !params.count(kH265LevelId); +} +#endif + } // namespace +#ifdef RTC_ENABLE_H265 +// Set level according to https://tools.ietf.org/html/rfc7798#section-7.1 +void H265GenerateProfileTierLevelForAnswer( + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params) { + // If local and remote haven't set profile-id/tier-flag/level-id, they + // are both using the default PTL In this case, don't set PTL in answer + // either. + if (IsDefaultH265PTL(local_supported_params) && + IsDefaultH265PTL(remote_offered_params)) { + return; + } + + // Parse profile-tier-level. + const absl::optional<H265ProfileTierLevel> local_profile_tier_level = + ParseSdpForH265ProfileTierLevel(local_supported_params); + const absl::optional<H265ProfileTierLevel> remote_profile_tier_level = + ParseSdpForH265ProfileTierLevel(remote_offered_params); + // Profile and tier for local and remote codec must be valid and equal. + RTC_DCHECK(local_profile_tier_level); + RTC_DCHECK(remote_profile_tier_level); + RTC_DCHECK_EQ(local_profile_tier_level->profile, + remote_profile_tier_level->profile); + RTC_DCHECK_EQ(local_profile_tier_level->tier, + remote_profile_tier_level->tier); + + const H265Level answer_level = H265LevelMin(local_profile_tier_level->level, + remote_profile_tier_level->level); + + // Level-id in answer is changable as long as the highest level indicated by + // the answer is not higher than that indicated by the offer. See + // https://tools.ietf.org/html/rfc7798#section-7.2.2, sub-clause 2. + (*answer_params)[kH265LevelId] = H265LevelToString(answer_level); +} +#endif + // Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2. void H264GenerateProfileLevelIdForAnswer( - const SdpVideoFormat::Parameters& local_supported_params, - const SdpVideoFormat::Parameters& remote_offered_params, - SdpVideoFormat::Parameters* answer_params) { + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params) { // If both local and remote haven't set profile-level-id, they are both using // the default profile. In this case, don't set profile-level-id in answer // either. @@ -106,12 +165,12 @@ void H264GenerateProfileLevelIdForAnswer( } absl::optional<int> ParseSdpForVPxMaxFrameRate( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate); } absl::optional<int> ParseSdpForVPxMaxFrameSize( - const SdpVideoFormat::Parameters& params) { + const CodecParameterMap& params) { const absl::optional<int> i = ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize); return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels) diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils.h b/third_party/libwebrtc/media/base/sdp_video_format_utils.h index 80c1e4d501..931caa8a29 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils.h +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils.h @@ -32,20 +32,30 @@ namespace webrtc { // parameters that are used when negotiating are the level part of // profile-level-id and level-asymmetry-allowed. void H264GenerateProfileLevelIdForAnswer( - const SdpVideoFormat::Parameters& local_supported_params, - const SdpVideoFormat::Parameters& remote_offered_params, - SdpVideoFormat::Parameters* answer_params); + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params); + +#ifdef RTC_ENABLE_H265 +// Works similarly as H264GenerateProfileLevelIdForAnswer, but generates codec +// parameters that will be used as answer for H.265. +// Media configuration parameters, except level-id, must be used symmetrically. +// For level-id, the highest level indicated by the answer must not be higher +// than that indicated by the offer. +void H265GenerateProfileTierLevelForAnswer( + const CodecParameterMap& local_supported_params, + const CodecParameterMap& remote_offered_params, + CodecParameterMap* answer_params); +#endif // Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the // field is missing or not a number. -absl::optional<int> ParseSdpForVPxMaxFrameRate( - const SdpVideoFormat::Parameters& params); +absl::optional<int> ParseSdpForVPxMaxFrameRate(const CodecParameterMap& params); // Parse max frame size from SDP FMTP line. absl::nullopt is returned if the // field is missing or not a number. Please note that the value is stored in sub // blocks but the returned value is in total number of pixels. -absl::optional<int> ParseSdpForVPxMaxFrameSize( - const SdpVideoFormat::Parameters& params); +absl::optional<int> ParseSdpForVPxMaxFrameSize(const CodecParameterMap& params); } // namespace webrtc diff --git a/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc b/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc index d8ef9ab827..9f505c19d7 100644 --- a/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc +++ b/third_party/libwebrtc/media/base/sdp_video_format_utils_unittest.cc @@ -27,29 +27,28 @@ const char kVPxFmtpMaxFrameSize[] = "max-fs"; } // namespace TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerEmpty) { - SdpVideoFormat::Parameters answer_params; - H264GenerateProfileLevelIdForAnswer(SdpVideoFormat::Parameters(), - SdpVideoFormat::Parameters(), + CodecParameterMap answer_params; + H264GenerateProfileLevelIdForAnswer(CodecParameterMap(), CodecParameterMap(), &answer_params); EXPECT_TRUE(answer_params.empty()); } TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerLevelSymmetryCapped) { - SdpVideoFormat::Parameters low_level; + CodecParameterMap low_level; low_level["profile-level-id"] = "42e015"; - SdpVideoFormat::Parameters high_level; + CodecParameterMap high_level; high_level["profile-level-id"] = "42e01f"; // Level asymmetry is not allowed; test that answer level is the lower of the // local and remote levels. - SdpVideoFormat::Parameters answer_params; + CodecParameterMap answer_params; H264GenerateProfileLevelIdForAnswer(low_level /* local_supported */, high_level /* remote_offered */, &answer_params); EXPECT_EQ("42e015", answer_params["profile-level-id"]); - SdpVideoFormat::Parameters answer_params2; + CodecParameterMap answer_params2; H264GenerateProfileLevelIdForAnswer(high_level /* local_supported */, low_level /* remote_offered */, &answer_params2); @@ -58,13 +57,13 @@ TEST(SdpVideoFormatUtilsTest, TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) { - SdpVideoFormat::Parameters local_params; + CodecParameterMap local_params; local_params["profile-level-id"] = "42e01f"; local_params["level-asymmetry-allowed"] = "1"; - SdpVideoFormat::Parameters remote_params; + CodecParameterMap remote_params; remote_params["profile-level-id"] = "42e015"; remote_params["level-asymmetry-allowed"] = "1"; - SdpVideoFormat::Parameters answer_params; + CodecParameterMap answer_params; H264GenerateProfileLevelIdForAnswer(local_params, remote_params, &answer_params); // When level asymmetry is allowed, we can answer a higher level than what was @@ -72,8 +71,38 @@ TEST(SdpVideoFormatUtilsTest, EXPECT_EQ("42e01f", answer_params["profile-level-id"]); } +#ifdef RTC_ENABLE_H265 +// Answer should not include explicit PTL info if neither local nor remote set +// any of them. +TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelEmpty) { + CodecParameterMap answer_params; + H265GenerateProfileTierLevelForAnswer(CodecParameterMap(), + CodecParameterMap(), &answer_params); + EXPECT_TRUE(answer_params.empty()); +} + +// Answer must use the minimum level as supported by both local and remote. +TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelNoEmpty) { + constexpr char kLocallySupportedLevelId[] = "93"; + constexpr char kRemoteOfferedLevelId[] = "120"; + + CodecParameterMap local_params; + local_params["profile-id"] = "1"; + local_params["tier-flag"] = "0"; + local_params["level-id"] = kLocallySupportedLevelId; + CodecParameterMap remote_params; + remote_params["profile-id"] = "1"; + remote_params["tier-flag"] = "0"; + remote_params["level-id"] = kRemoteOfferedLevelId; + CodecParameterMap answer_params; + H265GenerateProfileTierLevelForAnswer(local_params, remote_params, + &answer_params); + EXPECT_EQ(kLocallySupportedLevelId, answer_params["level-id"]); +} +#endif + TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; absl::optional<int> empty = ParseSdpForVPxMaxFrameRate(params); EXPECT_FALSE(empty); params[kVPxFmtpMaxFrameRate] = "-1"; @@ -85,7 +114,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) { } TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params[kVPxFmtpMaxFrameRate] = "30"; EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30); params[kVPxFmtpMaxFrameRate] = "60"; @@ -93,7 +122,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) { } TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; absl::optional<int> empty = ParseSdpForVPxMaxFrameSize(params); EXPECT_FALSE(empty); params[kVPxFmtpMaxFrameSize] = "-1"; @@ -105,7 +134,7 @@ TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) { } TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsSpecified) { - SdpVideoFormat::Parameters params; + CodecParameterMap params; params[kVPxFmtpMaxFrameSize] = "8100"; // 1920 x 1080 / (16^2) EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080); params[kVPxFmtpMaxFrameSize] = "32400"; // 3840 x 2160 / (16^2) diff --git a/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc b/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc index bb2e24d5d8..51d6a94dd6 100644 --- a/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc +++ b/third_party/libwebrtc/media/engine/internal_decoder_factory_unittest.cc @@ -43,6 +43,8 @@ constexpr bool kDav1dIsIncluded = true; #else constexpr bool kDav1dIsIncluded = false; #endif +constexpr bool kH265Enabled = false; + constexpr VideoDecoderFactory::CodecSupport kSupported = { /*is_supported=*/true, /*is_power_efficient=*/false}; constexpr VideoDecoderFactory::CodecSupport kUnsupported = { @@ -99,6 +101,14 @@ TEST(InternalDecoderFactoryTest, Av1Profile0) { } } +// At current stage since internal H.265 decoder is not implemented, +TEST(InternalDecoderFactoryTest, H265IsNotEnabled) { + InternalDecoderFactory factory; + std::unique_ptr<VideoDecoder> decoder = + factory.CreateVideoDecoder(SdpVideoFormat(cricket::kH265CodecName)); + EXPECT_EQ(static_cast<bool>(decoder), kH265Enabled); +} + #if defined(RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY) TEST(InternalDecoderFactoryTest, Av1) { InternalDecoderFactory factory; diff --git a/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc b/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc index a1c90b8cf4..b9ca6d88c2 100644 --- a/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc +++ b/third_party/libwebrtc/media/engine/internal_encoder_factory_unittest.cc @@ -33,6 +33,8 @@ constexpr bool kH264Enabled = true; #else constexpr bool kH264Enabled = false; #endif +constexpr bool kH265Enabled = false; + constexpr VideoEncoderFactory::CodecSupport kSupported = { /*is_supported=*/true, /*is_power_efficient=*/false}; constexpr VideoEncoderFactory::CodecSupport kUnsupported = { @@ -78,6 +80,17 @@ TEST(InternalEncoderFactoryTest, H264) { } } +// At current stage H.265 is not supported by internal encoder factory. +TEST(InternalEncoderFactoryTest, H265IsNotEnabled) { + InternalEncoderFactory factory; + std::unique_ptr<VideoEncoder> encoder = + factory.CreateVideoEncoder(SdpVideoFormat(cricket::kH265CodecName)); + EXPECT_EQ(static_cast<bool>(encoder), kH265Enabled); + EXPECT_THAT( + factory.GetSupportedFormats(), + Not(Contains(Field(&SdpVideoFormat::name, cricket::kH265CodecName)))); +} + TEST(InternalEncoderFactoryTest, QueryCodecSupportWithScalabilityMode) { InternalEncoderFactory factory; // VP8 and VP9 supported for singles spatial layers. diff --git a/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc b/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc index e2ac5ea390..3ee3465e13 100644 --- a/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc +++ b/third_party/libwebrtc/media/engine/simulcast_encoder_adapter_unittest.cc @@ -586,7 +586,7 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, absl::optional<int> last_encoded_image_simulcast_index_; std::unique_ptr<SimulcastRateAllocator> rate_allocator_; bool use_fallback_factory_; - SdpVideoFormat::Parameters sdp_video_parameters_; + CodecParameterMap sdp_video_parameters_; test::ScopedKeyValueConfig field_trials_; }; diff --git a/third_party/libwebrtc/media/engine/webrtc_media_engine.cc b/third_party/libwebrtc/media/engine/webrtc_media_engine.cc index 463ed29109..31769e05de 100644 --- a/third_party/libwebrtc/media/engine/webrtc_media_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_media_engine.cc @@ -12,53 +12,16 @@ #include <algorithm> #include <map> -#include <memory> #include <string> #include <utility> #include "absl/algorithm/container.h" #include "absl/strings/match.h" -#include "api/transport/field_trial_based_config.h" #include "media/base/media_constants.h" -#include "media/engine/webrtc_voice_engine.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#ifdef HAVE_WEBRTC_VIDEO -#include "media/engine/webrtc_video_engine.h" -#else -#include "media/engine/null_webrtc_video_engine.h" -#endif - namespace cricket { - -std::unique_ptr<MediaEngineInterface> CreateMediaEngine( - MediaEngineDependencies dependencies) { - // TODO(sprang): Make populating `dependencies.trials` mandatory and remove - // these fallbacks. - std::unique_ptr<webrtc::FieldTrialsView> fallback_trials( - dependencies.trials ? nullptr : new webrtc::FieldTrialBasedConfig()); - const webrtc::FieldTrialsView& trials = - dependencies.trials ? *dependencies.trials : *fallback_trials; - auto audio_engine = std::make_unique<WebRtcVoiceEngine>( - dependencies.task_queue_factory, dependencies.adm.get(), - std::move(dependencies.audio_encoder_factory), - std::move(dependencies.audio_decoder_factory), - std::move(dependencies.audio_mixer), - std::move(dependencies.audio_processing), - std::move(dependencies.owned_audio_frame_processor), trials); -#ifdef HAVE_WEBRTC_VIDEO - auto video_engine = std::make_unique<WebRtcVideoEngine>( - std::move(dependencies.video_encoder_factory), - std::move(dependencies.video_decoder_factory), trials); -#else - auto video_engine = std::make_unique<NullWebRtcVideoEngine>(); -#endif - return std::make_unique<CompositeMediaEngine>(std::move(fallback_trials), - std::move(audio_engine), - std::move(video_engine)); -} - namespace { // Remove mutually exclusive extensions with lower priority. void DiscardRedundantExtensions( diff --git a/third_party/libwebrtc/media/engine/webrtc_media_engine.h b/third_party/libwebrtc/media/engine/webrtc_media_engine.h index 863db9f278..5bd5a8bce5 100644 --- a/third_party/libwebrtc/media/engine/webrtc_media_engine.h +++ b/third_party/libwebrtc/media/engine/webrtc_media_engine.h @@ -11,59 +11,17 @@ #ifndef MEDIA_ENGINE_WEBRTC_MEDIA_ENGINE_H_ #define MEDIA_ENGINE_WEBRTC_MEDIA_ENGINE_H_ -#include <memory> #include <vector> #include "absl/strings/string_view.h" #include "api/array_view.h" -#include "api/audio/audio_frame_processor.h" -#include "api/audio/audio_mixer.h" -#include "api/audio_codecs/audio_decoder_factory.h" -#include "api/audio_codecs/audio_encoder_factory.h" #include "api/field_trials_view.h" #include "api/rtp_parameters.h" -#include "api/scoped_refptr.h" -#include "api/task_queue/task_queue_factory.h" #include "api/transport/bitrate_settings.h" -#include "api/video_codecs/video_decoder_factory.h" -#include "api/video_codecs/video_encoder_factory.h" #include "media/base/codec.h" -#include "media/base/media_engine.h" -#include "modules/audio_device/include/audio_device.h" -#include "modules/audio_processing/include/audio_processing.h" -#include "rtc_base/system/rtc_export.h" namespace cricket { -struct MediaEngineDependencies { - MediaEngineDependencies() = default; - MediaEngineDependencies(const MediaEngineDependencies&) = delete; - MediaEngineDependencies(MediaEngineDependencies&&) = default; - MediaEngineDependencies& operator=(const MediaEngineDependencies&) = delete; - MediaEngineDependencies& operator=(MediaEngineDependencies&&) = default; - ~MediaEngineDependencies() = default; - - webrtc::TaskQueueFactory* task_queue_factory = nullptr; - rtc::scoped_refptr<webrtc::AudioDeviceModule> adm; - rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory; - rtc::scoped_refptr<webrtc::AudioDecoderFactory> audio_decoder_factory; - rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer; - rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing; - std::unique_ptr<webrtc::AudioFrameProcessor> owned_audio_frame_processor; - - std::unique_ptr<webrtc::VideoEncoderFactory> video_encoder_factory; - std::unique_ptr<webrtc::VideoDecoderFactory> video_decoder_factory; - - const webrtc::FieldTrialsView* trials = nullptr; -}; - -// CreateMediaEngine may be called on any thread, though the engine is -// only expected to be used on one thread, internally called the "worker -// thread". This is the thread Init must be called on. -[[deprecated("bugs.webrtc.org/15574")]] // -RTC_EXPORT std::unique_ptr<MediaEngineInterface> -CreateMediaEngine(MediaEngineDependencies dependencies); - // Verify that extension IDs are within 1-byte extension range and are not // overlapping, and that they form a legal change from previously registerd // extensions (if any). diff --git a/third_party/libwebrtc/media/engine/webrtc_video_engine.cc b/third_party/libwebrtc/media/engine/webrtc_video_engine.cc index 8a9d6ff95c..a5b46d3344 100644 --- a/third_party/libwebrtc/media/engine/webrtc_video_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_video_engine.cc @@ -1038,13 +1038,19 @@ bool WebRtcVideoSendChannel::GetChangedSenderParameters( return false; } + std::vector<VideoCodecSettings> mapped_codecs = MapCodecs(params.codecs); + if (mapped_codecs.empty()) { + // This suggests a failure in MapCodecs, e.g. inconsistent RTX codecs. + return false; + } + std::vector<VideoCodecSettings> negotiated_codecs = - SelectSendVideoCodecs(MapCodecs(params.codecs)); + SelectSendVideoCodecs(mapped_codecs); - // We should only fail here if send direction is enabled. if (params.is_stream_active && negotiated_codecs.empty()) { - RTC_LOG(LS_ERROR) << "No video codecs supported."; - return false; + // This is not a failure but will lead to the answer being rejected. + RTC_LOG(LS_ERROR) << "No video codecs in common."; + return true; } // Never enable sending FlexFEC, unless we are in the experiment. diff --git a/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc b/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc index f5736679be..148223f497 100644 --- a/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc +++ b/third_party/libwebrtc/media/engine/webrtc_video_engine_unittest.cc @@ -3781,7 +3781,7 @@ class Vp9SettingsTest : public WebRtcVideoChannelTest { TEST_F(Vp9SettingsTest, VerifyVp9SpecificSettings) { encoder_factory_->AddSupportedVideoCodec( - webrtc::SdpVideoFormat("VP9", webrtc::SdpVideoFormat::Parameters(), + webrtc::SdpVideoFormat("VP9", webrtc::CodecParameterMap(), {ScalabilityMode::kL1T1, ScalabilityMode::kL2T1})); cricket::VideoSenderParameters parameters; @@ -8545,7 +8545,7 @@ TEST_F(WebRtcVideoChannelTest, FallbackForUnsetOrUnsupportedScalabilityMode) { ScalabilityMode::kL1T3}; encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP8", webrtc::SdpVideoFormat::Parameters(), kSupportedModes)); + "VP8", webrtc::CodecParameterMap(), kSupportedModes)); FakeVideoSendStream* stream = SetUpSimulcast(true, /*with_rtx=*/false); @@ -8615,9 +8615,9 @@ TEST_F(WebRtcVideoChannelTest, kVp9SupportedModes = {ScalabilityMode::kL3T3}; encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP8", webrtc::SdpVideoFormat::Parameters(), {ScalabilityMode::kL1T1})); + "VP8", webrtc::CodecParameterMap(), {ScalabilityMode::kL1T1})); encoder_factory_->AddSupportedVideoCodec(webrtc::SdpVideoFormat( - "VP9", webrtc::SdpVideoFormat::Parameters(), {ScalabilityMode::kL3T3})); + "VP9", webrtc::CodecParameterMap(), {ScalabilityMode::kL3T3})); cricket::VideoSenderParameters send_parameters; send_parameters.codecs.push_back(GetEngineCodec("VP9")); diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc b/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc index adf662074d..fcc2703f98 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine.cc @@ -377,9 +377,8 @@ void WebRtcVoiceEngine::Init() { // TaskQueue expects to be created/destroyed on the same thread. RTC_DCHECK(!low_priority_worker_queue_); - low_priority_worker_queue_.reset( - new rtc::TaskQueue(task_queue_factory_->CreateTaskQueue( - "rtc-low-prio", webrtc::TaskQueueFactory::Priority::LOW))); + low_priority_worker_queue_ = task_queue_factory_->CreateTaskQueue( + "rtc-low-prio", webrtc::TaskQueueFactory::Priority::LOW); // Load our audio codec lists. RTC_LOG(LS_VERBOSE) << "Supported send codecs in order of preference:"; @@ -761,9 +760,9 @@ std::vector<AudioCodec> WebRtcVoiceEngine::CollectCodecs( out.push_back(codec); if (codec.name == kOpusCodecName) { - std::string redFmtp = + std::string red_fmtp = rtc::ToString(codec.id) + "/" + rtc::ToString(codec.id); - map_format({kRedCodecName, 48000, 2, {{"", redFmtp}}}, &out); + map_format({kRedCodecName, 48000, 2, {{"", red_fmtp}}}, &out); } } } @@ -1318,7 +1317,7 @@ bool WebRtcVoiceSendChannel::SetSenderParameters( } } - if (!SetMaxSendBitrate(params.max_bandwidth_bps)) { + if (send_codec_spec_ && !SetMaxSendBitrate(params.max_bandwidth_bps)) { return false; } return SetOptions(params.options); @@ -1402,7 +1401,8 @@ bool WebRtcVoiceSendChannel::SetSendCodecs( } if (!send_codec_spec) { - return false; + // No codecs in common, bail out early. + return true; } RTC_DCHECK(voice_codec_info); diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine.h b/third_party/libwebrtc/media/engine/webrtc_voice_engine.h index ed71667525..b28b9652bb 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine.h +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine.h @@ -66,7 +66,6 @@ #include "rtc_base/network/sent_packet.h" #include "rtc_base/network_route.h" #include "rtc_base/system/file_wrapper.h" -#include "rtc_base/task_queue.h" namespace webrtc { class AudioFrameProcessor; @@ -141,7 +140,8 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface { void ApplyOptions(const AudioOptions& options); webrtc::TaskQueueFactory* const task_queue_factory_; - std::unique_ptr<rtc::TaskQueue> low_priority_worker_queue_; + std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> + low_priority_worker_queue_; webrtc::AudioDeviceModule* adm(); webrtc::AudioProcessing* apm() const; diff --git a/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc b/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc index 4d6580631d..8ae441bc69 100644 --- a/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc +++ b/third_party/libwebrtc/media/engine/webrtc_voice_engine_unittest.cc @@ -1702,27 +1702,29 @@ TEST_P(WebRtcVoiceEngineTestFake, DontRecreateSendStream) { // TODO(ossu): Revisit if these tests need to be here, now that these kinds of // tests should be available in AudioEncoderOpusTest. -// Test that if clockrate is not 48000 for opus, we fail. +// Test that if clockrate is not 48000 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBadClockrate) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].clockrate = 50000; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channels=0 for opus, we fail. +// Test that if channels=0 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0ChannelsNoStereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 0; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channels=0 for opus, we fail. +// Test that if channels=0 for opus, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0Channels1Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1730,20 +1732,23 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad0Channels1Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 0; parameters.codecs[0].params["stereo"] = "1"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and there's no stereo, we fail. +// Test that if channel is 1 for opus and there's no stereo, we do not have a +// send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpus1ChannelNoStereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; parameters.codecs.push_back(kOpusCodec); parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and stereo=0, we fail. +// Test that if channel is 1 for opus and stereo=0, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel0Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1751,10 +1756,11 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel0Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; parameters.codecs[0].params["stereo"] = "0"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } -// Test that if channel is 1 for opus and stereo=1, we fail. +// Test that if channel is 1 for opus and stereo=1, we do not have a send codec. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel1Stereo) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; @@ -1762,7 +1768,8 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecOpusBad1Channel1Stereo) { parameters.codecs[0].bitrate = 0; parameters.codecs[0].channels = 1; parameters.codecs[0].params["stereo"] = "1"; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } // Test that with bitrate=0 and no stereo, bitrate is 32000. @@ -2035,11 +2042,12 @@ TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsBitrate) { } } -// Test that we fail if no codecs are specified. +// Test that we do not fail if no codecs are specified. TEST_P(WebRtcVoiceEngineTestFake, SetSendCodecsNoCodecs) { EXPECT_TRUE(SetupSendStream()); cricket::AudioSenderParameter parameters; - EXPECT_FALSE(send_channel_->SetSenderParameters(parameters)); + EXPECT_TRUE(send_channel_->SetSenderParameters(parameters)); + EXPECT_EQ(send_channel_->GetSendCodec(), absl::nullopt); } // Test that we can set send codecs even with telephone-event codec as the first |