Compare only profile & tier when matching HEVC codec.

Level asymmetry is implicitly enabled for HEVC. When comparing two
codec params to see if they match, we only compare profile & tier,
similar as H.264.

Bug: chromium:41480904
Change-Id: I9e9debdf1b34f33986da9344b9fee14071b1ed60
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/363205
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#43069}
This commit is contained in:
Qiu Jianlin 2024-09-23 16:12:00 +08:00 committed by WebRTC LUCI CQ
parent 93ec3434a5
commit 6f90609fca
8 changed files with 151 additions and 10 deletions

View File

@ -285,6 +285,24 @@ bool H265IsSameProfileTierLevel(const CodecParameterMap& params1,
ptl1->tier == ptl2->tier && ptl1->level == ptl2->level;
}
bool H265IsSameProfile(const CodecParameterMap& params1,
const CodecParameterMap& params2) {
const std::optional<H265ProfileTierLevel> ptl1 =
ParseSdpForH265ProfileTierLevel(params1);
const std::optional<H265ProfileTierLevel> ptl2 =
ParseSdpForH265ProfileTierLevel(params2);
return ptl1 && ptl2 && ptl1->profile == ptl2->profile;
}
bool H265IsSameTier(const CodecParameterMap& params1,
const CodecParameterMap& params2) {
const std::optional<H265ProfileTierLevel> ptl1 =
ParseSdpForH265ProfileTierLevel(params1);
const std::optional<H265ProfileTierLevel> ptl2 =
ParseSdpForH265ProfileTierLevel(params2);
return ptl1 && ptl2 && ptl1->tier == ptl2->tier;
}
std::optional<H265Level> GetSupportedH265Level(const Resolution& resolution,
float max_fps) {
int aligned_width =

View File

@ -107,11 +107,21 @@ RTC_EXPORT std::optional<H265Level> GetSupportedH265Level(
RTC_EXPORT std::optional<H265ProfileTierLevel> ParseSdpForH265ProfileTierLevel(
const CodecParameterMap& params);
// Returns true if the parameters have the same H265 profile or neither contains
// an H265 profile, otherwise false.
// Returns true if the parameters have the same H265 profile/tier/level or
// neither contains an H265 profile/tier/level, otherwise false.
RTC_EXPORT bool H265IsSameProfileTierLevel(const CodecParameterMap& params1,
const CodecParameterMap& params2);
// Returns true if the parameters have the same H265 profile, or neither
// contains an H265 profile, otherwise false.
RTC_EXPORT bool H265IsSameProfile(const CodecParameterMap& params1,
const CodecParameterMap& params2);
// Returns true if the parameters have the same H265 tier, or neither
// contains an H265 tier, otherwise false.
RTC_EXPORT bool H265IsSameTier(const CodecParameterMap& params1,
const CodecParameterMap& params2);
} // namespace webrtc
#endif // API_VIDEO_CODECS_H265_PROFILE_TIER_LEVEL_H_

View File

@ -119,7 +119,8 @@ bool IsSameCodecSpecific(const std::string& name1,
AV1IsSameLevelIdx(params1, params2);
#ifdef RTC_ENABLE_H265
case kVideoCodecH265:
return H265IsSameProfileTierLevel(params1, params2) &&
return H265IsSameProfile(params1, params2) &&
H265IsSameTier(params1, params2) &&
IsSameH265TxMode(params1, params2);
#endif
default:

View File

@ -231,8 +231,9 @@ TEST(H265ProfileTierLevel, TestProfileTierLevelCompare) {
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "93";
params2["level-id"] = "93";
params1["level-id"] = "180";
// Level 3.1 is not allowed for tier 1.
params2["level-id"] = "180";
params1["tier-flag"] = "0";
params2["tier-flag"] = "1";
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
@ -247,6 +248,114 @@ TEST(H265ProfileTierLevel, TestProfileTierLevelCompare) {
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
}
TEST(H265ProfileTierLevel, TestProfileCompare) {
CodecParameterMap params1;
CodecParameterMap params2;
// None of profile-id/tier-flag/level-id is specified,
EXPECT_TRUE(H265IsSameProfile(params1, params2));
// Same non-empty PTL
params1["profile-id"] = "1";
params1["tier-flag"] = "0";
params1["level-id"] = "120";
params2["profile-id"] = "1";
params2["tier-flag"] = "0";
params2["level-id"] = "120";
EXPECT_TRUE(H265IsSameProfile(params1, params2));
// Different profiles.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "2";
EXPECT_FALSE(H265IsSameProfile(params1, params2));
// Different levels. We do not compare HEVC levels.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "93";
params2["level-id"] = "183";
EXPECT_TRUE(H265IsSameProfile(params1, params2));
// Different tiers.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "180";
// level 3.1 is not allowed for tier 1.
params2["level-id"] = "180";
params1["tier-flag"] = "0";
params2["tier-flag"] = "1";
EXPECT_TRUE(H265IsSameProfile(params1, params2));
// One of the CodecParameterMap is invalid.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["tier-flag"] = "0";
params2["tier-flag"] = "4";
EXPECT_FALSE(H265IsSameProfile(params1, params2));
}
TEST(H265ProfileTierLevel, TestTierCompare) {
CodecParameterMap params1;
CodecParameterMap params2;
// None of profile-id/tier-flag/level-id is specified,
EXPECT_TRUE(H265IsSameTier(params1, params2));
// Same non-empty PTL
params1["profile-id"] = "1";
params1["tier-flag"] = "0";
params1["level-id"] = "120";
params2["profile-id"] = "1";
params2["tier-flag"] = "0";
params2["level-id"] = "120";
EXPECT_TRUE(H265IsSameTier(params1, params2));
// Different profiles.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "2";
EXPECT_TRUE(H265IsSameTier(params1, params2));
// Different levels. We do not compare HEVC levels.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "93";
params2["level-id"] = "183";
EXPECT_TRUE(H265IsSameTier(params1, params2));
// Different tiers.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "180";
// level 3.1 is not allowed for tier 1.
params2["level-id"] = "180";
params1["tier-flag"] = "0";
params2["tier-flag"] = "1";
EXPECT_FALSE(H265IsSameTier(params1, params2));
// One of the CodecParameterMap is invalid.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["tier-flag"] = "0";
params2["tier-flag"] = "4";
EXPECT_FALSE(H265IsSameTier(params1, params2));
}
TEST(H265ProfileTierLevel, TestGetSupportedH265Level) {
// Test with 720p at 30fps
Resolution r{.width = 1280, .height = 720};

View File

@ -92,7 +92,7 @@ TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "93"}})));
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "90"}})));
EXPECT_FALSE(
@ -107,7 +107,7 @@ TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "120"}})));
EXPECT_FALSE(
EXPECT_TRUE(
Sdp("H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},

View File

@ -122,7 +122,8 @@ bool IsSameCodecSpecific(const std::string& name1,
AV1IsSameLevelIdx(params1, params2);
#ifdef RTC_ENABLE_H265
if (either_name_matches(kH265CodecName)) {
return webrtc::H265IsSameProfileTierLevel(params1, params2) &&
return webrtc::H265IsSameProfile(params1, params2) &&
webrtc::H265IsSameTier(params1, params2) &&
IsSameH265TxMode(params1, params2);
}
#endif

View File

@ -420,8 +420,8 @@ TEST(CodecTest, TestH265CodecMatches) {
Codec 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));
// Matches since we ignore level-id when matching H.265 codecs.
EXPECT_TRUE(c_ptl_blank.Matches(c_level_id_4));
}
{

View File

@ -1031,6 +1031,8 @@ std::vector<VideoCodecSettings> WebRtcVideoSendChannel::SelectSendVideoCodecs(
// following the spec in https://tools.ietf.org/html/rfc6184#section-8.2.2
// since we should limit the encode level to the lower of local and remote
// level when level asymmetry is not allowed.
// For H.265, the level asymmetry is implicitly allowed. We need to make
// sure the encode level is set to the remote offered level.
if (format_it->IsSameCodec(
{remote_codec.codec.name, remote_codec.codec.params})) {
encoders.push_back(remote_codec);