Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: webrtc/common_video/h264/profile_level_id.cc

Issue 2854123003: Build WebRTC with data channel only. (Closed)
Patch Set: Rebase. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/common_video/h264/profile_level_id.h ('k') | webrtc/logging/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 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 "webrtc/common_video/h264/profile_level_id.h"
12
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cstring>
16
17 #include "webrtc/base/arraysize.h"
18
19 namespace webrtc {
20 namespace H264 {
21
22 namespace {
23
24 const char kProfileLevelId[] = "profile-level-id";
25 const char kLevelAsymmetryAllowed[] = "level-asymmetry-allowed";
26
27 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
28 // flag specifies if level 1b or level 1.1 is used.
29 const uint8_t kConstraintSet3Flag = 0x10;
30
31 // Convert a string of 8 characters into a byte where the positions containing
32 // character c will have their bit set. For example, c = 'x', str = "x1xx0000"
33 // will return 0b10110000. constexpr is used so that the pattern table in
34 // kProfilePatterns is statically initialized.
35 constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
36 return (str[0] == c) << 7
37 | (str[1] == c) << 6
38 | (str[2] == c) << 5
39 | (str[3] == c) << 4
40 | (str[4] == c) << 3
41 | (str[5] == c) << 2
42 | (str[6] == c) << 1
43 | (str[7] == c) << 0;
44 }
45
46 // Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
47 // either 0 or 1.
48 class BitPattern {
49 public:
50 explicit constexpr BitPattern(const char (&str)[9])
51 : mask_(~ByteMaskString('x', str)),
52 masked_value_(ByteMaskString('1', str)) {}
53
54 bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
55
56 private:
57 const uint8_t mask_;
58 const uint8_t masked_value_;
59 };
60
61 // Table for converting between profile_idc/profile_iop to H264::Profile.
62 struct ProfilePattern {
63 const uint8_t profile_idc;
64 const BitPattern profile_iop;
65 const Profile profile;
66 };
67
68 // This is from https://tools.ietf.org/html/rfc6184#section-8.1.
69 constexpr ProfilePattern kProfilePatterns[] = {
70 {0x42, BitPattern("x1xx0000"), kProfileConstrainedBaseline},
71 {0x4D, BitPattern("1xxx0000"), kProfileConstrainedBaseline},
72 {0x58, BitPattern("11xx0000"), kProfileConstrainedBaseline},
73 {0x42, BitPattern("x0xx0000"), kProfileBaseline},
74 {0x58, BitPattern("10xx0000"), kProfileBaseline},
75 {0x4D, BitPattern("0x0x0000"), kProfileMain},
76 {0x64, BitPattern("00000000"), kProfileHigh},
77 {0x64, BitPattern("00001100"), kProfileConstrainedHigh}};
78
79 // Compare H264 levels and handle the level 1b case.
80 bool IsLess(Level a, Level b) {
81 if (a == kLevel1_b)
82 return b != kLevel1 && b != kLevel1_b;
83 if (b == kLevel1_b)
84 return a == kLevel1;
85 return a < b;
86 }
87
88 Level Min(Level a, Level b) {
89 return IsLess(a, b) ? a : b;
90 }
91
92 bool IsLevelAsymmetryAllowed(const CodecParameterMap& params) {
93 const auto it = params.find(kLevelAsymmetryAllowed);
94 return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
95 }
96
97 struct LevelConstraint {
98 const int max_macroblocks_per_second;
99 const int max_macroblock_frame_size;
100 const webrtc::H264::Level level;
101 };
102
103 // This is from ITU-T H.264 (02/2016) Table A-1 – Level limits.
104 static constexpr LevelConstraint kLevelConstraints[] = {
105 {1485, 99, webrtc::H264::kLevel1},
106 {1485, 99, webrtc::H264::kLevel1_b},
107 {3000, 396, webrtc::H264::kLevel1_1},
108 {6000, 396, webrtc::H264::kLevel1_2},
109 {11880, 396, webrtc::H264::kLevel1_3},
110 {11880, 396, webrtc::H264::kLevel2},
111 {19800, 792, webrtc::H264::kLevel2_1},
112 {20250, 1620, webrtc::H264::kLevel2_2},
113 {40500, 1620, webrtc::H264::kLevel3},
114 {108000, 3600, webrtc::H264::kLevel3_1},
115 {216000, 5120, webrtc::H264::kLevel3_2},
116 {245760, 8192, webrtc::H264::kLevel4},
117 {245760, 8192, webrtc::H264::kLevel4_1},
118 {522240, 8704, webrtc::H264::kLevel4_2},
119 {589824, 22080, webrtc::H264::kLevel5},
120 {983040, 3684, webrtc::H264::kLevel5_1},
121 {2073600, 3684, webrtc::H264::kLevel5_2},
122 };
123
124 } // anonymous namespace
125
126 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
127 // The string should consist of 3 bytes in hexadecimal format.
128 if (strlen(str) != 6u)
129 return rtc::Optional<ProfileLevelId>();
130 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
131 if (profile_level_id_numeric == 0)
132 return rtc::Optional<ProfileLevelId>();
133
134 // Separate into three bytes.
135 const uint8_t level_idc =
136 static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
137 const uint8_t profile_iop =
138 static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
139 const uint8_t profile_idc =
140 static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
141
142 // Parse level based on level_idc and constraint set 3 flag.
143 Level level;
144 switch (level_idc) {
145 case kLevel1_1:
146 level = (profile_iop & kConstraintSet3Flag) != 0 ? kLevel1_b : kLevel1_1;
147 break;
148 case kLevel1:
149 case kLevel1_2:
150 case kLevel1_3:
151 case kLevel2:
152 case kLevel2_1:
153 case kLevel2_2:
154 case kLevel3:
155 case kLevel3_1:
156 case kLevel3_2:
157 case kLevel4:
158 case kLevel4_1:
159 case kLevel4_2:
160 case kLevel5:
161 case kLevel5_1:
162 case kLevel5_2:
163 level = static_cast<Level>(level_idc);
164 break;
165 default:
166 // Unrecognized level_idc.
167 return rtc::Optional<ProfileLevelId>();
168 }
169
170 // Parse profile_idc/profile_iop into a Profile enum.
171 for (const ProfilePattern& pattern : kProfilePatterns) {
172 if (profile_idc == pattern.profile_idc &&
173 pattern.profile_iop.IsMatch(profile_iop)) {
174 return rtc::Optional<ProfileLevelId>({pattern.profile, level});
175 }
176 }
177
178 // Unrecognized profile_idc/profile_iop combination.
179 return rtc::Optional<ProfileLevelId>();
180 }
181
182 rtc::Optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
183 static const int kPixelsPerMacroblock = 16 * 16;
184
185 for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
186 const LevelConstraint& level_constraint = kLevelConstraints[i];
187 if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
188 max_frame_pixel_count &&
189 level_constraint.max_macroblocks_per_second <=
190 max_fps * level_constraint.max_macroblock_frame_size) {
191 return rtc::Optional<Level>(level_constraint.level);
192 }
193 }
194
195 // No level supported.
196 return rtc::Optional<Level>();
197 }
198
199 rtc::Optional<ProfileLevelId> ParseSdpProfileLevelId(
200 const CodecParameterMap& params) {
201 // TODO(magjed): The default should really be kProfileBaseline and kLevel1
202 // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
203 // order to not break backwards compatibility with older versions of WebRTC
204 // where external codecs don't have any parameters, use
205 // kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
206 // done in an interim period to allow external clients to update their code.
207 // http://crbug/webrtc/6337.
208 static const ProfileLevelId kDefaultProfileLevelId(
209 kProfileConstrainedBaseline, kLevel3_1);
210
211 const auto profile_level_id_it = params.find(kProfileLevelId);
212 return (profile_level_id_it == params.end())
213 ? rtc::Optional<ProfileLevelId>(kDefaultProfileLevelId)
214 : ParseProfileLevelId(profile_level_id_it->second.c_str());
215 }
216
217 rtc::Optional<std::string> ProfileLevelIdToString(
218 const ProfileLevelId& profile_level_id) {
219 // Handle special case level == 1b.
220 if (profile_level_id.level == kLevel1_b) {
221 switch (profile_level_id.profile) {
222 case kProfileConstrainedBaseline:
223 return rtc::Optional<std::string>("42f00b");
224 case kProfileBaseline:
225 return rtc::Optional<std::string>("42100b");
226 case kProfileMain:
227 return rtc::Optional<std::string>("4d100b");
228 // Level 1b is not allowed for other profiles.
229 default:
230 return rtc::Optional<std::string>();
231 }
232 }
233
234 const char* profile_idc_iop_string;
235 switch (profile_level_id.profile) {
236 case kProfileConstrainedBaseline:
237 profile_idc_iop_string = "42e0";
238 break;
239 case kProfileBaseline:
240 profile_idc_iop_string = "4200";
241 break;
242 case kProfileMain:
243 profile_idc_iop_string = "4d00";
244 break;
245 case kProfileConstrainedHigh:
246 profile_idc_iop_string = "640c";
247 break;
248 case kProfileHigh:
249 profile_idc_iop_string = "6400";
250 break;
251 // Unrecognized profile.
252 default:
253 return rtc::Optional<std::string>();
254 }
255
256 char str[7];
257 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
258 return rtc::Optional<std::string>(str);
259 }
260
261 // Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
262 void GenerateProfileLevelIdForAnswer(
263 const CodecParameterMap& local_supported_params,
264 const CodecParameterMap& remote_offered_params,
265 CodecParameterMap* answer_params) {
266 // If both local and remote haven't set profile-level-id, they are both using
267 // the default profile. In this case, don't set profile-level-id in answer
268 // either.
269 if (!local_supported_params.count(kProfileLevelId) &&
270 !remote_offered_params.count(kProfileLevelId)) {
271 return;
272 }
273
274 // Parse profile-level-ids.
275 const rtc::Optional<ProfileLevelId> local_profile_level_id =
276 ParseSdpProfileLevelId(local_supported_params);
277 const rtc::Optional<ProfileLevelId> remote_profile_level_id =
278 ParseSdpProfileLevelId(remote_offered_params);
279 // The local and remote codec must have valid and equal H264 Profiles.
280 RTC_DCHECK(local_profile_level_id);
281 RTC_DCHECK(remote_profile_level_id);
282 RTC_DCHECK_EQ(local_profile_level_id->profile,
283 remote_profile_level_id->profile);
284
285 // Parse level information.
286 const bool level_asymmetry_allowed =
287 IsLevelAsymmetryAllowed(local_supported_params) &&
288 IsLevelAsymmetryAllowed(remote_offered_params);
289 const Level local_level = local_profile_level_id->level;
290 const Level remote_level = remote_profile_level_id->level;
291 const Level min_level = Min(local_level, remote_level);
292
293 // Determine answer level. When level asymmetry is not allowed, level upgrade
294 // is not allowed, i.e., the level in the answer must be equal to or lower
295 // than the level in the offer.
296 const Level answer_level = level_asymmetry_allowed ? local_level : min_level;
297
298 // Set the resulting profile-level-id in the answer parameters.
299 (*answer_params)[kProfileLevelId] = *ProfileLevelIdToString(
300 ProfileLevelId(local_profile_level_id->profile, answer_level));
301 }
302
303 } // namespace H264
304 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/common_video/h264/profile_level_id.h ('k') | webrtc/logging/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698