| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "libavutil/common.h" | ||
| 20 | #include "libavcodec/h265_profile_level.h" | ||
| 21 | |||
| 22 | static const struct { | ||
| 23 | int width; | ||
| 24 | int height; | ||
| 25 | int level_idc; | ||
| 26 | } test_sizes[] = { | ||
| 27 | // First level usable at standard sizes, from H.265 table A.9. | ||
| 28 | { 176, 144, 30 }, // QCIF | ||
| 29 | { 352, 288, 60 }, // CIF | ||
| 30 | { 640, 480, 90 }, // VGA | ||
| 31 | { 720, 480, 90 }, // NTSC | ||
| 32 | { 720, 576, 90 }, // PAL | ||
| 33 | { 1024, 768, 93 }, // XGA | ||
| 34 | { 1280, 720, 93 }, // 720p | ||
| 35 | { 1280, 1024, 120 }, // SXGA | ||
| 36 | { 1920, 1080, 120 }, // 1080p | ||
| 37 | { 2048, 1080, 120 }, // 2Kx1080 | ||
| 38 | { 2048, 1536, 150 }, // 4XGA | ||
| 39 | { 3840, 2160, 150 }, // 4K | ||
| 40 | { 7680, 4320, 180 }, // 8K | ||
| 41 | |||
| 42 | // Overly wide or tall sizes. | ||
| 43 | { 1, 512, 30 }, | ||
| 44 | { 1, 1024, 63 }, | ||
| 45 | { 1, 2048, 90 }, | ||
| 46 | { 1, 4096, 120 }, | ||
| 47 | { 1, 8192, 150 }, | ||
| 48 | { 1, 16384, 180 }, | ||
| 49 | { 1, 32768, 0 }, | ||
| 50 | { 512, 1, 30 }, | ||
| 51 | { 1024, 1, 63 }, | ||
| 52 | { 2048, 1, 90 }, | ||
| 53 | { 4096, 1, 120 }, | ||
| 54 | { 8192, 1, 150 }, | ||
| 55 | { 16384, 1, 180 }, | ||
| 56 | { 32768, 1, 0 }, | ||
| 57 | { 2800, 256, 93 }, | ||
| 58 | { 2816, 128, 120 }, | ||
| 59 | { 256, 4208, 120 }, | ||
| 60 | { 128, 4224, 150 }, | ||
| 61 | { 8432, 256, 150 }, | ||
| 62 | { 8448, 128, 180 }, | ||
| 63 | { 256, 16880, 180 }, | ||
| 64 | { 128, 16896, 0 }, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static const struct { | ||
| 68 | int width; | ||
| 69 | int height; | ||
| 70 | int dpb_size; | ||
| 71 | int level_idc; | ||
| 72 | } test_dpb[] = { | ||
| 73 | // First level usable for some DPB sizes. | ||
| 74 | |||
| 75 | // L1: 176 * 144 = 25344 <= 36864 * 3/4 = 27648 | ||
| 76 | // L2: <= 122880 * 1/4 = 30720 | ||
| 77 | { 176, 144, 8, 30 }, | ||
| 78 | { 176, 144, 9, 60 }, | ||
| 79 | |||
| 80 | // L2: 352 * 288 = 101376 <= 122880 | ||
| 81 | // L2.1: <= 245760 * 1/2 = 122880 | ||
| 82 | // L3: <= 552960 * 1/4 = 138240 | ||
| 83 | { 352, 288, 6, 60 }, | ||
| 84 | { 352, 288, 7, 63 }, | ||
| 85 | { 352, 288, 13, 90 }, | ||
| 86 | |||
| 87 | // L3.1: 1280 * 720 = 921600 <= 983040 | ||
| 88 | // L4: <= 2228224 * 1/2 = 1114112 | ||
| 89 | // L5: <= 8912896 * 1/4 = 2228224 | ||
| 90 | { 1280, 720, 6, 93 }, | ||
| 91 | { 1280, 720, 12, 120 }, | ||
| 92 | { 1280, 720, 16, 150 }, | ||
| 93 | |||
| 94 | // L5: 3840 * 2160 = 8294400 <= 8912896 | ||
| 95 | // L6: <= 35651584 * 1/4 = 8912896 | ||
| 96 | { 3840, 2160, 6, 150 }, | ||
| 97 | { 3840, 2160, 7, 180 }, | ||
| 98 | { 3840, 2160, 16, 180 }, | ||
| 99 | }; | ||
| 100 | |||
| 101 | static const H265RawProfileTierLevel profile_main = { | ||
| 102 | // CpbNalFactor = 1100 | ||
| 103 | .general_profile_space = 0, | ||
| 104 | .general_profile_idc = 1, | ||
| 105 | .general_tier_flag = 0, | ||
| 106 | .general_profile_compatibility_flag[1] = 1, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static const H265RawProfileTierLevel profile_main_12 = { | ||
| 110 | // CpbNalFactor = 1650 | ||
| 111 | .general_profile_space = 0, | ||
| 112 | .general_profile_idc = 4, | ||
| 113 | .general_tier_flag = 0, | ||
| 114 | .general_profile_compatibility_flag[4] = 1, | ||
| 115 | .general_max_12bit_constraint_flag = 1, | ||
| 116 | .general_max_10bit_constraint_flag = 0, | ||
| 117 | .general_max_8bit_constraint_flag = 0, | ||
| 118 | .general_max_422chroma_constraint_flag = 1, | ||
| 119 | .general_max_420chroma_constraint_flag = 1, | ||
| 120 | .general_max_monochrome_constraint_flag = 0, | ||
| 121 | .general_intra_constraint_flag = 0, | ||
| 122 | .general_one_picture_only_constraint_flag = 0, | ||
| 123 | .general_lower_bit_rate_constraint_flag = 1, | ||
| 124 | }; | ||
| 125 | |||
| 126 | static const H265RawProfileTierLevel profile_main_422_12_intra = { | ||
| 127 | // CpbNalFactor = 2200 | ||
| 128 | .general_profile_space = 0, | ||
| 129 | .general_profile_idc = 4, | ||
| 130 | .general_tier_flag = 0, | ||
| 131 | .general_profile_compatibility_flag[4] = 1, | ||
| 132 | .general_max_12bit_constraint_flag = 1, | ||
| 133 | .general_max_10bit_constraint_flag = 0, | ||
| 134 | .general_max_8bit_constraint_flag = 0, | ||
| 135 | .general_max_422chroma_constraint_flag = 1, | ||
| 136 | .general_max_420chroma_constraint_flag = 0, | ||
| 137 | .general_max_monochrome_constraint_flag = 0, | ||
| 138 | .general_intra_constraint_flag = 1, | ||
| 139 | .general_one_picture_only_constraint_flag = 0, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static const H265RawProfileTierLevel profile_ht_444_14 = { | ||
| 143 | // CpbNalFactor = 3850 | ||
| 144 | .general_profile_space = 0, | ||
| 145 | .general_profile_idc = 5, | ||
| 146 | .general_tier_flag = 0, | ||
| 147 | .general_profile_compatibility_flag[5] = 1, | ||
| 148 | .general_max_14bit_constraint_flag = 1, | ||
| 149 | .general_max_12bit_constraint_flag = 0, | ||
| 150 | .general_max_10bit_constraint_flag = 0, | ||
| 151 | .general_max_8bit_constraint_flag = 0, | ||
| 152 | .general_max_422chroma_constraint_flag = 0, | ||
| 153 | .general_max_420chroma_constraint_flag = 0, | ||
| 154 | .general_max_monochrome_constraint_flag = 0, | ||
| 155 | .general_intra_constraint_flag = 0, | ||
| 156 | .general_one_picture_only_constraint_flag = 0, | ||
| 157 | .general_lower_bit_rate_constraint_flag = 1, | ||
| 158 | }; | ||
| 159 | |||
| 160 | static const H265RawProfileTierLevel profile_main_high_tier = { | ||
| 161 | // CpbNalFactor = 1100 | ||
| 162 | .general_profile_space = 0, | ||
| 163 | .general_profile_idc = 1, | ||
| 164 | .general_tier_flag = 1, | ||
| 165 | .general_profile_compatibility_flag[1] = 1, | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const struct { | ||
| 169 | int64_t bitrate; | ||
| 170 | const H265RawProfileTierLevel *ptl; | ||
| 171 | int level_idc; | ||
| 172 | } test_bitrate[] = { | ||
| 173 | // First level usable for some bitrates and profiles. | ||
| 174 | |||
| 175 | // L2.1: 3000 * 1100 = 3300000 | ||
| 176 | // L3: 6000 * 1100 = 6600000 | ||
| 177 | { 4000000, &profile_main, 90 }, | ||
| 178 | // L2: 1500 * 1650 = 2475000 | ||
| 179 | // L2.1: 3000 * 1650 = 4950000 | ||
| 180 | { 4000000, &profile_main_12, 63 }, | ||
| 181 | // L1: 350 * 2200 * 2 = 1540000 | ||
| 182 | // L2: 1500 * 2200 * 2 = 6600000 | ||
| 183 | { 4000000, &profile_main_422_12_intra, 60 }, | ||
| 184 | |||
| 185 | // L5.1: 40000 * 1100 = 44000000 | ||
| 186 | // L5.2: 60000 * 1100 = 66000000 | ||
| 187 | { 50000000, &profile_main, 156 }, | ||
| 188 | // L5: 25000 * 1650 = 41250000 | ||
| 189 | // L5.1: 40000 * 1650 = 66000000 | ||
| 190 | { 50000000, &profile_main_12, 153 }, | ||
| 191 | // L3.1: 10000 * 2200 * 2 = 44000000 | ||
| 192 | // L4: 12000 * 2200 * 2 = 52800000 | ||
| 193 | { 50000000, &profile_main_422_12_intra, 120 }, | ||
| 194 | // L2: 1500 * 3850 * 6 = 34650000 | ||
| 195 | // L2.1: 3000 * 3850 * 6 = 69300000 | ||
| 196 | { 50000000, &profile_ht_444_14, 63 }, | ||
| 197 | |||
| 198 | // Level changes based on tier. | ||
| 199 | { 1000, &profile_main, 30 }, | ||
| 200 | { 1000, &profile_main_high_tier, 120 }, | ||
| 201 | { 40000000, &profile_main, 153 }, | ||
| 202 | { 40000000, &profile_main_high_tier, 123 }, | ||
| 203 | { 200000000, &profile_main, 186 }, | ||
| 204 | { 200000000, &profile_main_high_tier, 156 }, | ||
| 205 | |||
| 206 | // Overflowing 32-bit integers. | ||
| 207 | // L6: 60000 * 3850 * 6 = 1386000000 | ||
| 208 | // L6.1: 120000 * 3850 * 6 = 2772000000 | ||
| 209 | // L6.2: 240000 * 3850 * 6 = 5544000000 | ||
| 210 | { INT64_C(2700000000), &profile_ht_444_14, 183 }, | ||
| 211 | { INT64_C(4200000000), &profile_ht_444_14, 186 }, | ||
| 212 | { INT64_C(5600000000), &profile_ht_444_14, 0 }, | ||
| 213 | }; | ||
| 214 | |||
| 215 | static const struct { | ||
| 216 | int slice_segments; | ||
| 217 | int tile_rows; | ||
| 218 | int tile_cols; | ||
| 219 | int level_idc; | ||
| 220 | } test_fragments[] = { | ||
| 221 | // Slices. | ||
| 222 | { 4, 1, 1, 30 }, | ||
| 223 | { 32, 1, 1, 93 }, | ||
| 224 | { 70, 1, 1, 120 }, | ||
| 225 | { 80, 1, 1, 150 }, | ||
| 226 | { 201, 1, 1, 180 }, | ||
| 227 | { 600, 1, 1, 180 }, | ||
| 228 | { 601, 1, 1, 0 }, | ||
| 229 | |||
| 230 | // Tiles. | ||
| 231 | { 1, 2, 1, 90 }, | ||
| 232 | { 1, 1, 2, 90 }, | ||
| 233 | { 1, 3, 3, 93 }, | ||
| 234 | { 1, 4, 2, 120 }, | ||
| 235 | { 1, 2, 4, 120 }, | ||
| 236 | { 1, 11, 10, 150 }, | ||
| 237 | { 1, 10, 11, 180 }, | ||
| 238 | { 1, 22, 20, 180 }, | ||
| 239 | { 1, 20, 22, 0 }, | ||
| 240 | }; | ||
| 241 | |||
| 242 | 1 | int main(void) | |
| 243 | { | ||
| 244 | const H265ProfileDescriptor *profile; | ||
| 245 | const H265LevelDescriptor *level; | ||
| 246 | int i; | ||
| 247 | |||
| 248 | #define CHECK(expected, format, ...) do { \ | ||
| 249 | if (expected ? (!level || level->level_idc != expected) \ | ||
| 250 | : !!level) { \ | ||
| 251 | av_log(NULL, AV_LOG_ERROR, "Incorrect level for " \ | ||
| 252 | format ": expected %d, got %d.\n", __VA_ARGS__, \ | ||
| 253 | expected, level ? level->level_idc : -1); \ | ||
| 254 | return 1; \ | ||
| 255 | } \ | ||
| 256 | } while (0) | ||
| 257 | |||
| 258 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 1 times.
|
36 | for (i = 0; i < FF_ARRAY_ELEMS(test_sizes); i++) { |
| 259 | 35 | level = ff_h265_guess_level(&profile_main, 0, | |
| 260 | 35 | test_sizes[i].width, | |
| 261 | 35 | test_sizes[i].height, | |
| 262 | 0, 0, 0, 0); | ||
| 263 |
5/10✓ Branch 0 taken 32 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 35 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
35 | CHECK(test_sizes[i].level_idc, "size %dx%d", |
| 264 | test_sizes[i].width, test_sizes[i].height); | ||
| 265 | } | ||
| 266 | |||
| 267 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | for (i = 0; i < FF_ARRAY_ELEMS(test_dpb); i++) { |
| 268 | 11 | level = ff_h265_guess_level(&profile_main, 0, | |
| 269 | 11 | test_dpb[i].width, | |
| 270 | 11 | test_dpb[i].height, | |
| 271 | 11 | 0, 0, 0, test_dpb[i].dpb_size); | |
| 272 |
4/10✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
11 | CHECK(test_dpb[i].level_idc, "size %dx%d dpb %d", |
| 273 | test_dpb[i].width, test_dpb[i].height, | ||
| 274 | test_dpb[i].dpb_size); | ||
| 275 | } | ||
| 276 | |||
| 277 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
|
17 | for (i = 0; i < FF_ARRAY_ELEMS(test_bitrate); i++) { |
| 278 | 16 | profile = ff_h265_get_profile(test_bitrate[i].ptl); | |
| 279 | 16 | level = ff_h265_guess_level(test_bitrate[i].ptl, | |
| 280 | 16 | test_bitrate[i].bitrate, | |
| 281 | 0, 0, 0, 0, 0, 0); | ||
| 282 |
5/10✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
16 | CHECK(test_bitrate[i].level_idc, "bitrate %"PRId64" profile %s", |
| 283 | test_bitrate[i].bitrate, profile->name); | ||
| 284 | } | ||
| 285 | |||
| 286 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
|
17 | for (i = 0; i < FF_ARRAY_ELEMS(test_fragments); i++) { |
| 287 | 16 | level = ff_h265_guess_level(&profile_main, 0, 0, 0, | |
| 288 | 16 | test_fragments[i].slice_segments, | |
| 289 | 16 | test_fragments[i].tile_rows, | |
| 290 | 16 | test_fragments[i].tile_cols, 0); | |
| 291 |
5/10✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
16 | CHECK(test_fragments[i].level_idc, "%d slices %dx%d tiles", |
| 292 | test_fragments[i].slice_segments, | ||
| 293 | test_fragments[i].tile_cols, test_fragments[i].tile_rows); | ||
| 294 | } | ||
| 295 | |||
| 296 | 1 | return 0; | |
| 297 | } | ||
| 298 |