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 |