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

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: 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
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 constexpr ProfilePattern kProfilePatterns[] = { 61 constexpr ProfilePattern kProfilePatterns[] = {
62 {0x42, BitPattern("x1xx0000"), webrtc::H264::kProfileConstrainedBaseline}, 62 {0x42, BitPattern("x1xx0000"), webrtc::H264::kProfileConstrainedBaseline},
63 {0x4D, BitPattern("1xxx0000"), webrtc::H264::kProfileConstrainedBaseline}, 63 {0x4D, BitPattern("1xxx0000"), webrtc::H264::kProfileConstrainedBaseline},
64 {0x58, BitPattern("11xx0000"), webrtc::H264::kProfileConstrainedBaseline}, 64 {0x58, BitPattern("11xx0000"), webrtc::H264::kProfileConstrainedBaseline},
65 {0x42, BitPattern("x0xx0000"), webrtc::H264::kProfileBaseline}, 65 {0x42, BitPattern("x0xx0000"), webrtc::H264::kProfileBaseline},
66 {0x58, BitPattern("10xx0000"), webrtc::H264::kProfileBaseline}, 66 {0x58, BitPattern("10xx0000"), webrtc::H264::kProfileBaseline},
67 {0x4D, BitPattern("0x0x0000"), webrtc::H264::kProfileMain}, 67 {0x4D, BitPattern("0x0x0000"), webrtc::H264::kProfileMain},
68 {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh}, 68 {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh},
69 {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}}; 69 {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}};
70 70
71 // Compare H264 levels and handle the level 1b case.
72 bool IsLess(webrtc::H264::Level a, webrtc::H264::Level b) {
73 if (a == webrtc::H264::kLevel1_b)
74 return b != webrtc::H264::kLevel1 && b != webrtc::H264::kLevel1_b;
75 if (b == webrtc::H264::kLevel1_b)
76 return a == webrtc::H264::kLevel1;
77 return a < b;
78 }
79
80 bool IsLevelAsymmetryAllowed(const webrtc::H264::CodecParameterMap& params) {
81 const auto it = params.find("level-asymmetry-allowed");
82 return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
83 }
84
71 } // anonymous namespace 85 } // anonymous namespace
72 86
73 namespace webrtc { 87 namespace webrtc {
74 namespace H264 { 88 namespace H264 {
75 89
76 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { 90 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
77 // The string should consist of 3 bytes in hexadecimal format. 91 // The string should consist of 3 bytes in hexadecimal format.
78 if (strlen(str) != 6u) 92 if (strlen(str) != 6u)
79 return rtc::Optional<ProfileLevelId>(); 93 return rtc::Optional<ProfileLevelId>();
80 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16); 94 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 if (profile_idc == pattern.profile_idc && 136 if (profile_idc == pattern.profile_idc &&
123 pattern.profile_iop.IsMatch(profile_iop)) { 137 pattern.profile_iop.IsMatch(profile_iop)) {
124 return rtc::Optional<ProfileLevelId>({pattern.profile, level}); 138 return rtc::Optional<ProfileLevelId>({pattern.profile, level});
125 } 139 }
126 } 140 }
127 141
128 // Unrecognized profile_idc/profile_iop combination. 142 // Unrecognized profile_idc/profile_iop combination.
129 return rtc::Optional<ProfileLevelId>(); 143 return rtc::Optional<ProfileLevelId>();
130 } 144 }
131 145
146 rtc::Optional<ProfileLevelId> ParseSdpProfileLevelId(
147 const CodecParameterMap& params) {
148 // TODO(magjed): The default should really be kProfileBaseline and kLevel1
149 // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
150 // order to not break backwards compatibility with older versions of WebRTC
151 // where external codecs don't have any parameters, use
152 // kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
153 // done in an interim period to allow external clients to update their code.
154 // http://crbug/webrtc/6337.
155 static const ProfileLevelId kDefaultProfileLevelId(
156 kProfileConstrainedBaseline, kLevel3_1);
157
158 const auto profile_level_id_it = params.find("profile-level-id");
159 return (profile_level_id_it == params.end())
160 ? rtc::Optional<ProfileLevelId>(kDefaultProfileLevelId)
161 : ParseProfileLevelId(profile_level_id_it->second.c_str());
kthelgason 2016/11/08 09:27:24 nit: IMO this is a little too much code for a tern
magjed_webrtc 2016/11/08 15:48:40 Acknowledged, but I think this is fine.
162 }
163
132 rtc::Optional<std::string> ProfileLevelIdToString( 164 rtc::Optional<std::string> ProfileLevelIdToString(
133 const ProfileLevelId& profile_level_id) { 165 const ProfileLevelId& profile_level_id) {
134 // Handle special case level == 1b. 166 // Handle special case level == 1b.
135 if (profile_level_id.level == kLevel1_b) { 167 if (profile_level_id.level == kLevel1_b) {
136 switch (profile_level_id.profile) { 168 switch (profile_level_id.profile) {
137 case kProfileConstrainedBaseline: 169 case kProfileConstrainedBaseline:
138 return rtc::Optional<std::string>("42f00b"); 170 return rtc::Optional<std::string>("42f00b");
139 case kProfileBaseline: 171 case kProfileBaseline:
140 return rtc::Optional<std::string>("42100b"); 172 return rtc::Optional<std::string>("42100b");
141 case kProfileMain: 173 case kProfileMain:
(...skipping 24 matching lines...) Expand all
166 // Unrecognized profile. 198 // Unrecognized profile.
167 default: 199 default:
168 return rtc::Optional<std::string>(); 200 return rtc::Optional<std::string>();
169 } 201 }
170 202
171 char str[7]; 203 char str[7];
172 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level); 204 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
173 return rtc::Optional<std::string>(str); 205 return rtc::Optional<std::string>(str);
174 } 206 }
175 207
208 rtc::Optional<ProfileLevelId> NegotiateProfileLevelId(
hta-webrtc 2016/11/08 09:39:06 The name of this function is misleading - it doesn
magjed_webrtc 2016/11/08 15:48:39 What I'm trying to implement here is the negotiati
209 const CodecParameterMap& local_params,
210 const CodecParameterMap& remote_params) {
211 const rtc::Optional<ProfileLevelId> local_profile_level_id =
212 ParseSdpProfileLevelId(local_params);
213 const rtc::Optional<ProfileLevelId> remote_profile_level_id =
214 ParseSdpProfileLevelId(remote_params);
215 // Check that local and remote have the same H264 Profile.
216 if (!local_profile_level_id || !remote_profile_level_id ||
217 local_profile_level_id->profile != remote_profile_level_id->profile) {
218 return rtc::Optional<ProfileLevelId>();
kthelgason 2016/11/08 09:27:24 Can't you just choose the lower of the two profile
magjed_webrtc 2016/11/08 15:48:39 This is unfortunately not allowed according to the
219 }
220
221 // Parse level-asymmetry-allowed.
222 const bool level_asymmetry_allowed = IsLevelAsymmetryAllowed(local_params) &&
223 IsLevelAsymmetryAllowed(remote_params);
224 // Abort if local codec can't cope with the remote H264 level.
225 if (!level_asymmetry_allowed &&
226 IsLess(local_profile_level_id->level, remote_profile_level_id->level)) {
227 return rtc::Optional<ProfileLevelId>();
hta-webrtc 2016/11/08 09:39:06 In the case where we end up here, the local profil
magjed_webrtc 2016/11/08 15:48:40 I see, I misunderstood what level-asymmetry-allowe
228 }
229
230 const Level level = level_asymmetry_allowed ? local_profile_level_id->level
231 : remote_profile_level_id->level;
232 return rtc::Optional<ProfileLevelId>(
233 ProfileLevelId(local_profile_level_id->profile, level));
234 }
235
176 } // namespace H264 236 } // namespace H264
177 } // namespace webrtc 237 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698