Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2019 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/sdp_video_format_utils.h" |
| 12 | |
| 13 | #include <string.h> |
| 14 | |
| 15 | #include <map> |
| 16 | #include <utility> |
| 17 | |
| 18 | #include "rtc_base/string_to_number.h" |
| 19 | #include "test/gtest.h" |
| 20 | |
| 21 | namespace webrtc { |
| 22 | namespace { |
| 23 | // Max frame rate for VP8 and VP9 video. |
| 24 | const char kVPxFmtpMaxFrameRate[] = "max-fr"; |
| 25 | // Max frame size for VP8 and VP9 video. |
| 26 | const char kVPxFmtpMaxFrameSize[] = "max-fs"; |
| 27 | } // namespace |
| 28 | |
| 29 | TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerEmpty) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 30 | CodecParameterMap answer_params; |
| 31 | H264GenerateProfileLevelIdForAnswer(CodecParameterMap(), CodecParameterMap(), |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 32 | &answer_params); |
| 33 | EXPECT_TRUE(answer_params.empty()); |
| 34 | } |
| 35 | |
| 36 | TEST(SdpVideoFormatUtilsTest, |
| 37 | TestH264GenerateProfileLevelIdForAnswerLevelSymmetryCapped) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 38 | CodecParameterMap low_level; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 39 | low_level["profile-level-id"] = "42e015"; |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 40 | CodecParameterMap high_level; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 41 | high_level["profile-level-id"] = "42e01f"; |
| 42 | |
| 43 | // Level asymmetry is not allowed; test that answer level is the lower of the |
| 44 | // local and remote levels. |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 45 | CodecParameterMap answer_params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 46 | H264GenerateProfileLevelIdForAnswer(low_level /* local_supported */, |
| 47 | high_level /* remote_offered */, |
| 48 | &answer_params); |
| 49 | EXPECT_EQ("42e015", answer_params["profile-level-id"]); |
| 50 | |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 51 | CodecParameterMap answer_params2; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 52 | H264GenerateProfileLevelIdForAnswer(high_level /* local_supported */, |
| 53 | low_level /* remote_offered */, |
| 54 | &answer_params2); |
| 55 | EXPECT_EQ("42e015", answer_params2["profile-level-id"]); |
| 56 | } |
| 57 | |
| 58 | TEST(SdpVideoFormatUtilsTest, |
| 59 | TestH264GenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 60 | CodecParameterMap local_params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 61 | local_params["profile-level-id"] = "42e01f"; |
| 62 | local_params["level-asymmetry-allowed"] = "1"; |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 63 | CodecParameterMap remote_params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 64 | remote_params["profile-level-id"] = "42e015"; |
| 65 | remote_params["level-asymmetry-allowed"] = "1"; |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 66 | CodecParameterMap answer_params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 67 | H264GenerateProfileLevelIdForAnswer(local_params, remote_params, |
| 68 | &answer_params); |
| 69 | // When level asymmetry is allowed, we can answer a higher level than what was |
| 70 | // offered. |
| 71 | EXPECT_EQ("42e01f", answer_params["profile-level-id"]); |
| 72 | } |
| 73 | |
Qiu Jianlin | b3488d0 | 2023-12-07 00:12:12 | [diff] [blame] | 74 | #ifdef RTC_ENABLE_H265 |
| 75 | // Answer should not include explicit PTL info if neither local nor remote set |
| 76 | // any of them. |
| 77 | TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelEmpty) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 78 | CodecParameterMap answer_params; |
| 79 | H265GenerateProfileTierLevelForAnswer(CodecParameterMap(), |
| 80 | CodecParameterMap(), &answer_params); |
Qiu Jianlin | b3488d0 | 2023-12-07 00:12:12 | [diff] [blame] | 81 | EXPECT_TRUE(answer_params.empty()); |
| 82 | } |
| 83 | |
| 84 | // Answer must use the minimum level as supported by both local and remote. |
| 85 | TEST(SdpVideoFormatUtilsTest, H265GenerateProfileTierLevelNoEmpty) { |
| 86 | constexpr char kLocallySupportedLevelId[] = "93"; |
| 87 | constexpr char kRemoteOfferedLevelId[] = "120"; |
| 88 | |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 89 | CodecParameterMap local_params; |
Qiu Jianlin | b3488d0 | 2023-12-07 00:12:12 | [diff] [blame] | 90 | local_params["profile-id"] = "1"; |
| 91 | local_params["tier-flag"] = "0"; |
| 92 | local_params["level-id"] = kLocallySupportedLevelId; |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 93 | CodecParameterMap remote_params; |
Qiu Jianlin | b3488d0 | 2023-12-07 00:12:12 | [diff] [blame] | 94 | remote_params["profile-id"] = "1"; |
| 95 | remote_params["tier-flag"] = "0"; |
| 96 | remote_params["level-id"] = kRemoteOfferedLevelId; |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 97 | CodecParameterMap answer_params; |
Qiu Jianlin | b3488d0 | 2023-12-07 00:12:12 | [diff] [blame] | 98 | H265GenerateProfileTierLevelForAnswer(local_params, remote_params, |
| 99 | &answer_params); |
| 100 | EXPECT_EQ(kLocallySupportedLevelId, answer_params["level-id"]); |
| 101 | } |
| 102 | #endif |
| 103 | |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 104 | TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 105 | CodecParameterMap params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 106 | absl::optional<int> empty = ParseSdpForVPxMaxFrameRate(params); |
| 107 | EXPECT_FALSE(empty); |
| 108 | params[kVPxFmtpMaxFrameRate] = "-1"; |
| 109 | EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); |
| 110 | params[kVPxFmtpMaxFrameRate] = "0"; |
| 111 | EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); |
| 112 | params[kVPxFmtpMaxFrameRate] = "abcde"; |
| 113 | EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); |
| 114 | } |
| 115 | |
| 116 | TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 117 | CodecParameterMap params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 118 | params[kVPxFmtpMaxFrameRate] = "30"; |
| 119 | EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30); |
| 120 | params[kVPxFmtpMaxFrameRate] = "60"; |
| 121 | EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 60); |
| 122 | } |
| 123 | |
| 124 | TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 125 | CodecParameterMap params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 126 | absl::optional<int> empty = ParseSdpForVPxMaxFrameSize(params); |
| 127 | EXPECT_FALSE(empty); |
| 128 | params[kVPxFmtpMaxFrameSize] = "-1"; |
| 129 | EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); |
| 130 | params[kVPxFmtpMaxFrameSize] = "0"; |
| 131 | EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); |
| 132 | params[kVPxFmtpMaxFrameSize] = "abcde"; |
| 133 | EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); |
| 134 | } |
| 135 | |
| 136 | TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsSpecified) { |
Philipp Hancke | de17252 | 2023-12-14 08:45:39 | [diff] [blame] | 137 | CodecParameterMap params; |
Johannes Kron | c3fcee7 | 2021-04-19 07:09:26 | [diff] [blame] | 138 | params[kVPxFmtpMaxFrameSize] = "8100"; // 1920 x 1080 / (16^2) |
| 139 | EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080); |
| 140 | params[kVPxFmtpMaxFrameSize] = "32400"; // 3840 x 2160 / (16^2) |
| 141 | EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 3840 * 2160); |
| 142 | } |
| 143 | |
| 144 | } // namespace webrtc |