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

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

Issue 2481033003: Add helper functions for negotiating H264 profile level id (Closed)
Patch Set: Add more comments. Remove DecideSendProfileLevelId. Created 4 years, 1 month 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
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/common_video/h264/profile_level_id.h" 11 #include "webrtc/common_video/h264/profile_level_id.h"
12 12
13 #include <cstdio> 13 #include <cstdio>
14 #include <cstdlib> 14 #include <cstdlib>
15 #include <cstring> 15 #include <cstring>
16 16
17 #include "webrtc/base/arraysize.h" 17 #include "webrtc/base/arraysize.h"
18 18
19 namespace webrtc {
20 namespace H264 {
21
19 namespace { 22 namespace {
20 23
24 const char kProfileLevelId[] = "profile-level-id";
25 const char kLevelAsymmetryAllowed[] = "level-asymmetry-allowed";
26
21 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3 27 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
22 // flag specifies if level 1b or level 1.1 is used. 28 // flag specifies if level 1b or level 1.1 is used.
23 const uint8_t kConstraintSet3Flag = 0x10; 29 const uint8_t kConstraintSet3Flag = 0x10;
24 30
25 // Convert a string of 8 characters into a byte where the positions containing 31 // Convert a string of 8 characters into a byte where the positions containing
26 // character c will have their bit set. For example, c = 'x', str = "x1xx0000" 32 // character c will have their bit set. For example, c = 'x', str = "x1xx0000"
27 // will return 0b10110000. constexpr is used so that the pattern table in 33 // will return 0b10110000. constexpr is used so that the pattern table in
28 // kProfilePatterns is statically initialized. 34 // kProfilePatterns is statically initialized.
29 constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) { 35 constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
30 return (str[0] == c) << 7 36 return (str[0] == c) << 7
(...skipping 18 matching lines...) Expand all
49 55
50 private: 56 private:
51 const uint8_t mask_; 57 const uint8_t mask_;
52 const uint8_t masked_value_; 58 const uint8_t masked_value_;
53 }; 59 };
54 60
55 // Table for converting between profile_idc/profile_iop to H264::Profile. 61 // Table for converting between profile_idc/profile_iop to H264::Profile.
56 struct ProfilePattern { 62 struct ProfilePattern {
57 const uint8_t profile_idc; 63 const uint8_t profile_idc;
58 const BitPattern profile_iop; 64 const BitPattern profile_iop;
59 const webrtc::H264::Profile profile; 65 const Profile profile;
60 }; 66 };
61 67
62 // This is from https://tools.ietf.org/html/rfc6184#section-8.1. 68 // This is from https://tools.ietf.org/html/rfc6184#section-8.1.
63 constexpr ProfilePattern kProfilePatterns[] = { 69 constexpr ProfilePattern kProfilePatterns[] = {
64 {0x42, BitPattern("x1xx0000"), webrtc::H264::kProfileConstrainedBaseline}, 70 {0x42, BitPattern("x1xx0000"), kProfileConstrainedBaseline},
65 {0x4D, BitPattern("1xxx0000"), webrtc::H264::kProfileConstrainedBaseline}, 71 {0x4D, BitPattern("1xxx0000"), kProfileConstrainedBaseline},
66 {0x58, BitPattern("11xx0000"), webrtc::H264::kProfileConstrainedBaseline}, 72 {0x58, BitPattern("11xx0000"), kProfileConstrainedBaseline},
67 {0x42, BitPattern("x0xx0000"), webrtc::H264::kProfileBaseline}, 73 {0x42, BitPattern("x0xx0000"), kProfileBaseline},
68 {0x58, BitPattern("10xx0000"), webrtc::H264::kProfileBaseline}, 74 {0x58, BitPattern("10xx0000"), kProfileBaseline},
69 {0x4D, BitPattern("0x0x0000"), webrtc::H264::kProfileMain}, 75 {0x4D, BitPattern("0x0x0000"), kProfileMain},
70 {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh}, 76 {0x64, BitPattern("00000000"), kProfileHigh},
71 {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}}; 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 }
72 96
73 struct LevelConstraint { 97 struct LevelConstraint {
74 const int max_macroblocks_per_second; 98 const int max_macroblocks_per_second;
75 const int max_macroblock_frame_size; 99 const int max_macroblock_frame_size;
76 const webrtc::H264::Level level; 100 const webrtc::H264::Level level;
77 }; 101 };
78 102
79 // This is from ITU-T H.264 (02/2016) Table A-1 – Level limits. 103 // This is from ITU-T H.264 (02/2016) Table A-1 – Level limits.
80 static constexpr LevelConstraint kLevelConstraints[] = { 104 static constexpr LevelConstraint kLevelConstraints[] = {
81 {1485, 99, webrtc::H264::kLevel1}, 105 {1485, 99, webrtc::H264::kLevel1},
(...skipping 10 matching lines...) Expand all
92 {245760, 8192, webrtc::H264::kLevel4}, 116 {245760, 8192, webrtc::H264::kLevel4},
93 {245760, 8192, webrtc::H264::kLevel4_1}, 117 {245760, 8192, webrtc::H264::kLevel4_1},
94 {522240, 8704, webrtc::H264::kLevel4_2}, 118 {522240, 8704, webrtc::H264::kLevel4_2},
95 {589824, 22080, webrtc::H264::kLevel5}, 119 {589824, 22080, webrtc::H264::kLevel5},
96 {983040, 3684, webrtc::H264::kLevel5_1}, 120 {983040, 3684, webrtc::H264::kLevel5_1},
97 {2073600, 3684, webrtc::H264::kLevel5_2}, 121 {2073600, 3684, webrtc::H264::kLevel5_2},
98 }; 122 };
99 123
100 } // anonymous namespace 124 } // anonymous namespace
101 125
102 namespace webrtc {
103 namespace H264 {
104
105 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { 126 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
106 // The string should consist of 3 bytes in hexadecimal format. 127 // The string should consist of 3 bytes in hexadecimal format.
107 if (strlen(str) != 6u) 128 if (strlen(str) != 6u)
108 return rtc::Optional<ProfileLevelId>(); 129 return rtc::Optional<ProfileLevelId>();
109 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16); 130 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
110 if (profile_level_id_numeric == 0) 131 if (profile_level_id_numeric == 0)
111 return rtc::Optional<ProfileLevelId>(); 132 return rtc::Optional<ProfileLevelId>();
112 133
113 // Separate into three bytes. 134 // Separate into three bytes.
114 const uint8_t level_idc = 135 const uint8_t level_idc =
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 level_constraint.max_macroblocks_per_second <= 189 level_constraint.max_macroblocks_per_second <=
169 max_fps * level_constraint.max_macroblock_frame_size) { 190 max_fps * level_constraint.max_macroblock_frame_size) {
170 return rtc::Optional<Level>(level_constraint.level); 191 return rtc::Optional<Level>(level_constraint.level);
171 } 192 }
172 } 193 }
173 194
174 // No level supported. 195 // No level supported.
175 return rtc::Optional<Level>(); 196 return rtc::Optional<Level>();
176 } 197 }
177 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
178 rtc::Optional<std::string> ProfileLevelIdToString( 217 rtc::Optional<std::string> ProfileLevelIdToString(
179 const ProfileLevelId& profile_level_id) { 218 const ProfileLevelId& profile_level_id) {
180 // Handle special case level == 1b. 219 // Handle special case level == 1b.
181 if (profile_level_id.level == kLevel1_b) { 220 if (profile_level_id.level == kLevel1_b) {
182 switch (profile_level_id.profile) { 221 switch (profile_level_id.profile) {
183 case kProfileConstrainedBaseline: 222 case kProfileConstrainedBaseline:
184 return rtc::Optional<std::string>("42f00b"); 223 return rtc::Optional<std::string>("42f00b");
185 case kProfileBaseline: 224 case kProfileBaseline:
186 return rtc::Optional<std::string>("42100b"); 225 return rtc::Optional<std::string>("42100b");
187 case kProfileMain: 226 case kProfileMain:
(...skipping 24 matching lines...) Expand all
212 // Unrecognized profile. 251 // Unrecognized profile.
213 default: 252 default:
214 return rtc::Optional<std::string>(); 253 return rtc::Optional<std::string>();
215 } 254 }
216 255
217 char str[7]; 256 char str[7];
218 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level); 257 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
219 return rtc::Optional<std::string>(str); 258 return rtc::Optional<std::string>(str);
220 } 259 }
221 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 // Parse profile-level-ids.
267 const rtc::Optional<ProfileLevelId> local_profile_level_id =
268 ParseSdpProfileLevelId(local_supported_params);
269 const rtc::Optional<ProfileLevelId> remote_profile_level_id =
270 ParseSdpProfileLevelId(remote_offered_params);
271 // The local and remote codec must have valid and equal H264 Profiles.
272 RTC_DCHECK(local_profile_level_id);
273 RTC_DCHECK(remote_profile_level_id);
274 RTC_DCHECK_EQ(local_profile_level_id->profile,
275 remote_profile_level_id->profile);
276
277 // Parse level information.
278 const bool level_asymmetry_allowed =
279 IsLevelAsymmetryAllowed(local_supported_params) &&
280 IsLevelAsymmetryAllowed(remote_offered_params);
281 const Level local_level = local_profile_level_id->level;
282 const Level remote_level = remote_profile_level_id->level;
283 const Level min_level = Min(local_level, remote_level);
284
285 // Determine answer level. When level asymmetry is not allowed, level upgrade
286 // is not allowed, i.e., the level in the answer must be equal to or lower
287 // than the level in the offer.
288 const Level answer_level = level_asymmetry_allowed ? local_level : min_level;
289
290 // Set the resulting profile-level-id in the answer parameters.
291 (*answer_params)[kProfileLevelId] = *ProfileLevelIdToString(
292 ProfileLevelId(local_profile_level_id->profile, answer_level));
293 }
294
222 } // namespace H264 295 } // namespace H264
223 } // namespace webrtc 296 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/common_video/h264/profile_level_id.h ('k') | webrtc/common_video/h264/profile_level_id_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698