/src/libheif/libheif/codecs/hevc_boxes.cc
Line | Count | Source |
1 | | /* |
2 | | * HEIF codec. |
3 | | * Copyright (c) 2017 Dirk Farin <dirk.farin@gmail.com> |
4 | | * |
5 | | * This file is part of libheif. |
6 | | * |
7 | | * libheif is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libheif is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libheif. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "hevc_boxes.h" |
22 | | #include "bitstream.h" |
23 | | #include "error.h" |
24 | | #include "file.h" |
25 | | #include "hevc_dec.h" |
26 | | |
27 | | #include <cassert> |
28 | | #include <cmath> |
29 | | #include <cstring> |
30 | | #include <iomanip> |
31 | | #include <string> |
32 | | #include <utility> |
33 | | #include <algorithm> |
34 | | #include "api_structs.h" |
35 | | |
36 | | |
37 | | Error HEVCDecoderConfigurationRecord::parse(BitstreamRange& range, const heif_security_limits* limits) |
38 | 9.62k | { |
39 | 9.62k | uint8_t byte; |
40 | | |
41 | 9.62k | configuration_version = range.read8(); |
42 | 9.62k | byte = range.read8(); |
43 | 9.62k | general_profile_space = (byte >> 6) & 3; |
44 | 9.62k | general_tier_flag = (byte >> 5) & 1; |
45 | 9.62k | general_profile_idc = (byte & 0x1F); |
46 | | |
47 | 9.62k | general_profile_compatibility_flags = range.read32(); |
48 | | |
49 | 67.3k | for (int i = 0; i < 6; i++) { |
50 | 57.7k | byte = range.read8(); |
51 | | |
52 | 519k | for (int b = 0; b < 8; b++) { |
53 | 462k | general_constraint_indicator_flags[i * 8 + b] = (byte >> (7 - b)) & 1; |
54 | 462k | } |
55 | 57.7k | } |
56 | | |
57 | 9.62k | general_level_idc = range.read8(); |
58 | 9.62k | min_spatial_segmentation_idc = range.read16() & 0x0FFF; |
59 | 9.62k | parallelism_type = range.read8() & 0x03; |
60 | 9.62k | chroma_format = range.read8() & 0x03; |
61 | 9.62k | bit_depth_luma = static_cast<uint8_t>((range.read8() & 0x07) + 8); |
62 | 9.62k | bit_depth_chroma = static_cast<uint8_t>((range.read8() & 0x07) + 8); |
63 | 9.62k | avg_frame_rate = range.read16(); |
64 | | |
65 | 9.62k | byte = range.read8(); |
66 | 9.62k | constant_frame_rate = (byte >> 6) & 0x03; |
67 | 9.62k | num_temporal_layers = (byte >> 3) & 0x07; |
68 | 9.62k | temporal_id_nested = (byte >> 2) & 1; |
69 | | |
70 | 9.62k | m_length_size = static_cast<uint8_t>((byte & 0x03) + 1); |
71 | | |
72 | 9.62k | int nArrays = range.read8(); |
73 | | |
74 | 37.1k | for (int i = 0; i < nArrays && !range.error(); i++) { |
75 | 27.5k | byte = range.read8(); |
76 | | |
77 | 27.5k | NalArray array; |
78 | | |
79 | 27.5k | array.m_array_completeness = (byte >> 6) & 1; |
80 | 27.5k | array.m_NAL_unit_type = (byte & 0x3F); |
81 | | |
82 | 27.5k | int nUnits = range.read16(); |
83 | 55.7k | for (int u = 0; u < nUnits && !range.error(); u++) { |
84 | | |
85 | 28.2k | std::vector<uint8_t> nal_unit; |
86 | 28.2k | int size = range.read16(); |
87 | 28.2k | if (!size) { |
88 | | // Ignore empty NAL units. |
89 | 1.72k | continue; |
90 | 1.72k | } |
91 | | |
92 | 26.4k | if (range.prepare_read(size)) { |
93 | 26.3k | nal_unit.resize(size); |
94 | 26.3k | bool success = range.get_istream()->read((char*) nal_unit.data(), size); |
95 | 26.3k | if (!success) { |
96 | 0 | return Error{heif_error_Invalid_input, heif_suberror_End_of_data, "error while reading hvcC box"}; |
97 | 0 | } |
98 | 26.3k | } |
99 | | |
100 | 26.4k | array.m_nal_units.push_back(std::move(nal_unit)); |
101 | 26.4k | } |
102 | | |
103 | 27.5k | m_nal_array.push_back(std::move(array)); |
104 | 27.5k | } |
105 | | |
106 | 9.62k | range.skip_to_end_of_box(); |
107 | | |
108 | 9.62k | return range.get_error(); |
109 | 9.62k | } |
110 | | |
111 | | |
112 | | Error HEVCDecoderConfigurationRecord::write(StreamWriter& writer) const |
113 | 0 | { |
114 | 0 | writer.write8(configuration_version); |
115 | |
|
116 | 0 | writer.write8((uint8_t) (((general_profile_space & 3) << 6) | |
117 | 0 | ((general_tier_flag & 1) << 5) | |
118 | 0 | (general_profile_idc & 0x1F))); |
119 | |
|
120 | 0 | writer.write32(general_profile_compatibility_flags); |
121 | |
|
122 | 0 | for (int i = 0; i < 6; i++) { |
123 | 0 | uint8_t byte = 0; |
124 | |
|
125 | 0 | for (int b = 0; b < 8; b++) { |
126 | 0 | byte = (uint8_t) (byte << 1); |
127 | |
|
128 | 0 | if (general_constraint_indicator_flags[i * 8 + b]) { |
129 | 0 | byte |= 1; |
130 | 0 | } |
131 | 0 | } |
132 | |
|
133 | 0 | writer.write8(byte); |
134 | 0 | } |
135 | |
|
136 | 0 | writer.write8(general_level_idc); |
137 | 0 | writer.write16((min_spatial_segmentation_idc & 0x0FFF) | 0xF000); |
138 | 0 | writer.write8(parallelism_type | 0xFC); |
139 | 0 | writer.write8(chroma_format | 0xFC); |
140 | 0 | writer.write8((uint8_t) ((bit_depth_luma - 8) | 0xF8)); |
141 | 0 | writer.write8((uint8_t) ((bit_depth_chroma - 8) | 0xF8)); |
142 | 0 | writer.write16(avg_frame_rate); |
143 | |
|
144 | 0 | writer.write8((uint8_t) (((constant_frame_rate & 0x03) << 6) | |
145 | 0 | ((num_temporal_layers & 0x07) << 3) | |
146 | 0 | ((temporal_id_nested & 1) << 2) | |
147 | 0 | ((m_length_size - 1) & 0x03))); |
148 | |
|
149 | 0 | size_t nArrays = m_nal_array.size(); |
150 | | // There cannot be an overflow because the nal-type is less than 8-bit. |
151 | 0 | assert(nArrays <= 0xFF); |
152 | |
|
153 | 0 | writer.write8(static_cast<uint8_t>(nArrays)); |
154 | |
|
155 | 0 | for (const HEVCDecoderConfigurationRecord::NalArray& array : m_nal_array) { |
156 | |
|
157 | 0 | writer.write8((uint8_t) (((array.m_array_completeness & 1) << 6) | |
158 | 0 | (array.m_NAL_unit_type & 0x3F))); |
159 | |
|
160 | 0 | size_t nUnits = array.m_nal_units.size(); |
161 | 0 | if (nUnits > 0xFFFF) { |
162 | 0 | return Error{heif_error_Invalid_input, heif_suberror_Unspecified, "Too many NAL units in hvcC"}; |
163 | 0 | } |
164 | | |
165 | 0 | writer.write16(static_cast<uint16_t>(nUnits)); |
166 | |
|
167 | 0 | for (const std::vector<uint8_t>& nal_unit : array.m_nal_units) { |
168 | 0 | if (nal_unit.size() > 0xFFFF) { |
169 | 0 | return Error{heif_error_Invalid_input, heif_suberror_Unspecified, "hvcC NAL unit exceeds maximum size (64kB)"}; |
170 | 0 | } |
171 | | |
172 | 0 | writer.write16(static_cast<uint16_t>(nal_unit.size())); |
173 | 0 | writer.write(nal_unit); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | 0 | return Error::Ok; |
178 | 0 | } |
179 | | |
180 | | |
181 | | bool HEVCDecoderConfigurationRecord::get_general_profile_compatibility_flag(int idx) const |
182 | 0 | { |
183 | 0 | return general_profile_compatibility_flags & (UINT32_C(0x80000000) >> idx); |
184 | 0 | } |
185 | | |
186 | | |
187 | | bool HEVCDecoderConfigurationRecord::is_profile_compatible(Profile profile) const |
188 | 0 | { |
189 | 0 | return (general_profile_idc == profile || |
190 | 0 | get_general_profile_compatibility_flag(profile)); |
191 | 0 | } |
192 | | |
193 | | |
194 | | bool HEVCDecoderConfigurationRecord::is_miaf_profile() const |
195 | 0 | { |
196 | | // The MIAF HEVC Basic, Advanced and Extended profiles (ISO/IEC 23000-22, A.3.2, A.4.2, A.5.2) |
197 | | // list the HEVC profiles of their images. |
198 | | // |
199 | | // They also limit the images to the Main tier and to level 6. This is not checked here: |
200 | | // the encoders do not all signal the level that the image needs (kvazaar signals level 6.2 |
201 | | // for every image), so the level in 'hvcC' does not tell whether the image is within |
202 | | // the limit. |
203 | |
|
204 | 0 | if (general_profile_space != 0) { |
205 | 0 | return false; |
206 | 0 | } |
207 | | |
208 | | // Main and Main Still Picture (Basic), Main 10 and Main 10 Still Picture (Advanced). |
209 | | // A bitstream in the Main 10 Still Picture profile is also one in the Main 10 profile. |
210 | | |
211 | 0 | if (is_profile_compatible(Profile_Main) || |
212 | 0 | is_profile_compatible(Profile_MainStillPicture) || |
213 | 0 | is_profile_compatible(Profile_Main10)) { |
214 | 0 | return true; |
215 | 0 | } |
216 | | |
217 | 0 | if (!is_profile_compatible(Profile_RExt)) { |
218 | | // There is no MIAF profile with the high throughput profiles, the screen content coding |
219 | | // profiles or any other profile of HEVC. |
220 | 0 | return false; |
221 | 0 | } |
222 | | |
223 | | // The format range extensions profiles are told apart by nine of the constraint flags. |
224 | | // A bitstream conforms to a profile when each of its flags is greater than or equal to the |
225 | | // flag of the profile in Table A.2 of ITU-T H.265. This way, a profile that is not listed |
226 | | // here is accepted when it is a subset of a listed one, like Main 4:4:4 Intra, which is a |
227 | | // subset of Main 4:4:4 10 Intra. |
228 | | |
229 | 0 | const int first_flag = 4; // general_max_12bit_constraint_flag |
230 | 0 | const int num_flags = 9; |
231 | |
|
232 | 0 | static const bool miaf_profiles[][num_flags] = { |
233 | | // max 12 bit, max 10 bit, max 8 bit, max 4:2:2, max 4:2:0, max monochrome, |
234 | | // intra, one picture only, lower bit rate |
235 | | |
236 | | // MIAF HEVC Advanced profile |
237 | 0 | {1, 1, 1, 1, 1, 0, 1, 0, 0}, // Main Intra |
238 | 0 | {1, 1, 0, 1, 1, 0, 1, 0, 0}, // Main 10 Intra |
239 | 0 | {1, 1, 0, 1, 0, 0, 1, 0, 0}, // Main 4:2:2 10 Intra |
240 | | |
241 | | // MIAF HEVC Extended profile |
242 | 0 | {1, 1, 1, 0, 0, 0, 0, 0, 1}, // Main 4:4:4 |
243 | 0 | {1, 1, 0, 0, 0, 0, 0, 0, 1}, // Main 4:4:4 10 |
244 | 0 | {1, 1, 0, 0, 0, 0, 1, 0, 0}, // Main 4:4:4 10 Intra |
245 | 0 | {1, 1, 1, 0, 0, 0, 1, 1, 0}, // Main 4:4:4 Still Picture |
246 | 0 | {1, 1, 1, 1, 1, 1, 0, 0, 1}, // Monochrome |
247 | 0 | {1, 1, 0, 1, 1, 1, 0, 0, 1} // Monochrome 10 |
248 | 0 | }; |
249 | |
|
250 | 0 | for (const auto& profile : miaf_profiles) { |
251 | 0 | bool conforms = true; |
252 | |
|
253 | 0 | for (int i = 0; i < num_flags; i++) { |
254 | 0 | if (profile[i] && !general_constraint_indicator_flags[first_flag + i]) { |
255 | 0 | conforms = false; |
256 | 0 | break; |
257 | 0 | } |
258 | 0 | } |
259 | |
|
260 | 0 | if (conforms) { |
261 | 0 | return true; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 0 | return false; |
266 | 0 | } |
267 | | |
268 | | |
269 | | Error Box_hvcC::parse(BitstreamRange& range, const heif_security_limits* limits) |
270 | 9.62k | { |
271 | 9.62k | return m_configuration.parse(range, limits); |
272 | 9.62k | } |
273 | | |
274 | | |
275 | | void Box_hvcC::dump(std::ostream& sstr, Indent& indent, bool full_log) const |
276 | 0 | { |
277 | 0 | Box::dump(sstr, indent, full_log); |
278 | |
|
279 | 0 | const auto& c = m_configuration; // abbreviation |
280 | |
|
281 | 0 | sstr << indent << "configuration_version: " << ((int) c.configuration_version) << "\n" |
282 | 0 | << indent << "general_profile_space: " << ((int) c.general_profile_space) << "\n" |
283 | 0 | << indent << "general_tier_flag: " << c.general_tier_flag << "\n" |
284 | 0 | << indent << "general_profile_idc: " << ((int) c.general_profile_idc) << "\n"; |
285 | |
|
286 | 0 | sstr << indent << "general_profile_compatibility_flags: "; |
287 | 0 | for (int i = 0; i < 32; i++) { |
288 | 0 | sstr << ((c.general_profile_compatibility_flags >> (31 - i)) & 1); |
289 | 0 | if ((i % 8) == 7) sstr << ' '; |
290 | 0 | else if ((i % 4) == 3) sstr << '.'; |
291 | 0 | } |
292 | 0 | sstr << "\n"; |
293 | |
|
294 | 0 | sstr << indent << "general_constraint_indicator_flags: "; |
295 | 0 | int cnt = 0; |
296 | 0 | for (int i = 0; i < HEVCDecoderConfigurationRecord::NUM_CONSTRAINT_INDICATOR_FLAGS; i++) { |
297 | 0 | bool b = c.general_constraint_indicator_flags[i]; |
298 | |
|
299 | 0 | sstr << (b ? 1 : 0); |
300 | 0 | cnt++; |
301 | 0 | if ((cnt % 8) == 0) |
302 | 0 | sstr << ' '; |
303 | 0 | } |
304 | 0 | sstr << "\n"; |
305 | |
|
306 | 0 | sstr << indent << "general_level_idc: " << ((int) c.general_level_idc) << "\n" |
307 | 0 | << indent << "min_spatial_segmentation_idc: " << c.min_spatial_segmentation_idc << "\n" |
308 | 0 | << indent << "parallelism_type: " << ((int) c.parallelism_type) << "\n" |
309 | 0 | << indent << "chroma_format: "; |
310 | |
|
311 | 0 | switch (c.chroma_format) { |
312 | 0 | case 0: |
313 | 0 | sstr << "monochrome"; |
314 | 0 | break; |
315 | 0 | case 1: |
316 | 0 | sstr << "4:2:0"; |
317 | 0 | break; |
318 | 0 | case 2: |
319 | 0 | sstr << "4:2:2"; |
320 | 0 | break; |
321 | 0 | case 3: |
322 | 0 | sstr << "4:4:4"; |
323 | 0 | break; |
324 | 0 | default: |
325 | 0 | sstr << ((int) c.chroma_format); |
326 | 0 | break; |
327 | 0 | } |
328 | | |
329 | 0 | sstr << "\n" |
330 | 0 | << indent << "bit_depth_luma: " << ((int) c.bit_depth_luma) << "\n" |
331 | 0 | << indent << "bit_depth_chroma: " << ((int) c.bit_depth_chroma) << "\n" |
332 | 0 | << indent << "avg_frame_rate: " << c.avg_frame_rate << "\n" |
333 | 0 | << indent << "constant_frame_rate: " << ((int) c.constant_frame_rate) << "\n" |
334 | 0 | << indent << "num_temporal_layers: " << ((int) c.num_temporal_layers) << "\n" |
335 | 0 | << indent << "temporal_id_nested: " << ((int) c.temporal_id_nested) << "\n" |
336 | 0 | << indent << "length_size: " << ((int) c.m_length_size) << "\n"; |
337 | |
|
338 | 0 | for (const auto& array : c.m_nal_array) { |
339 | 0 | sstr << indent << "<array>\n"; |
340 | |
|
341 | 0 | indent++; |
342 | 0 | sstr << indent << "array_completeness: " << ((int) array.m_array_completeness) << "\n" |
343 | 0 | << indent << "NAL_unit_type: " << ((int) array.m_NAL_unit_type) << "\n"; |
344 | |
|
345 | 0 | for (const auto& unit : array.m_nal_units) { |
346 | | //sstr << " unit with " << unit.size() << " bytes of data\n"; |
347 | 0 | sstr << indent; |
348 | 0 | for (uint8_t b : unit) { |
349 | 0 | sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " "; |
350 | 0 | } |
351 | 0 | sstr << "\n"; |
352 | 0 | sstr << std::dec; |
353 | 0 | } |
354 | |
|
355 | 0 | indent--; |
356 | 0 | } |
357 | |
|
358 | 0 | return; |
359 | 0 | } |
360 | | |
361 | | |
362 | | bool Box_hvcC::get_header_nals(std::vector<uint8_t>* dest) const |
363 | 8.82k | { |
364 | | // Concatenate all header NALs, each prefixed by a 4-byte size. |
365 | | |
366 | 25.0k | for (const auto& array : m_configuration.m_nal_array) { |
367 | 25.0k | for (const auto& unit : array.m_nal_units) { |
368 | | |
369 | | // Write 4-byte NALs size |
370 | | |
371 | 24.5k | dest->push_back((unit.size() >> 24) & 0xFF); |
372 | 24.5k | dest->push_back((unit.size() >> 16) & 0xFF); |
373 | 24.5k | dest->push_back((unit.size() >> 8) & 0xFF); |
374 | 24.5k | dest->push_back((unit.size() >> 0) & 0xFF); |
375 | | |
376 | | // Copy NAL data |
377 | | |
378 | 24.5k | dest->insert(dest->end(), unit.begin(), unit.end()); |
379 | 24.5k | } |
380 | 25.0k | } |
381 | | |
382 | 8.82k | return true; |
383 | 8.82k | } |
384 | | |
385 | | void Box_hvcC::append_nal_data(const uint8_t* data, size_t size) |
386 | 0 | { |
387 | 0 | std::vector<uint8_t> nal; |
388 | 0 | nal.resize(size); |
389 | 0 | if (size > 0) { // memcpy() with a NULL pointer is UB even for size 0 (until C2y/N3322), see StreamReader_memory::read() |
390 | 0 | memcpy(nal.data(), data, size); |
391 | 0 | } |
392 | |
|
393 | 0 | append_nal_data(nal); |
394 | 0 | } |
395 | | |
396 | | void Box_hvcC::append_nal_data(const std::vector<uint8_t>& nal) |
397 | 0 | { |
398 | 0 | for (auto& nal_array : m_configuration.m_nal_array) { |
399 | 0 | if (nal_array.m_NAL_unit_type == uint8_t(nal[0] >> 1)) { |
400 | | |
401 | | // kvazaar may send the same headers multiple times. Filter out the identical copies. |
402 | |
|
403 | 0 | for (auto& nal_unit : nal_array.m_nal_units) { |
404 | | |
405 | | // Note: sometimes kvazaar even sends the same packet twice, but with an extra zero byte. |
406 | | // We detect this by comparing only the common length. This is correct since each NAL |
407 | | // packet must be complete and thus, if a packet is longer than another complete packet, |
408 | | // its extra data must be superfluous. |
409 | | // |
410 | | // Example: |
411 | | //| | | <array> |
412 | | //| | | | array_completeness: 1 |
413 | | //| | | | NAL_unit_type: 34 |
414 | | //| | | | 44 01 c1 71 82 99 20 00 |
415 | | //| | | | 44 01 c1 71 82 99 20 |
416 | | |
417 | | // Check whether packets have similar content. |
418 | |
|
419 | 0 | const size_t common_length = std::min(nal_unit.size(), nal.size()); |
420 | 0 | bool similar = true; |
421 | 0 | for (size_t i = 0; i < common_length; i++) { |
422 | 0 | if (nal_unit[i] != nal[i]) { |
423 | 0 | similar = false; |
424 | 0 | break; |
425 | 0 | } |
426 | 0 | } |
427 | |
|
428 | 0 | if (similar) { |
429 | | // If they are similar, keep the smaller one. |
430 | |
|
431 | 0 | if (nal_unit.size() > nal.size()) { |
432 | 0 | nal_unit = nal; |
433 | 0 | } |
434 | | |
435 | | // Exit. Do not add a copy of the packet. |
436 | |
|
437 | 0 | return; |
438 | 0 | } |
439 | 0 | } |
440 | | |
441 | 0 | nal_array.m_nal_units.push_back(nal); |
442 | |
|
443 | 0 | return; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | | // This is a new NAL type. Add a new NAL array. |
448 | | |
449 | 0 | HEVCDecoderConfigurationRecord::NalArray array; |
450 | 0 | array.m_array_completeness = 1; |
451 | 0 | array.m_NAL_unit_type = uint8_t(nal[0] >> 1); |
452 | 0 | array.m_nal_units.push_back(nal); |
453 | |
|
454 | 0 | m_configuration.m_nal_array.push_back(array); |
455 | 0 | } |
456 | | |
457 | | |
458 | | Error Box_hvcC::write(StreamWriter& writer) const |
459 | 0 | { |
460 | 0 | size_t box_start = reserve_box_header_space(writer); |
461 | |
|
462 | 0 | const auto& c = m_configuration; // abbreviation |
463 | |
|
464 | 0 | Error err = c.write(writer); |
465 | 0 | if (err) { |
466 | 0 | return err; |
467 | 0 | } |
468 | | |
469 | 0 | prepend_header(writer, box_start); |
470 | |
|
471 | 0 | return Error::Ok; |
472 | 0 | } |
473 | | |
474 | | |
475 | | static double read_depth_rep_info_element(BitReader& reader) |
476 | 0 | { |
477 | 0 | uint8_t sign_flag = reader.get_bits8(1); |
478 | 0 | int exponent = reader.get_bits(7); |
479 | 0 | auto mantissa_len = static_cast<uint8_t>(reader.get_bits8(5) + 1); |
480 | 0 | if (mantissa_len < 1 || mantissa_len > 32) { |
481 | | // TODO err |
482 | 0 | } |
483 | |
|
484 | 0 | if (exponent == 127) { |
485 | | // TODO value unspecified |
486 | 0 | } |
487 | |
|
488 | 0 | uint32_t mantissa = reader.get_bits32(mantissa_len); |
489 | 0 | double value; |
490 | | |
491 | | //printf("sign:%d exponent:%d mantissa_len:%d mantissa:%d\n",sign_flag,exponent,mantissa_len,mantissa); |
492 | | |
493 | | // TODO: this seems to be wrong. 'exponent' is never negative. How to read it correctly? |
494 | 0 | if (exponent > 0) { |
495 | 0 | value = pow(2.0, exponent - 31) * (1.0 + mantissa / pow(2.0, mantissa_len)); |
496 | 0 | } |
497 | 0 | else { |
498 | 0 | value = pow(2.0, -(30 + mantissa_len)) * mantissa; |
499 | 0 | } |
500 | |
|
501 | 0 | if (sign_flag) { |
502 | 0 | value = -value; |
503 | 0 | } |
504 | |
|
505 | 0 | return value; |
506 | 0 | } |
507 | | |
508 | | |
509 | | static Result<std::shared_ptr<SEIMessage>> read_depth_representation_info(BitReader& reader) |
510 | 0 | { |
511 | 0 | auto msg = std::make_shared<SEIMessage_depth_representation_info>(); |
512 | | |
513 | | |
514 | | // default values |
515 | |
|
516 | 0 | msg->version = 1; |
517 | |
|
518 | 0 | msg->disparity_reference_view = 0; |
519 | 0 | msg->depth_nonlinear_representation_model_size = 0; |
520 | 0 | msg->depth_nonlinear_representation_model = nullptr; |
521 | | |
522 | | |
523 | | // read header |
524 | |
|
525 | 0 | msg->has_z_near = (uint8_t) reader.get_bits(1); |
526 | 0 | msg->has_z_far = (uint8_t) reader.get_bits(1); |
527 | 0 | msg->has_d_min = (uint8_t) reader.get_bits(1); |
528 | 0 | msg->has_d_max = (uint8_t) reader.get_bits(1); |
529 | |
|
530 | 0 | uint32_t rep_type; |
531 | 0 | if (!reader.get_uvlc(&rep_type)) { |
532 | 0 | return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "invalid depth representation type in input"}; |
533 | 0 | } |
534 | | |
535 | 0 | if (rep_type > 3) { |
536 | 0 | return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "input depth representation type out of range"}; |
537 | 0 | } |
538 | | |
539 | 0 | msg->depth_representation_type = (enum heif_depth_representation_type) rep_type; |
540 | | |
541 | | //printf("flags: %d %d %d %d\n",msg->has_z_near,msg->has_z_far,msg->has_d_min,msg->has_d_max); |
542 | | //printf("type: %d\n",rep_type); |
543 | |
|
544 | 0 | if (msg->has_d_min || msg->has_d_max) { |
545 | 0 | uint32_t ref_view; |
546 | 0 | if (!reader.get_uvlc(&ref_view)) { |
547 | 0 | return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "invalid disparity_reference_view in input"}; |
548 | 0 | } |
549 | 0 | msg->disparity_reference_view = ref_view; |
550 | | |
551 | | //printf("ref_view: %d\n",msg->disparity_reference_view); |
552 | 0 | } |
553 | | |
554 | 0 | if (msg->has_z_near) msg->z_near = read_depth_rep_info_element(reader); |
555 | 0 | if (msg->has_z_far) msg->z_far = read_depth_rep_info_element(reader); |
556 | 0 | if (msg->has_d_min) msg->d_min = read_depth_rep_info_element(reader); |
557 | 0 | if (msg->has_d_max) msg->d_max = read_depth_rep_info_element(reader); |
558 | | |
559 | | /* |
560 | | printf("z_near: %f\n",msg->z_near); |
561 | | printf("z_far: %f\n",msg->z_far); |
562 | | printf("dmin: %f\n",msg->d_min); |
563 | | printf("dmax: %f\n",msg->d_max); |
564 | | */ |
565 | |
|
566 | 0 | if (msg->depth_representation_type == heif_depth_representation_type_nonuniform_disparity) { |
567 | | // TODO: load non-uniform response curve |
568 | 0 | } |
569 | |
|
570 | 0 | return {msg}; |
571 | 0 | } |
572 | | |
573 | | |
574 | | // aux subtypes: 00 00 00 11 / 00 00 00 0d / 4e 01 / b1 09 / 35 1e 78 c8 01 03 c5 d0 20 |
575 | | |
576 | | Error decode_hevc_aux_sei_messages(const std::vector<uint8_t>& data, |
577 | | std::vector<std::shared_ptr<SEIMessage>>& msgs) |
578 | 85 | { |
579 | | // TODO: we probably do not need a full BitReader just for the array size. |
580 | | // Read this and the NAL size directly on the array data. |
581 | | |
582 | 85 | BitReader reader(data.data(), data.size()); |
583 | 85 | if (reader.get_bits_remaining() < 32) { |
584 | 0 | return {heif_error_Invalid_input, |
585 | 0 | heif_suberror_End_of_data, |
586 | 0 | "HEVC SEI NAL too short"}; |
587 | 0 | } |
588 | | |
589 | 85 | uint32_t len = reader.get_bits32(32); |
590 | | |
591 | 85 | if (len > data.size() - 4) { |
592 | | // ERROR: read past end of data |
593 | 59 | } |
594 | | |
595 | 85 | while (reader.get_current_byte_index() < len) { |
596 | 59 | size_t currPos = reader.get_current_byte_index(); |
597 | | |
598 | 59 | BitReader sei_reader(data.data() + currPos, data.size() - currPos); |
599 | | |
600 | 59 | if (sei_reader.get_bits_remaining() < 32+8) { |
601 | 1 | return {heif_error_Invalid_input, |
602 | 1 | heif_suberror_End_of_data, |
603 | 1 | "HEVC SEI NAL too short"}; |
604 | 1 | } |
605 | | |
606 | 58 | uint32_t nal_size = sei_reader.get_bits32(32); |
607 | 58 | (void) nal_size; |
608 | | |
609 | 58 | auto nal_type = static_cast<uint8_t>(sei_reader.get_bits8(8) >> 1); |
610 | 58 | sei_reader.skip_bits(8); |
611 | | |
612 | | // SEI |
613 | | |
614 | 58 | if (nal_type == 39 || |
615 | 36 | nal_type == 40) { |
616 | | |
617 | 22 | if (sei_reader.get_bits_remaining() < 16) { |
618 | 0 | return {heif_error_Invalid_input, |
619 | 0 | heif_suberror_End_of_data, |
620 | 0 | "HEVC SEI NAL too short"}; |
621 | 0 | } |
622 | | |
623 | | // TODO: loading of multi-byte sei headers |
624 | 22 | uint8_t payload_id = sei_reader.get_bits8(8); |
625 | 22 | uint8_t payload_size = sei_reader.get_bits8(8); |
626 | 22 | (void) payload_size; |
627 | | |
628 | 22 | if (payload_id == 177) { |
629 | | // depth_representation_info |
630 | 0 | Result<std::shared_ptr<SEIMessage>> seiResult = read_depth_representation_info(sei_reader); |
631 | 0 | if (!seiResult) { |
632 | 0 | return seiResult.error(); |
633 | 0 | } |
634 | | |
635 | 0 | msgs.push_back(*seiResult); |
636 | 0 | } |
637 | 22 | } |
638 | | |
639 | 58 | break; // TODO: read next SEI |
640 | 58 | } |
641 | | |
642 | | |
643 | 84 | return Error::Ok; |
644 | 85 | } |
645 | | |
646 | | |
647 | | // Used for AVC, HEVC, and VVC. |
648 | | std::vector<uint8_t> remove_start_code_emulation(const uint8_t* sps, size_t size) |
649 | 7.84k | { |
650 | 7.84k | std::vector<uint8_t> out_data; |
651 | | |
652 | 499k | for (size_t i = 0; i < size; i++) { |
653 | 491k | if (i + 2 < size && |
654 | 475k | sps[i] == 0 && |
655 | 120k | sps[i + 1] == 0 && |
656 | 67.0k | sps[i + 2] == 3) { |
657 | 18.6k | out_data.push_back(0); |
658 | 18.6k | out_data.push_back(0); |
659 | 18.6k | i += 2; |
660 | 18.6k | } |
661 | 472k | else { |
662 | 472k | out_data.push_back(sps[i]); |
663 | 472k | } |
664 | 491k | } |
665 | | |
666 | 7.84k | return out_data; |
667 | 7.84k | } |
668 | | |
669 | | |
670 | | Error parse_sps_for_hvcC_configuration(const uint8_t* sps, size_t size, |
671 | | HEVCDecoderConfigurationRecord* config, |
672 | | uint32_t* width, uint32_t* height, |
673 | | ImageSize* coded_size) |
674 | 7.84k | { |
675 | | // remove start-code emulation bytes from SPS header stream |
676 | | |
677 | 7.84k | std::vector<uint8_t> sps_no_emul = remove_start_code_emulation(sps, size); |
678 | | |
679 | 7.84k | sps = sps_no_emul.data(); |
680 | 7.84k | size = sps_no_emul.size(); |
681 | | |
682 | | |
683 | 7.84k | BitReader reader(sps, size); |
684 | | |
685 | | // skip NAL header |
686 | 7.84k | reader.skip_bits(2 * 8); |
687 | | |
688 | | // skip VPS ID |
689 | 7.84k | reader.skip_bits(4); |
690 | | |
691 | 7.84k | uint8_t nMaxSubLayersMinus1 = reader.get_bits8(3); |
692 | 7.84k | if (nMaxSubLayersMinus1 > 6) { |
693 | | // sps_max_sub_layers_minus1 is in the range 0..6 (H.265 section 7.4.3.2.1). |
694 | 12 | return Error{heif_error_Invalid_input, |
695 | 12 | heif_suberror_Invalid_parameter_value, |
696 | 12 | "SPS sps_max_sub_layers_minus1 out of range"}; |
697 | 12 | } |
698 | | |
699 | 7.83k | config->temporal_id_nested = reader.get_bits8(1); |
700 | | |
701 | | // --- profile_tier_level --- |
702 | | |
703 | 7.83k | config->general_profile_space = reader.get_bits8(2); |
704 | 7.83k | config->general_tier_flag = reader.get_bits8(1); |
705 | 7.83k | config->general_profile_idc = reader.get_bits8(5); |
706 | 7.83k | config->general_profile_compatibility_flags = reader.get_bits32(32); |
707 | | |
708 | | // general_progressive_source_flag up to the last of the constraint flags. Within the range |
709 | | // extensions and the screen content coding extensions, they tell the profiles apart. |
710 | 383k | for (int i = 0; i < HEVCDecoderConfigurationRecord::NUM_CONSTRAINT_INDICATOR_FLAGS; i++) { |
711 | 375k | config->general_constraint_indicator_flags[i] = (reader.get_bits(1) != 0); |
712 | 375k | } |
713 | | |
714 | 7.83k | config->general_level_idc = reader.get_bits8(8); |
715 | | |
716 | 7.83k | std::vector<bool> layer_profile_present(nMaxSubLayersMinus1); |
717 | 7.83k | std::vector<bool> layer_level_present(nMaxSubLayersMinus1); |
718 | | |
719 | 9.69k | for (int i = 0; i < nMaxSubLayersMinus1; i++) { |
720 | 1.86k | layer_profile_present[i] = reader.get_bits(1); |
721 | 1.86k | layer_level_present[i] = reader.get_bits(1); |
722 | 1.86k | } |
723 | | |
724 | 7.83k | if (nMaxSubLayersMinus1 > 0) { |
725 | 3.00k | for (int i = nMaxSubLayersMinus1; i < 8; i++) { |
726 | 2.46k | reader.skip_bits(2); |
727 | 2.46k | } |
728 | 541 | } |
729 | | |
730 | 9.69k | for (int i = 0; i < nMaxSubLayersMinus1; i++) { |
731 | 1.86k | if (layer_profile_present[i]) { |
732 | | // Same 88 bits as the general profile above: space, tier, idc, |
733 | | // compatibility flags, then 48 bits of source and constraint flags. |
734 | 638 | reader.skip_bits(2 + 1 + 5); |
735 | 638 | reader.skip_bits(32); |
736 | 638 | reader.skip_bits(16); |
737 | 638 | reader.skip_bits(16); |
738 | 638 | reader.skip_bits(16); |
739 | 638 | } |
740 | | |
741 | 1.86k | if (layer_level_present[i]) { |
742 | 529 | reader.skip_bits(8); |
743 | 529 | } |
744 | 1.86k | } |
745 | | |
746 | | |
747 | | // --- SPS continued --- |
748 | | |
749 | 7.83k | Error invalidUVLC{ |
750 | 7.83k | heif_error_Invalid_input, |
751 | 7.83k | heif_suberror_Invalid_parameter_value, |
752 | 7.83k | "Invalid variable length code in HEVC SPS header" |
753 | 7.83k | }; |
754 | | |
755 | 7.83k | uint32_t value; |
756 | 7.83k | if (!reader.get_uvlc(&value)) { |
757 | 90 | return invalidUVLC; |
758 | 90 | } |
759 | 7.74k | if (value > 15) { |
760 | 28 | return Error{heif_error_Invalid_input, |
761 | 28 | heif_suberror_Invalid_parameter_value, |
762 | 28 | "SPS seq_parameter_set_id out of range"}; |
763 | 28 | } |
764 | | |
765 | 7.71k | if (!reader.get_uvlc(&value)) { |
766 | 11 | return invalidUVLC; |
767 | 11 | } |
768 | 7.70k | if (value > 3) { |
769 | | // chroma_format_idc is in the range 0..3 (H.265 section 7.4.3.2.1). The |
770 | | // value is later cast to heif_chroma, so it must not be left unchecked. |
771 | 17 | return Error{heif_error_Invalid_input, |
772 | 17 | heif_suberror_Invalid_parameter_value, |
773 | 17 | "SPS chroma_format_idc out of range"}; |
774 | 17 | } |
775 | 7.68k | config->chroma_format = (uint8_t) value; |
776 | | |
777 | 7.68k | if (config->chroma_format == 3) { |
778 | 1.73k | reader.skip_bits(1); |
779 | 1.73k | } |
780 | | |
781 | 7.68k | if (!reader.get_uvlc(width) || |
782 | 7.67k | !reader.get_uvlc(height)) { |
783 | 23 | return invalidUVLC; |
784 | 23 | } |
785 | 7.66k | if (*width == 0 || *height == 0 || *width > 65535 || *height > 65535) { |
786 | 78 | return Error{heif_error_Invalid_input, |
787 | 78 | heif_suberror_Invalid_parameter_value, |
788 | 78 | "SPS picture size out of range"}; |
789 | 78 | } |
790 | | |
791 | 7.58k | if (coded_size) { |
792 | 7.58k | coded_size->width = *width; |
793 | 7.58k | coded_size->height = *height; |
794 | 7.58k | } |
795 | | |
796 | 7.58k | bool conformance_window = reader.get_bits(1); |
797 | 7.58k | if (conformance_window) { |
798 | 961 | uint32_t left, right, top, bottom; |
799 | 961 | if (!reader.get_uvlc(&left) || |
800 | 950 | !reader.get_uvlc(&right) || |
801 | 939 | !reader.get_uvlc(&top) || |
802 | 928 | !reader.get_uvlc(&bottom)) { |
803 | 45 | return invalidUVLC; |
804 | 45 | } |
805 | | |
806 | | //printf("conformance borders: %u %u %u %u\n",left,right,top,bottom); |
807 | | |
808 | 916 | uint32_t subH = 1, subV = 1; |
809 | 916 | if (config->chroma_format == 1) { |
810 | 415 | subV = 2; |
811 | 415 | subH = 2; |
812 | 415 | } |
813 | 916 | if (config->chroma_format == 2) { subH = 2; } |
814 | | |
815 | 916 | const uint64_t crop_w = (uint64_t)subH * ((uint64_t)left + (uint64_t)right); |
816 | 916 | const uint64_t crop_h = (uint64_t)subV * ((uint64_t)top + (uint64_t)bottom); |
817 | 916 | if (crop_w >= *width || crop_h >= *height) { |
818 | 50 | return Error{heif_error_Invalid_input, |
819 | 50 | heif_suberror_Invalid_parameter_value, |
820 | 50 | "SPS conformance window exceeds image dimensions"}; |
821 | 50 | } |
822 | 866 | *width -= (uint32_t)crop_w; |
823 | 866 | *height -= (uint32_t)crop_h; |
824 | 866 | } |
825 | | |
826 | 7.48k | if (!reader.get_uvlc(&value)) { |
827 | 12 | return invalidUVLC; |
828 | 12 | } |
829 | 7.47k | if (value > 8) { |
830 | 17 | return Error{heif_error_Invalid_input, |
831 | 17 | heif_suberror_Invalid_parameter_value, |
832 | 17 | "SPS bit_depth_luma_minus8 out of range"}; |
833 | 17 | } |
834 | 7.45k | config->bit_depth_luma = (uint8_t) (value + 8); |
835 | | |
836 | 7.45k | if (!reader.get_uvlc(&value)) { |
837 | 13 | return invalidUVLC; |
838 | 13 | } |
839 | 7.44k | if (value > 8) { |
840 | 11 | return Error{heif_error_Invalid_input, |
841 | 11 | heif_suberror_Invalid_parameter_value, |
842 | 11 | "SPS bit_depth_chroma_minus8 out of range"}; |
843 | 11 | } |
844 | 7.43k | config->bit_depth_chroma = (uint8_t) (value + 8); |
845 | | |
846 | 7.43k | if (reader.get_bits_remaining() < 0) { |
847 | | // The reader returns zeros past the end, so a truncated SPS would |
848 | | // otherwise parse with made-up values. |
849 | 3 | return Error{heif_error_Invalid_input, |
850 | 3 | heif_suberror_End_of_data, |
851 | 3 | "SPS header is truncated"}; |
852 | 3 | } |
853 | | |
854 | | |
855 | | // --- init static configuration fields --- |
856 | | |
857 | 7.43k | config->configuration_version = 1; |
858 | 7.43k | config->min_spatial_segmentation_idc = 0; // TODO: get this value from the VUI, 0 should be safe |
859 | 7.43k | config->parallelism_type = 0; // TODO, 0 should be safe |
860 | 7.43k | config->avg_frame_rate = 0; // makes no sense for HEIF (TODO) |
861 | 7.43k | config->constant_frame_rate = 0; // makes no sense for HEIF (TODO) |
862 | 7.43k | config->num_temporal_layers = 1; // makes no sense for HEIF |
863 | | |
864 | 7.43k | return Error::Ok; |
865 | 7.43k | } |