blob: f4dcebb25a04fdbb5180cfd3985fc5c473ae4abb [file] [log] [blame]
Alfred E. Heggestadb330a792024-01-08 13:19:411/*
2 * Copyright (c) 2023 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 "api/video_codecs/h265_profile_tier_level.h"
12
13#include <string>
14
15#include "rtc_base/string_to_number.h"
16
17namespace webrtc {
18
19namespace {
20
21const char kH265FmtpProfile[] = "profile-id";
22const char kH265FmtpTier[] = "tier-flag";
23const char kH265FmtpLevel[] = "level-id";
24
25} // anonymous namespace
26
27// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.3.
28absl::optional<H265Profile> StringToH265Profile(const std::string& profile) {
29 absl::optional<int> i = rtc::StringToNumber<int>(profile);
30 if (!i.has_value()) {
31 return absl::nullopt;
32 }
33
34 switch (i.value()) {
35 case 1:
36 return H265Profile::kProfileMain;
37 case 2:
38 return H265Profile::kProfileMain10;
39 case 3:
40 return H265Profile::kProfileMainStill;
41 case 4:
42 return H265Profile::kProfileRangeExtensions;
43 case 5:
44 return H265Profile::kProfileHighThroughput;
45 case 6:
46 return H265Profile::kProfileMultiviewMain;
47 case 7:
48 return H265Profile::kProfileScalableMain;
49 case 8:
50 return H265Profile::kProfile3dMain;
51 case 9:
52 return H265Profile::kProfileScreenContentCoding;
53 case 10:
54 return H265Profile::kProfileScalableRangeExtensions;
55 case 11:
56 return H265Profile::kProfileHighThroughputScreenContentCoding;
57 default:
58 return absl::nullopt;
59 }
60}
61
62// Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.4,
63// tiers and levels.
64absl::optional<H265Tier> StringToH265Tier(const std::string& tier) {
65 absl::optional<int> i = rtc::StringToNumber<int>(tier);
66 if (!i.has_value()) {
67 return absl::nullopt;
68 }
69
70 switch (i.value()) {
71 case 0:
72 return H265Tier::kTier0;
73 case 1:
74 return H265Tier::kTier1;
75 default:
76 return absl::nullopt;
77 }
78}
79
80absl::optional<H265Level> StringToH265Level(const std::string& level) {
81 const absl::optional<int> i = rtc::StringToNumber<int>(level);
82 if (!i.has_value())
83 return absl::nullopt;
84
85 switch (i.value()) {
86 case 30:
87 return H265Level::kLevel1;
88 case 60:
89 return H265Level::kLevel2;
90 case 63:
91 return H265Level::kLevel2_1;
92 case 90:
93 return H265Level::kLevel3;
94 case 93:
95 return H265Level::kLevel3_1;
96 case 120:
97 return H265Level::kLevel4;
98 case 123:
99 return H265Level::kLevel4_1;
100 case 150:
101 return H265Level::kLevel5;
102 case 153:
103 return H265Level::kLevel5_1;
104 case 156:
105 return H265Level::kLevel5_2;
106 case 180:
107 return H265Level::kLevel6;
108 case 183:
109 return H265Level::kLevel6_1;
110 case 186:
111 return H265Level::kLevel6_2;
112 default:
113 return absl::nullopt;
114 }
115}
116
117std::string H265ProfileToString(H265Profile profile) {
118 switch (profile) {
119 case H265Profile::kProfileMain:
120 return "1";
121 case H265Profile::kProfileMain10:
122 return "2";
123 case H265Profile::kProfileMainStill:
124 return "3";
125 case H265Profile::kProfileRangeExtensions:
126 return "4";
127 case H265Profile::kProfileHighThroughput:
128 return "5";
129 case H265Profile::kProfileMultiviewMain:
130 return "6";
131 case H265Profile::kProfileScalableMain:
132 return "7";
133 case H265Profile::kProfile3dMain:
134 return "8";
135 case H265Profile::kProfileScreenContentCoding:
136 return "9";
137 case H265Profile::kProfileScalableRangeExtensions:
138 return "10";
139 case H265Profile::kProfileHighThroughputScreenContentCoding:
140 return "11";
141 }
142}
143
144std::string H265TierToString(H265Tier tier) {
145 switch (tier) {
146 case H265Tier::kTier0:
147 return "0";
148 case H265Tier::kTier1:
149 return "1";
150 }
151}
152
153std::string H265LevelToString(H265Level level) {
154 switch (level) {
155 case H265Level::kLevel1:
156 return "30";
157 case H265Level::kLevel2:
158 return "60";
159 case H265Level::kLevel2_1:
160 return "63";
161 case H265Level::kLevel3:
162 return "90";
163 case H265Level::kLevel3_1:
164 return "93";
165 case H265Level::kLevel4:
166 return "120";
167 case H265Level::kLevel4_1:
168 return "123";
169 case H265Level::kLevel5:
170 return "150";
171 case H265Level::kLevel5_1:
172 return "153";
173 case H265Level::kLevel5_2:
174 return "156";
175 case H265Level::kLevel6:
176 return "180";
177 case H265Level::kLevel6_1:
178 return "183";
179 case H265Level::kLevel6_2:
180 return "186";
181 }
182}
183
184absl::optional<H265ProfileTierLevel> ParseSdpForH265ProfileTierLevel(
185 const CodecParameterMap& params) {
186 static const H265ProfileTierLevel kDefaultProfileTierLevel(
187 H265Profile::kProfileMain, H265Tier::kTier0, H265Level::kLevel3_1);
188 bool profile_tier_level_specified = false;
189
190 absl::optional<H265Profile> profile;
191 const auto profile_it = params.find(kH265FmtpProfile);
192 if (profile_it != params.end()) {
193 profile_tier_level_specified = true;
194 const std::string& profile_str = profile_it->second;
195 profile = StringToH265Profile(profile_str);
196 if (!profile) {
197 return absl::nullopt;
198 }
199 } else {
200 profile = H265Profile::kProfileMain;
201 }
202 absl::optional<H265Tier> tier;
203 const auto tier_it = params.find(kH265FmtpTier);
204 if (tier_it != params.end()) {
205 profile_tier_level_specified = true;
206 const std::string& tier_str = tier_it->second;
207 tier = StringToH265Tier(tier_str);
208 if (!tier) {
209 return absl::nullopt;
210 }
211 } else {
212 tier = H265Tier::kTier0;
213 }
214 absl::optional<H265Level> level;
215 const auto level_it = params.find(kH265FmtpLevel);
216 if (level_it != params.end()) {
217 profile_tier_level_specified = true;
218 const std::string& level_str = level_it->second;
219 level = StringToH265Level(level_str);
220 if (!level) {
221 return absl::nullopt;
222 }
223 } else {
224 level = H265Level::kLevel3_1;
225 }
226
227 // Spec Table A.9, level 1 to level 3.1 does not allow high tiers.
228 if (level <= H265Level::kLevel3_1 && tier == H265Tier::kTier1) {
229 return absl::nullopt;
230 }
231
232 return !profile_tier_level_specified
233 ? kDefaultProfileTierLevel
234 : H265ProfileTierLevel(profile.value(), tier.value(),
235 level.value());
236}
237
238bool H265IsSameProfileTierLevel(const CodecParameterMap& params1,
239 const CodecParameterMap& params2) {
240 const absl::optional<H265ProfileTierLevel> ptl1 =
241 ParseSdpForH265ProfileTierLevel(params1);
242 const absl::optional<H265ProfileTierLevel> ptl2 =
243 ParseSdpForH265ProfileTierLevel(params2);
244 return ptl1 && ptl2 && ptl1->profile == ptl2->profile &&
245 ptl1->tier == ptl2->tier && ptl1->level == ptl2->level;
246}
247
248} // namespace webrtc