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 |
| 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" | |
| 18 | |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3 | 21 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3 |
| 20 // flag specifies if level 1b or level 1.1 is used. | 22 // flag specifies if level 1b or level 1.1 is used. |
| 21 const uint8_t kConstraintSet3Flag = 0x10; | 23 const uint8_t kConstraintSet3Flag = 0x10; |
| 22 | 24 |
| 23 // Convert a string of 8 characters into a byte where the positions containing | 25 // Convert a string of 8 characters into a byte where the positions containing |
| 24 // character c will have their bit set. For example, c = 'x', str = "x1xx0000" | 26 // character c will have their bit set. For example, c = 'x', str = "x1xx0000" |
| 25 // will return 0b10110000. constexpr is used so that the pattern table in | 27 // will return 0b10110000. constexpr is used so that the pattern table in |
| 26 // kProfilePatterns is statically initialized. | 28 // kProfilePatterns is statically initialized. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 constexpr ProfilePattern kProfilePatterns[] = { | 63 constexpr ProfilePattern kProfilePatterns[] = { |
| 62 {0x42, BitPattern("x1xx0000"), webrtc::H264::kProfileConstrainedBaseline}, | 64 {0x42, BitPattern("x1xx0000"), webrtc::H264::kProfileConstrainedBaseline}, |
| 63 {0x4D, BitPattern("1xxx0000"), webrtc::H264::kProfileConstrainedBaseline}, | 65 {0x4D, BitPattern("1xxx0000"), webrtc::H264::kProfileConstrainedBaseline}, |
| 64 {0x58, BitPattern("11xx0000"), webrtc::H264::kProfileConstrainedBaseline}, | 66 {0x58, BitPattern("11xx0000"), webrtc::H264::kProfileConstrainedBaseline}, |
| 65 {0x42, BitPattern("x0xx0000"), webrtc::H264::kProfileBaseline}, | 67 {0x42, BitPattern("x0xx0000"), webrtc::H264::kProfileBaseline}, |
| 66 {0x58, BitPattern("10xx0000"), webrtc::H264::kProfileBaseline}, | 68 {0x58, BitPattern("10xx0000"), webrtc::H264::kProfileBaseline}, |
| 67 {0x4D, BitPattern("0x0x0000"), webrtc::H264::kProfileMain}, | 69 {0x4D, BitPattern("0x0x0000"), webrtc::H264::kProfileMain}, |
| 68 {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh}, | 70 {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh}, |
| 69 {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}}; | 71 {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}}; |
| 70 | 72 |
| 73 struct LevelConstraint { | |
| 74 const int max_macroblocks_per_second; | |
| 75 const int max_macroblock_frame_size; | |
|
kthelgason
2016/11/02 17:26:21
super-nit: maybe use size_t for these unless there
magjed_webrtc
2016/11/03 12:16:51
This is a static table so we can statically verify
| |
| 76 const webrtc::H264::Level level; | |
| 77 }; | |
| 78 | |
| 79 // This is from the H264 spec. | |
| 80 static constexpr LevelConstraint kLevelConstraints[] = { | |
| 81 {1485, 99, webrtc::H264::kLevel1}, | |
| 82 {1485, 99, webrtc::H264::kLevel1_b}, | |
| 83 {3000, 396, webrtc::H264::kLevel1_1}, | |
| 84 {6000, 396, webrtc::H264::kLevel1_2}, | |
| 85 {11880, 396, webrtc::H264::kLevel1_3}, | |
| 86 {11880, 396, webrtc::H264::kLevel2}, | |
| 87 {19800, 792, webrtc::H264::kLevel2_1}, | |
| 88 {20250, 1620, webrtc::H264::kLevel2_2}, | |
| 89 {40500, 1620, webrtc::H264::kLevel3}, | |
| 90 {108000, 3600, webrtc::H264::kLevel3_1}, | |
| 91 {216000, 5120, webrtc::H264::kLevel3_2}, | |
| 92 {245760, 8192, webrtc::H264::kLevel4}, | |
| 93 {245760, 8192, webrtc::H264::kLevel4_1}, | |
| 94 {522240, 8704, webrtc::H264::kLevel4_2}, | |
| 95 {589824, 22080, webrtc::H264::kLevel5}, | |
| 96 {983040, 3684, webrtc::H264::kLevel5_1}, | |
| 97 {2073600, 3684, webrtc::H264::kLevel5_2}, | |
| 98 }; | |
| 99 | |
| 71 } // anonymous namespace | 100 } // anonymous namespace |
| 72 | 101 |
| 73 namespace webrtc { | 102 namespace webrtc { |
| 74 namespace H264 { | 103 namespace H264 { |
| 75 | 104 |
| 76 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { | 105 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { |
| 77 // The string should consist of 3 bytes in hexadecimal format. | 106 // The string should consist of 3 bytes in hexadecimal format. |
| 78 if (strlen(str) != 6u) | 107 if (strlen(str) != 6u) |
| 79 return rtc::Optional<ProfileLevelId>(); | 108 return rtc::Optional<ProfileLevelId>(); |
| 80 const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16); | 109 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 && | 151 if (profile_idc == pattern.profile_idc && |
| 123 pattern.profile_iop.IsMatch(profile_iop)) { | 152 pattern.profile_iop.IsMatch(profile_iop)) { |
| 124 return rtc::Optional<ProfileLevelId>({pattern.profile, level}); | 153 return rtc::Optional<ProfileLevelId>({pattern.profile, level}); |
| 125 } | 154 } |
| 126 } | 155 } |
| 127 | 156 |
| 128 // Unrecognized profile_idc/profile_iop combination. | 157 // Unrecognized profile_idc/profile_iop combination. |
| 129 return rtc::Optional<ProfileLevelId>(); | 158 return rtc::Optional<ProfileLevelId>(); |
| 130 } | 159 } |
| 131 | 160 |
| 161 Level SupportedLevel(int max_frame_pixel_count, int max_fps) { | |
| 162 static const int kPixelsPerMacroblock = 16 * 16; | |
| 163 | |
| 164 for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) { | |
| 165 const LevelConstraint& level_constraint = kLevelConstraints[i]; | |
| 166 if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <= | |
| 167 max_frame_pixel_count && | |
| 168 level_constraint.max_macroblocks_per_second <= | |
| 169 max_fps * level_constraint.max_macroblock_frame_size) { | |
| 170 return level_constraint.level; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 // Return lowest possible level. | |
| 175 return kLevel1; | |
|
kthelgason
2016/11/02 17:26:21
Is this really the correct thing to do in this sit
magjed_webrtc
2016/11/03 12:16:51
No, it's not strictly correct. I could do NOT_REAC
| |
| 176 } | |
| 177 | |
| 132 std::string ProfileLevelIdToString(const ProfileLevelId& profile_level_id) { | 178 std::string ProfileLevelIdToString(const ProfileLevelId& profile_level_id) { |
| 133 // Handle special case level == 1b. | 179 // Handle special case level == 1b. |
| 134 if (profile_level_id.level == kLevel1_b) { | 180 if (profile_level_id.level == kLevel1_b) { |
| 135 switch (profile_level_id.profile) { | 181 switch (profile_level_id.profile) { |
| 136 case kProfileConstrainedBaseline: | 182 case kProfileConstrainedBaseline: |
| 137 return "42f00b"; | 183 return "42f00b"; |
| 138 case kProfileBaseline: | 184 case kProfileBaseline: |
| 139 return "42100b"; | 185 return "42100b"; |
| 140 case kProfileMain: | 186 case kProfileMain: |
| 141 return "4D100b"; | 187 return "4D100b"; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 167 return std::string(); | 213 return std::string(); |
| 168 } | 214 } |
| 169 | 215 |
| 170 char str[7]; | 216 char str[7]; |
| 171 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level); | 217 snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level); |
| 172 return str; | 218 return str; |
| 173 } | 219 } |
| 174 | 220 |
| 175 } // namespace H264 | 221 } // namespace H264 |
| 176 } // namespace webrtc | 222 } // namespace webrtc |
| OLD | NEW |