This was exercised by a test, but multi-codec RED is not currently generated by WebRTC. RED spec allows it, so failing in comparator seems wrong. This was one of the cases where the referenced bug was triggered, but not the only one. Bug: webrtc:384756621 Change-Id: I28c101aa34a62083b72b5f7fc12d25fc637db209 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/372060 Commit-Queue: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43607}
543 lines
22 KiB
C++
543 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
#include "media/base/codec_comparators.h"
|
|
|
|
#include <string>
|
|
|
|
#include "api/audio_codecs/audio_format.h"
|
|
#include "api/rtp_parameters.h"
|
|
#include "api/video_codecs/sdp_video_format.h"
|
|
#include "api/video_codecs/vp9_profile.h"
|
|
#include "media/base/codec.h"
|
|
#include "media/base/media_constants.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
|
|
using cricket::Codec;
|
|
using cricket::CreateAudioCodec;
|
|
using cricket::CreateVideoCodec;
|
|
using cricket::kH264CodecName;
|
|
using cricket::kH264FmtpPacketizationMode;
|
|
using ::testing::TestWithParam;
|
|
using ::testing::ValuesIn;
|
|
|
|
TEST(CodecComparatorsTest, CodecMatchesItself) {
|
|
Codec codec = cricket::CreateVideoCodec("custom");
|
|
EXPECT_TRUE(MatchesWithCodecRules(codec, codec));
|
|
}
|
|
|
|
TEST(CodecComparatorsTest, MismatchedBasicParameters) {
|
|
Codec codec = CreateAudioCodec(SdpAudioFormat("opus", 48000, 2));
|
|
Codec nonmatch_codec = codec;
|
|
nonmatch_codec.name = "g711";
|
|
EXPECT_FALSE(MatchesWithCodecRules(nonmatch_codec, codec));
|
|
nonmatch_codec = codec;
|
|
nonmatch_codec.clockrate = 8000;
|
|
EXPECT_FALSE(MatchesWithCodecRules(nonmatch_codec, codec));
|
|
nonmatch_codec = codec;
|
|
nonmatch_codec.channels = 1;
|
|
EXPECT_FALSE(MatchesWithCodecRules(nonmatch_codec, codec));
|
|
}
|
|
|
|
TEST(CodecComparatorsTest, H264PacketizationModeMismatch) {
|
|
Codec pt_mode_1 = CreateVideoCodec(kH264CodecName);
|
|
Codec pt_mode_0 = pt_mode_1;
|
|
pt_mode_0.SetParam(kH264FmtpPacketizationMode, "0");
|
|
EXPECT_FALSE(MatchesWithCodecRules(pt_mode_1, pt_mode_0));
|
|
EXPECT_FALSE(MatchesWithCodecRules(pt_mode_0, pt_mode_1));
|
|
Codec no_pt_mode = pt_mode_1;
|
|
no_pt_mode.RemoveParam(kH264FmtpPacketizationMode);
|
|
EXPECT_TRUE(MatchesWithCodecRules(pt_mode_0, no_pt_mode));
|
|
EXPECT_TRUE(MatchesWithCodecRules(no_pt_mode, pt_mode_0));
|
|
EXPECT_FALSE(MatchesWithCodecRules(no_pt_mode, pt_mode_1));
|
|
}
|
|
|
|
TEST(CodecComparatorsTest, AudioParametersIgnored) {
|
|
// Currently, all parameters on audio codecs are ignored for matching.
|
|
Codec basic_opus = CreateAudioCodec(SdpAudioFormat("opus", 48000, 2));
|
|
Codec opus_with_parameters = basic_opus;
|
|
opus_with_parameters.SetParam("stereo", "0");
|
|
EXPECT_TRUE(MatchesWithCodecRules(basic_opus, opus_with_parameters));
|
|
EXPECT_TRUE(MatchesWithCodecRules(opus_with_parameters, basic_opus));
|
|
opus_with_parameters.SetParam("nonsense", "stuff");
|
|
EXPECT_TRUE(MatchesWithCodecRules(basic_opus, opus_with_parameters));
|
|
EXPECT_TRUE(MatchesWithCodecRules(opus_with_parameters, basic_opus));
|
|
}
|
|
|
|
TEST(CodecComparatorsTest, StaticPayloadTypesIgnoreName) {
|
|
// This is the IANA registered format for PT 8
|
|
Codec codec_1 = CreateAudioCodec(8, "pcma", 8000, 1);
|
|
Codec codec_2 = CreateAudioCodec(8, "nonsense", 8000, 1);
|
|
EXPECT_TRUE(MatchesWithCodecRules(codec_1, codec_2));
|
|
}
|
|
|
|
TEST(CodecComparatorsTest, MatchesWithReferenceAttributesRed) {
|
|
// Test that RED codecs' reference attributes get parsed correctly.
|
|
Codec codec_1 =
|
|
cricket::CreateAudioCodec(101, cricket::kRedCodecName, 48000, 2);
|
|
codec_1.SetParam(cricket::kCodecParamNotInNameValueFormat, "100/100");
|
|
Codec codec_2 =
|
|
cricket::CreateAudioCodec(102, cricket::kRedCodecName, 48000, 2);
|
|
codec_2.SetParam(cricket::kCodecParamNotInNameValueFormat, "101/101");
|
|
// Mixed codecs in RED
|
|
Codec codec_3 =
|
|
cricket::CreateAudioCodec(103, cricket::kRedCodecName, 48000, 2);
|
|
codec_3.SetParam(cricket::kCodecParamNotInNameValueFormat, "100/101");
|
|
// Identical codecs always match.
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_1, codec_1));
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_2, codec_2));
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_3, codec_3));
|
|
// Mismatched reference codec lists.
|
|
EXPECT_FALSE(MatchesWithReferenceAttributes(codec_1, codec_2));
|
|
EXPECT_FALSE(MatchesWithReferenceAttributes(codec_1, codec_3));
|
|
EXPECT_FALSE(MatchesWithReferenceAttributes(codec_2, codec_3));
|
|
// Overflow of longer lists are ignored.
|
|
// Overlong list - overflow should be ignored.
|
|
Codec codec_4 =
|
|
cricket::CreateAudioCodec(103, cricket::kRedCodecName, 48000, 2);
|
|
codec_4.SetParam(cricket::kCodecParamNotInNameValueFormat, "100/100/101/102");
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_4, codec_4));
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_1, codec_4));
|
|
// Broken syntax will cause a non-match with anything except itself.
|
|
Codec codec_5 =
|
|
cricket::CreateAudioCodec(103, cricket::kRedCodecName, 48000, 2);
|
|
codec_5.SetParam(cricket::kCodecParamNotInNameValueFormat, "");
|
|
EXPECT_TRUE(MatchesWithReferenceAttributes(codec_5, codec_5));
|
|
EXPECT_FALSE(MatchesWithReferenceAttributes(codec_1, codec_5));
|
|
}
|
|
|
|
struct TestParams {
|
|
std::string name;
|
|
SdpVideoFormat codec1;
|
|
SdpVideoFormat codec2;
|
|
bool expected_result;
|
|
};
|
|
|
|
using IsSameRtpCodecTest = TestWithParam<TestParams>;
|
|
|
|
TEST_P(IsSameRtpCodecTest, IsSameRtpCodec) {
|
|
TestParams param = GetParam();
|
|
Codec codec1 = cricket::CreateVideoCodec(param.codec1);
|
|
Codec codec2 = cricket::CreateVideoCodec(param.codec2);
|
|
|
|
EXPECT_EQ(IsSameRtpCodec(codec1, codec2.ToCodecParameters()),
|
|
param.expected_result);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
CodecTest,
|
|
IsSameRtpCodecTest,
|
|
ValuesIn<TestParams>({
|
|
{.name = "CodecWithDifferentName",
|
|
.codec1 = {"VP9", {}},
|
|
.codec2 = {"VP8", {}},
|
|
.expected_result = false},
|
|
{.name = "Vp8WithoutParameters",
|
|
.codec1 = {"vp8", {}},
|
|
.codec2 = {"VP8", {}},
|
|
.expected_result = true},
|
|
{.name = "Vp8WithSameParameters",
|
|
.codec1 = {"VP8", {{"x", "1"}}},
|
|
.codec2 = {"VP8", {{"x", "1"}}},
|
|
.expected_result = true},
|
|
{.name = "Vp8WithDifferentParameters",
|
|
.codec1 = {"VP8", {}},
|
|
.codec2 = {"VP8", {{"x", "1"}}},
|
|
.expected_result = false},
|
|
{.name = "Av1WithoutParameters",
|
|
.codec1 = {"AV1", {}},
|
|
.codec2 = {"AV1", {}},
|
|
.expected_result = true},
|
|
{.name = "Av1WithSameProfile",
|
|
.codec1 = {"AV1", SdpVideoFormat::AV1Profile0().parameters},
|
|
.codec2 = {"AV1", SdpVideoFormat::AV1Profile0().parameters},
|
|
.expected_result = true},
|
|
{.name = "Av1WithoutParametersTreatedAsProfile0",
|
|
.codec1 = {"AV1", SdpVideoFormat::AV1Profile0().parameters},
|
|
.codec2 = {"AV1", {}},
|
|
.expected_result = true},
|
|
{.name = "Av1WithoutProfileTreatedAsProfile0",
|
|
.codec1 = {"AV1", {{cricket::kAv1FmtpProfile, "0"}, {"x", "1"}}},
|
|
.codec2 = {"AV1", {{"x", "1"}}},
|
|
.expected_result = true},
|
|
{.name = "Av1WithDifferentProfile",
|
|
.codec1 = {"AV1", SdpVideoFormat::AV1Profile0().parameters},
|
|
.codec2 = {"AV1", SdpVideoFormat::AV1Profile1().parameters},
|
|
.expected_result = false},
|
|
{.name = "Av1WithDifferentParameters",
|
|
.codec1 = {"AV1", {{cricket::kAv1FmtpProfile, "0"}, {"x", "1"}}},
|
|
.codec2 = {"AV1", {{cricket::kAv1FmtpProfile, "0"}, {"x", "2"}}},
|
|
.expected_result = false},
|
|
{.name = "Vp9WithSameProfile",
|
|
.codec1 = {"VP9", SdpVideoFormat::VP9Profile0().parameters},
|
|
.codec2 = {"VP9", SdpVideoFormat::VP9Profile0().parameters},
|
|
.expected_result = true},
|
|
{.name = "Vp9WithoutProfileTreatedAsProfile0",
|
|
.codec1 = {"VP9", {{kVP9FmtpProfileId, "0"}, {"x", "1"}}},
|
|
.codec2 = {"VP9", {{"x", "1"}}},
|
|
.expected_result = true},
|
|
{.name = "Vp9WithDifferentProfile",
|
|
.codec1 = {"VP9", SdpVideoFormat::VP9Profile0().parameters},
|
|
.codec2 = {"VP9", SdpVideoFormat::VP9Profile1().parameters},
|
|
.expected_result = false},
|
|
{.name = "H264WithSamePacketizationMode",
|
|
.codec1 = {"H264", {{kH264FmtpPacketizationMode, "0"}}},
|
|
.codec2 = {"H264", {{kH264FmtpPacketizationMode, "0"}}},
|
|
.expected_result = true},
|
|
{.name = "H264WithoutPacketizationModeTreatedAsMode0",
|
|
.codec1 = {"H264", {{kH264FmtpPacketizationMode, "0"}, {"x", "1"}}},
|
|
.codec2 = {"H264", {{"x", "1"}}},
|
|
.expected_result = true},
|
|
{.name = "H264WithDifferentPacketizationMode",
|
|
.codec1 = {"H264", {{kH264FmtpPacketizationMode, "0"}}},
|
|
.codec2 = {"H264", {{kH264FmtpPacketizationMode, "1"}}},
|
|
.expected_result = false},
|
|
#ifdef RTC_ENABLE_H265
|
|
{.name = "H265WithSameProfile",
|
|
.codec1 = {"H265",
|
|
{{cricket::kH265FmtpProfileId, "1"},
|
|
{cricket::kH265FmtpTierFlag, "0"},
|
|
{cricket::kH265FmtpLevelId, "93"},
|
|
{cricket::kH265FmtpTxMode, "SRST"}}},
|
|
.codec2 = {"H265",
|
|
{{cricket::kH265FmtpProfileId, "1"},
|
|
{cricket::kH265FmtpTierFlag, "0"},
|
|
{cricket::kH265FmtpLevelId, "93"},
|
|
{cricket::kH265FmtpTxMode, "SRST"}}},
|
|
.expected_result = true},
|
|
{.name = "H265WithoutParametersTreatedAsDefault",
|
|
.codec1 = {"H265",
|
|
{{cricket::kH265FmtpProfileId, "1"},
|
|
{cricket::kH265FmtpTierFlag, "0"},
|
|
{cricket::kH265FmtpLevelId, "93"},
|
|
{cricket::kH265FmtpTxMode, "SRST"}}},
|
|
.codec2 = {"H265", {}},
|
|
.expected_result = true},
|
|
{.name = "H265WithDifferentProfile",
|
|
.codec1 = {"H265",
|
|
{{cricket::kH265FmtpProfileId, "1"},
|
|
{cricket::kH265FmtpTierFlag, "0"},
|
|
{cricket::kH265FmtpLevelId, "93"},
|
|
{cricket::kH265FmtpTxMode, "SRST"}}},
|
|
.codec2 = {"H265",
|
|
{{cricket::kH265FmtpProfileId, "1"},
|
|
{cricket::kH265FmtpTierFlag, "1"},
|
|
{cricket::kH265FmtpLevelId, "93"},
|
|
{cricket::kH265FmtpTxMode, "SRST"}}},
|
|
.expected_result = false},
|
|
#endif
|
|
}),
|
|
[](const testing::TestParamInfo<IsSameRtpCodecTest::ParamType>& info) {
|
|
return info.param.name;
|
|
});
|
|
|
|
TEST(CodecTest, TestCodecMatches) {
|
|
// Test a codec with a static payload type.
|
|
Codec c0 = cricket::CreateAudioCodec(34, "A", 44100, 1);
|
|
EXPECT_TRUE(c0.Matches(cricket::CreateAudioCodec(34, "", 44100, 1)));
|
|
EXPECT_TRUE(c0.Matches(cricket::CreateAudioCodec(34, "", 44100, 0)));
|
|
EXPECT_TRUE(c0.Matches(cricket::CreateAudioCodec(34, "", 44100, 0)));
|
|
EXPECT_TRUE(c0.Matches(cricket::CreateAudioCodec(34, "", 0, 0)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(96, "A", 44100, 1)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(96, "", 44100, 1)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(95, "", 55100, 1)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(95, "", 44100, 1)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(95, "", 44100, 2)));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateAudioCodec(95, "", 55100, 2)));
|
|
|
|
// Test a codec with a dynamic payload type.
|
|
Codec c1 = cricket::CreateAudioCodec(96, "A", 44100, 1);
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(96, "A", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(97, "A", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(96, "a", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(97, "a", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(35, "a", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(42, "a", 0, 0)));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateAudioCodec(65, "a", 0, 0)));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateAudioCodec(95, "A", 0, 0)));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateAudioCodec(34, "A", 0, 0)));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateAudioCodec(96, "", 44100, 2)));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateAudioCodec(96, "A", 55100, 1)));
|
|
|
|
// Test a codec with a dynamic payload type, and auto bitrate.
|
|
Codec c2 = cricket::CreateAudioCodec(97, "A", 16000, 1);
|
|
// Use default bitrate.
|
|
EXPECT_TRUE(c2.Matches(cricket::CreateAudioCodec(97, "A", 16000, 1)));
|
|
EXPECT_TRUE(c2.Matches(cricket::CreateAudioCodec(97, "A", 16000, 0)));
|
|
// Use explicit bitrate.
|
|
EXPECT_TRUE(c2.Matches(cricket::CreateAudioCodec(97, "A", 16000, 1)));
|
|
// Backward compatibility with clients that might send "-1" (for default).
|
|
EXPECT_TRUE(c2.Matches(cricket::CreateAudioCodec(97, "A", 16000, 1)));
|
|
|
|
// Stereo doesn't match channels = 0.
|
|
Codec c3 = cricket::CreateAudioCodec(96, "A", 44100, 2);
|
|
EXPECT_TRUE(c3.Matches(cricket::CreateAudioCodec(96, "A", 44100, 2)));
|
|
EXPECT_FALSE(c3.Matches(cricket::CreateAudioCodec(96, "A", 44100, 1)));
|
|
EXPECT_FALSE(c3.Matches(cricket::CreateAudioCodec(96, "A", 44100, 0)));
|
|
}
|
|
|
|
TEST(CodecTest, TestOpusAudioCodecWithDifferentParameters) {
|
|
Codec opus_with_fec = cricket::CreateAudioCodec(96, "opus", 48000, 2);
|
|
opus_with_fec.params["useinbandfec"] = "1";
|
|
Codec opus_without_fec = cricket::CreateAudioCodec(96, "opus", 48000, 2);
|
|
|
|
EXPECT_TRUE(opus_with_fec != opus_without_fec);
|
|
// Matches does not compare parameters for audio.
|
|
EXPECT_TRUE(opus_with_fec.Matches(opus_without_fec));
|
|
|
|
webrtc::RtpCodecParameters rtp_opus_with_fec =
|
|
opus_with_fec.ToCodecParameters();
|
|
// MatchesRtpCodec takes parameters into account.
|
|
EXPECT_TRUE(opus_with_fec.MatchesRtpCodec(rtp_opus_with_fec));
|
|
EXPECT_FALSE(opus_without_fec.MatchesRtpCodec(rtp_opus_with_fec));
|
|
}
|
|
|
|
TEST(CodecTest, TestVideoCodecMatches) {
|
|
// Test a codec with a static payload type.
|
|
Codec c0 = cricket::CreateVideoCodec(34, "V");
|
|
EXPECT_TRUE(c0.Matches(cricket::CreateVideoCodec(34, "")));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateVideoCodec(96, "")));
|
|
EXPECT_FALSE(c0.Matches(cricket::CreateVideoCodec(96, "V")));
|
|
|
|
// Test a codec with a dynamic payload type.
|
|
Codec c1 = cricket::CreateVideoCodec(96, "V");
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(96, "V")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(97, "V")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(96, "v")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(97, "v")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(35, "v")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(42, "v")));
|
|
EXPECT_TRUE(c1.Matches(cricket::CreateVideoCodec(65, "v")));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateVideoCodec(96, "")));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateVideoCodec(95, "V")));
|
|
EXPECT_FALSE(c1.Matches(cricket::CreateVideoCodec(34, "V")));
|
|
}
|
|
|
|
TEST(CodecTest, TestVideoCodecMatchesWithDifferentPacketization) {
|
|
Codec c0 = cricket::CreateVideoCodec(100, cricket::kVp8CodecName);
|
|
Codec c1 = cricket::CreateVideoCodec(101, cricket::kVp8CodecName);
|
|
c1.packetization = "raw";
|
|
|
|
EXPECT_TRUE(c0.Matches(c1));
|
|
EXPECT_TRUE(c1.Matches(c0));
|
|
}
|
|
|
|
// AV1 codecs compare profile information.
|
|
TEST(CodecTest, TestAV1CodecMatches) {
|
|
const char kProfile0[] = "0";
|
|
const char kProfile1[] = "1";
|
|
const char kProfile2[] = "2";
|
|
|
|
Codec c_no_profile = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
Codec c_profile0 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
c_profile0.params[cricket::kAv1FmtpProfile] = kProfile0;
|
|
Codec c_profile1 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
c_profile1.params[cricket::kAv1FmtpProfile] = kProfile1;
|
|
Codec c_profile2 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
c_profile2.params[cricket::kAv1FmtpProfile] = kProfile2;
|
|
|
|
// An AV1 entry with no profile specified should be treated as profile-0.
|
|
EXPECT_TRUE(c_profile0.Matches(c_no_profile));
|
|
|
|
{
|
|
// Two AV1 entries without a profile specified are treated as duplicates.
|
|
Codec c_no_profile_eq =
|
|
cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
EXPECT_TRUE(c_no_profile.Matches(c_no_profile_eq));
|
|
}
|
|
|
|
{
|
|
// Two AV1 entries with profile 0 specified are treated as duplicates.
|
|
Codec c_profile0_eq = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
c_profile0_eq.params[cricket::kAv1FmtpProfile] = kProfile0;
|
|
EXPECT_TRUE(c_profile0.Matches(c_profile0_eq));
|
|
}
|
|
|
|
{
|
|
// Two AV1 entries with profile 1 specified are treated as duplicates.
|
|
Codec c_profile1_eq = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
|
c_profile1_eq.params[cricket::kAv1FmtpProfile] = kProfile1;
|
|
EXPECT_TRUE(c_profile1.Matches(c_profile1_eq));
|
|
}
|
|
|
|
// AV1 entries with different profiles (0 and 1) are seen as distinct.
|
|
EXPECT_FALSE(c_profile0.Matches(c_profile1));
|
|
EXPECT_FALSE(c_no_profile.Matches(c_profile1));
|
|
|
|
// AV1 entries with different profiles (0 and 2) are seen as distinct.
|
|
EXPECT_FALSE(c_profile0.Matches(c_profile2));
|
|
EXPECT_FALSE(c_no_profile.Matches(c_profile2));
|
|
}
|
|
|
|
// VP9 codecs compare profile information.
|
|
TEST(CodecTest, TestVP9CodecMatches) {
|
|
const char kProfile0[] = "0";
|
|
const char kProfile2[] = "2";
|
|
|
|
Codec c_no_profile = cricket::CreateVideoCodec(95, cricket::kVp9CodecName);
|
|
Codec c_profile0 = cricket::CreateVideoCodec(95, cricket::kVp9CodecName);
|
|
c_profile0.params[webrtc::kVP9FmtpProfileId] = kProfile0;
|
|
|
|
EXPECT_TRUE(c_profile0.Matches(c_no_profile));
|
|
|
|
{
|
|
Codec c_profile0_eq = cricket::CreateVideoCodec(95, cricket::kVp9CodecName);
|
|
c_profile0_eq.params[webrtc::kVP9FmtpProfileId] = kProfile0;
|
|
EXPECT_TRUE(c_profile0.Matches(c_profile0_eq));
|
|
}
|
|
|
|
{
|
|
Codec c_profile2 = cricket::CreateVideoCodec(95, cricket::kVp9CodecName);
|
|
c_profile2.params[webrtc::kVP9FmtpProfileId] = kProfile2;
|
|
EXPECT_FALSE(c_profile0.Matches(c_profile2));
|
|
EXPECT_FALSE(c_no_profile.Matches(c_profile2));
|
|
}
|
|
|
|
{
|
|
Codec c_no_profile_eq =
|
|
cricket::CreateVideoCodec(95, cricket::kVp9CodecName);
|
|
EXPECT_TRUE(c_no_profile.Matches(c_no_profile_eq));
|
|
}
|
|
}
|
|
|
|
// Matching H264 codecs also need to have matching profile-level-id and
|
|
// packetization-mode.
|
|
TEST(CodecTest, TestH264CodecMatches) {
|
|
const char kProfileLevelId1[] = "42e01f";
|
|
const char kProfileLevelId2[] = "42a01e";
|
|
const char kProfileLevelId3[] = "42e01e";
|
|
|
|
Codec pli_1_pm_0 = cricket::CreateVideoCodec(95, "H264");
|
|
pli_1_pm_0.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1;
|
|
pli_1_pm_0.params[cricket::kH264FmtpPacketizationMode] = "0";
|
|
|
|
{
|
|
Codec pli_1_pm_blank = cricket::CreateVideoCodec(95, "H264");
|
|
pli_1_pm_blank.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1;
|
|
pli_1_pm_blank.params.erase(
|
|
pli_1_pm_blank.params.find(cricket::kH264FmtpPacketizationMode));
|
|
|
|
// Matches since if packetization-mode is not specified it defaults to "0".
|
|
EXPECT_TRUE(pli_1_pm_0.Matches(pli_1_pm_blank));
|
|
|
|
// MatchesRtpCodec does exact comparison of parameters.
|
|
EXPECT_FALSE(
|
|
pli_1_pm_0.MatchesRtpCodec(pli_1_pm_blank.ToCodecParameters()));
|
|
}
|
|
|
|
{
|
|
Codec pli_1_pm_1 = cricket::CreateVideoCodec(95, "H264");
|
|
pli_1_pm_1.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1;
|
|
pli_1_pm_1.params[cricket::kH264FmtpPacketizationMode] = "1";
|
|
|
|
// Does not match since packetization-mode is different.
|
|
EXPECT_FALSE(pli_1_pm_0.Matches(pli_1_pm_1));
|
|
|
|
EXPECT_FALSE(pli_1_pm_0.MatchesRtpCodec(pli_1_pm_1.ToCodecParameters()));
|
|
}
|
|
|
|
{
|
|
Codec pli_2_pm_0 = cricket::CreateVideoCodec(95, "H264");
|
|
pli_2_pm_0.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId2;
|
|
pli_2_pm_0.params[cricket::kH264FmtpPacketizationMode] = "0";
|
|
|
|
// Does not match since profile-level-id is different.
|
|
EXPECT_FALSE(pli_1_pm_0.Matches(pli_2_pm_0));
|
|
|
|
EXPECT_FALSE(pli_1_pm_0.MatchesRtpCodec(pli_2_pm_0.ToCodecParameters()));
|
|
}
|
|
|
|
{
|
|
Codec pli_3_pm_0_asym = cricket::CreateVideoCodec(95, "H264");
|
|
pli_3_pm_0_asym.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId3;
|
|
pli_3_pm_0_asym.params[cricket::kH264FmtpPacketizationMode] = "0";
|
|
|
|
// Does match, profile-level-id is different but the level is not compared.
|
|
// and the profile matches.
|
|
EXPECT_TRUE(pli_1_pm_0.Matches(pli_3_pm_0_asym));
|
|
|
|
EXPECT_FALSE(
|
|
pli_1_pm_0.MatchesRtpCodec(pli_3_pm_0_asym.ToCodecParameters()));
|
|
|
|
//
|
|
}
|
|
}
|
|
|
|
#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";
|
|
|
|
Codec c_ptl_blank = cricket::CreateVideoCodec(95, cricket::kH265CodecName);
|
|
|
|
{
|
|
Codec 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));
|
|
}
|
|
|
|
{
|
|
Codec 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));
|
|
}
|
|
|
|
{
|
|
Codec 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 defaults to "93".
|
|
EXPECT_TRUE(c_ptl_blank.Matches(c_level_id_3_1));
|
|
}
|
|
|
|
{
|
|
Codec c_level_id_4 = cricket::CreateVideoCodec(95, cricket::kH265CodecName);
|
|
c_level_id_4.params[cricket::kH265FmtpLevelId] = kLevel4;
|
|
|
|
// Matches since we ignore level-id when matching H.265 codecs.
|
|
EXPECT_TRUE(c_ptl_blank.Matches(c_level_id_4));
|
|
}
|
|
|
|
{
|
|
Codec 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, TestMatchesRtpCodecRtx) {
|
|
const Codec rtx_codec_1 = cricket::CreateVideoRtxCodec(96, 120);
|
|
const Codec rtx_codec_2 = cricket::CreateVideoRtxCodec(96, 121);
|
|
EXPECT_TRUE(rtx_codec_1.Matches(rtx_codec_2));
|
|
// MatchesRtpCodec ignores the different associated payload type (apt) for
|
|
// RTX.
|
|
EXPECT_TRUE(rtx_codec_1.MatchesRtpCodec(rtx_codec_2.ToCodecParameters()));
|
|
}
|
|
|
|
} // namespace webrtc
|