Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}