Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |