codec_unittest.cc (11932B)
1 /* 2 * Copyright (c) 2009 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "media/base/codec.h" 12 13 #include <optional> 14 #include <string> 15 #include <vector> 16 17 #include "absl/strings/str_cat.h" 18 #include "api/media_types.h" 19 #include "api/rtp_parameters.h" 20 #include "api/video_codecs/h264_profile_level_id.h" 21 #include "api/video_codecs/sdp_video_format.h" 22 #include "api/video_codecs/vp9_profile.h" 23 #include "media/base/media_constants.h" 24 #include "modules/video_coding/codecs/h264/include/h264.h" 25 #include "test/gtest.h" 26 27 namespace webrtc { 28 namespace { 29 30 class TestCodec : public Codec { 31 public: 32 TestCodec(int id, const std::string& name, int clockrate) 33 : Codec(Type::kAudio, id, name, clockrate) {} 34 TestCodec() : Codec(Type::kAudio) {} 35 TestCodec(const TestCodec& c) = default; 36 TestCodec& operator=(const TestCodec& c) = default; 37 }; 38 39 TEST(CodecTest, TestCodecOperators) { 40 TestCodec c0(96, "D", 1000); 41 c0.SetParam("a", 1); 42 43 TestCodec c1 = c0; 44 EXPECT_TRUE(c1 == c0); 45 46 int param_value0; 47 int param_value1; 48 EXPECT_TRUE(c0.GetParam("a", ¶m_value0)); 49 EXPECT_TRUE(c1.GetParam("a", ¶m_value1)); 50 EXPECT_EQ(param_value0, param_value1); 51 52 c1.id = 86; 53 EXPECT_TRUE(c0 != c1); 54 55 c1 = c0; 56 c1.name = "x"; 57 EXPECT_TRUE(c0 != c1); 58 59 c1 = c0; 60 c1.clockrate = 2000; 61 EXPECT_TRUE(c0 != c1); 62 63 c1 = c0; 64 c1.SetParam("a", 2); 65 EXPECT_TRUE(c0 != c1); 66 67 TestCodec c5; 68 TestCodec c6(Codec::kIdNotSet, "", kDefaultAudioClockRateHz); 69 EXPECT_TRUE(c5 == c6); 70 } 71 72 TEST(CodecTest, TestAudioCodecOperators) { 73 Codec c0 = CreateAudioCodec(96, "A", 44100, 2); 74 Codec c1 = CreateAudioCodec(95, "A", 44100, 2); 75 Codec c2 = CreateAudioCodec(96, "x", 44100, 2); 76 Codec c3 = CreateAudioCodec(96, "A", 48000, 2); 77 Codec c4 = CreateAudioCodec(96, "A", 44100, 2); 78 c4.bitrate = 10000; 79 Codec c5 = CreateAudioCodec(96, "A", 44100, 1); 80 EXPECT_NE(c0, c1); 81 EXPECT_NE(c0, c2); 82 EXPECT_NE(c0, c3); 83 EXPECT_NE(c0, c4); 84 EXPECT_NE(c0, c5); 85 86 Codec c8 = CreateAudioCodec(0, "", kDefaultAudioClockRateHz, 0); 87 Codec c9 = c0; 88 EXPECT_EQ(c9, c0); 89 90 Codec c10(c0); 91 Codec c11(c0); 92 Codec c12(c0); 93 Codec c13(c0); 94 c10.params["x"] = "abc"; 95 c11.params["x"] = "def"; 96 c12.params["y"] = "abc"; 97 c13.params["x"] = "abc"; 98 EXPECT_NE(c10, c0); 99 EXPECT_NE(c11, c0); 100 EXPECT_NE(c11, c10); 101 EXPECT_NE(c12, c0); 102 EXPECT_NE(c12, c10); 103 EXPECT_NE(c12, c11); 104 EXPECT_EQ(c13, c10); 105 } 106 107 TEST(CodecTest, TestVideoCodecOperators) { 108 Codec c0 = CreateVideoCodec(96, "V"); 109 Codec c1 = CreateVideoCodec(95, "V"); 110 Codec c2 = CreateVideoCodec(96, "x"); 111 112 EXPECT_TRUE(c0 != c1); 113 EXPECT_TRUE(c0 != c2); 114 115 Codec c8 = CreateVideoCodec(0, ""); 116 Codec c9 = c0; 117 EXPECT_TRUE(c9 == c0); 118 119 Codec c10(c0); 120 Codec c11(c0); 121 Codec c12(c0); 122 Codec c13(c0); 123 c10.params["x"] = "abc"; 124 c11.params["x"] = "def"; 125 c12.params["y"] = "abc"; 126 c13.params["x"] = "abc"; 127 EXPECT_TRUE(c10 != c0); 128 EXPECT_TRUE(c11 != c0); 129 EXPECT_TRUE(c11 != c10); 130 EXPECT_TRUE(c12 != c0); 131 EXPECT_TRUE(c12 != c10); 132 EXPECT_TRUE(c12 != c11); 133 EXPECT_TRUE(c13 == c10); 134 } 135 136 TEST(CodecTest, TestVideoCodecEqualsWithDifferentPacketization) { 137 Codec c0 = CreateVideoCodec(100, kVp8CodecName); 138 Codec c1 = CreateVideoCodec(100, kVp8CodecName); 139 Codec c2 = CreateVideoCodec(100, kVp8CodecName); 140 c2.packetization = "raw"; 141 142 EXPECT_EQ(c0, c1); 143 EXPECT_NE(c0, c2); 144 EXPECT_NE(c2, c0); 145 EXPECT_EQ(c2, c2); 146 } 147 148 TEST(CodecTest, TestSetParamGetParamAndRemoveParam) { 149 Codec codec = CreateAudioCodec(0, "foo", 22222, 2); 150 codec.SetParam("a", "1"); 151 codec.SetParam("b", "x"); 152 153 int int_value = 0; 154 EXPECT_TRUE(codec.GetParam("a", &int_value)); 155 EXPECT_EQ(1, int_value); 156 EXPECT_FALSE(codec.GetParam("b", &int_value)); 157 EXPECT_FALSE(codec.GetParam("c", &int_value)); 158 159 std::string str_value; 160 EXPECT_TRUE(codec.GetParam("a", &str_value)); 161 EXPECT_EQ("1", str_value); 162 EXPECT_TRUE(codec.GetParam("b", &str_value)); 163 EXPECT_EQ("x", str_value); 164 EXPECT_FALSE(codec.GetParam("c", &str_value)); 165 EXPECT_TRUE(codec.RemoveParam("a")); 166 EXPECT_FALSE(codec.RemoveParam("c")); 167 } 168 169 TEST(CodecTest, TestIntersectFeedbackParams) { 170 const FeedbackParam a1("a", "1"); 171 const FeedbackParam b2("b", "2"); 172 const FeedbackParam b3("b", "3"); 173 const FeedbackParam c3("c", "3"); 174 TestCodec c1; 175 c1.AddFeedbackParam(a1); // Only match with c2. 176 c1.AddFeedbackParam(b2); // Same param different values. 177 c1.AddFeedbackParam(c3); // Not in c2. 178 TestCodec c2; 179 c2.AddFeedbackParam(a1); 180 c2.AddFeedbackParam(b3); 181 182 c1.IntersectFeedbackParams(c2); 183 EXPECT_TRUE(c1.HasFeedbackParam(a1)); 184 EXPECT_FALSE(c1.HasFeedbackParam(b2)); 185 EXPECT_FALSE(c1.HasFeedbackParam(c3)); 186 } 187 188 TEST(CodecTest, TestGetCodecType) { 189 // Codec type comparison should be case insensitive on names. 190 const Codec codec = CreateVideoCodec(96, "V"); 191 const Codec rtx_codec = CreateVideoCodec(96, "rTx"); 192 const Codec ulpfec_codec = CreateVideoCodec(96, "ulpFeC"); 193 const Codec flexfec_codec = CreateVideoCodec(96, "FlExFeC-03"); 194 const Codec red_codec = CreateVideoCodec(96, "ReD"); 195 EXPECT_TRUE(codec.IsMediaCodec()); 196 EXPECT_EQ(codec.GetResiliencyType(), Codec::ResiliencyType::kNone); 197 EXPECT_EQ(rtx_codec.GetResiliencyType(), Codec::ResiliencyType::kRtx); 198 EXPECT_EQ(ulpfec_codec.GetResiliencyType(), Codec::ResiliencyType::kUlpfec); 199 EXPECT_EQ(flexfec_codec.GetResiliencyType(), Codec::ResiliencyType::kFlexfec); 200 EXPECT_EQ(red_codec.GetResiliencyType(), Codec::ResiliencyType::kRed); 201 } 202 203 TEST(CodecTest, TestCreateRtxCodec) { 204 const Codec rtx_codec = CreateVideoRtxCodec(96, 120); 205 EXPECT_EQ(96, rtx_codec.id); 206 EXPECT_EQ(rtx_codec.GetResiliencyType(), Codec::ResiliencyType::kRtx); 207 int associated_payload_type; 208 ASSERT_TRUE(rtx_codec.GetParam(kCodecParamAssociatedPayloadType, 209 &associated_payload_type)); 210 EXPECT_EQ(120, associated_payload_type); 211 } 212 213 TEST(CodecTest, TestValidateCodecFormat) { 214 const Codec codec = CreateVideoCodec(96, "V"); 215 ASSERT_TRUE(codec.ValidateCodecFormat()); 216 217 // Accept 0-127 as payload types. 218 Codec low_payload_type = codec; 219 low_payload_type.id = 0; 220 Codec high_payload_type = codec; 221 high_payload_type.id = 127; 222 ASSERT_TRUE(low_payload_type.ValidateCodecFormat()); 223 EXPECT_TRUE(high_payload_type.ValidateCodecFormat()); 224 225 // Reject negative payloads. 226 Codec negative_payload_type = codec; 227 negative_payload_type.id = -1; 228 EXPECT_FALSE(negative_payload_type.ValidateCodecFormat()); 229 230 // Reject too-high payloads. 231 Codec too_high_payload_type = codec; 232 too_high_payload_type.id = 128; 233 EXPECT_FALSE(too_high_payload_type.ValidateCodecFormat()); 234 235 // Reject codecs with min bitrate > max bitrate. 236 Codec incorrect_bitrates = codec; 237 incorrect_bitrates.params[kCodecParamMinBitrate] = "100"; 238 incorrect_bitrates.params[kCodecParamMaxBitrate] = "80"; 239 EXPECT_FALSE(incorrect_bitrates.ValidateCodecFormat()); 240 241 // Accept min bitrate == max bitrate. 242 Codec equal_bitrates = codec; 243 equal_bitrates.params[kCodecParamMinBitrate] = "100"; 244 equal_bitrates.params[kCodecParamMaxBitrate] = "100"; 245 EXPECT_TRUE(equal_bitrates.ValidateCodecFormat()); 246 247 // Accept min bitrate < max bitrate. 248 Codec different_bitrates = codec; 249 different_bitrates.params[kCodecParamMinBitrate] = "99"; 250 different_bitrates.params[kCodecParamMaxBitrate] = "100"; 251 EXPECT_TRUE(different_bitrates.ValidateCodecFormat()); 252 } 253 254 TEST(CodecTest, TestToCodecParameters) { 255 Codec v = CreateVideoCodec(96, "V"); 256 v.SetParam("p1", "v1"); 257 RtpCodecParameters codec_params_1 = v.ToCodecParameters(); 258 EXPECT_EQ(96, codec_params_1.payload_type); 259 EXPECT_EQ(MediaType::VIDEO, codec_params_1.kind); 260 EXPECT_EQ("V", codec_params_1.name); 261 EXPECT_EQ(kVideoCodecClockrate, codec_params_1.clock_rate); 262 EXPECT_EQ(std::nullopt, codec_params_1.num_channels); 263 ASSERT_EQ(1u, codec_params_1.parameters.size()); 264 EXPECT_EQ("p1", codec_params_1.parameters.begin()->first); 265 EXPECT_EQ("v1", codec_params_1.parameters.begin()->second); 266 267 Codec a = CreateAudioCodec(97, "A", 44100, 2); 268 a.SetParam("p1", "a1"); 269 RtpCodecParameters codec_params_2 = a.ToCodecParameters(); 270 EXPECT_EQ(97, codec_params_2.payload_type); 271 EXPECT_EQ(MediaType::AUDIO, codec_params_2.kind); 272 EXPECT_EQ("A", codec_params_2.name); 273 EXPECT_EQ(44100, codec_params_2.clock_rate); 274 EXPECT_EQ(2, codec_params_2.num_channels); 275 ASSERT_EQ(1u, codec_params_2.parameters.size()); 276 EXPECT_EQ("p1", codec_params_2.parameters.begin()->first); 277 EXPECT_EQ("a1", codec_params_2.parameters.begin()->second); 278 } 279 280 TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) { 281 const std::vector<SdpVideoFormat> kExplicitlySupportedFormats = { 282 CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 283 "1"), 284 CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 285 "0")}; 286 287 std::vector<SdpVideoFormat> supported_formats = kExplicitlySupportedFormats; 288 AddH264ConstrainedBaselineProfileToSupportedFormats(&supported_formats); 289 290 const SdpVideoFormat kH264ConstrainedBasedlinePacketization1 = 291 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 292 H264Level::kLevel3_1, "1"); 293 const SdpVideoFormat kH264ConstrainedBasedlinePacketization0 = 294 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 295 H264Level::kLevel3_1, "0"); 296 297 EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]); 298 EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]); 299 EXPECT_EQ(supported_formats[2], kH264ConstrainedBasedlinePacketization1); 300 EXPECT_EQ(supported_formats[3], kH264ConstrainedBasedlinePacketization0); 301 } 302 303 TEST(CodecTest, H264CostrainedBaselineIsNotAddedIfH264IsUnsupported) { 304 const std::vector<SdpVideoFormat> kExplicitlySupportedFormats = { 305 {kVp9CodecName, 306 {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile0)}}}}; 307 308 std::vector<SdpVideoFormat> supported_formats = kExplicitlySupportedFormats; 309 AddH264ConstrainedBaselineProfileToSupportedFormats(&supported_formats); 310 311 EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]); 312 EXPECT_EQ(supported_formats.size(), kExplicitlySupportedFormats.size()); 313 } 314 315 TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) { 316 const std::vector<SdpVideoFormat> kExplicitlySupportedFormats = { 317 CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 318 "1"), 319 CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 320 "0"), 321 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 322 H264Level::kLevel3_1, "1"), 323 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 324 H264Level::kLevel3_1, "0")}; 325 326 std::vector<SdpVideoFormat> supported_formats = kExplicitlySupportedFormats; 327 AddH264ConstrainedBaselineProfileToSupportedFormats(&supported_formats); 328 329 EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]); 330 EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]); 331 EXPECT_EQ(supported_formats[2], kExplicitlySupportedFormats[2]); 332 EXPECT_EQ(supported_formats[3], kExplicitlySupportedFormats[3]); 333 EXPECT_EQ(supported_formats.size(), kExplicitlySupportedFormats.size()); 334 } 335 336 TEST(CodecTest, AbslStringify) { 337 Codec codec = CreateAudioCodec(47, "custom-audio", 48000, 2); 338 EXPECT_EQ(absl::StrCat(codec), "[47:audio/custom-audio/48000/2]"); 339 codec.params["key"] = "value"; 340 EXPECT_EQ(absl::StrCat(codec), "[47:audio/custom-audio/48000/2;key=value]"); 341 } 342 343 } // namespace 344 } // namespace webrtc