Coverage Report

Created: 2026-05-24 07:45

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
23.8k
{
39
23.8k
  uint8_t byte;
40
41
23.8k
  configuration_version = range.read8();
42
23.8k
  byte = range.read8();
43
23.8k
  general_profile_space = (byte >> 6) & 3;
44
23.8k
  general_tier_flag = (byte >> 5) & 1;
45
23.8k
  general_profile_idc = (byte & 0x1F);
46
47
23.8k
  general_profile_compatibility_flags = range.read32();
48
49
167k
  for (int i = 0; i < 6; i++) {
50
143k
    byte = range.read8();
51
52
1.29M
    for (int b = 0; b < 8; b++) {
53
1.14M
      general_constraint_indicator_flags[i * 8 + b] = (byte >> (7 - b)) & 1;
54
1.14M
    }
55
143k
  }
56
57
23.8k
  general_level_idc = range.read8();
58
23.8k
  min_spatial_segmentation_idc = range.read16() & 0x0FFF;
59
23.8k
  parallelism_type = range.read8() & 0x03;
60
23.8k
  chroma_format = range.read8() & 0x03;
61
23.8k
  bit_depth_luma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
62
23.8k
  bit_depth_chroma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
63
23.8k
  avg_frame_rate = range.read16();
64
65
23.8k
  byte = range.read8();
66
23.8k
  constant_frame_rate = (byte >> 6) & 0x03;
67
23.8k
  num_temporal_layers = (byte >> 3) & 0x07;
68
23.8k
  temporal_id_nested = (byte >> 2) & 1;
69
70
23.8k
  m_length_size = static_cast<uint8_t>((byte & 0x03) + 1);
71
72
23.8k
  int nArrays = range.read8();
73
74
90.9k
  for (int i = 0; i < nArrays && !range.error(); i++) {
75
67.0k
    byte = range.read8();
76
77
67.0k
    NalArray array;
78
79
67.0k
    array.m_array_completeness = (byte >> 6) & 1;
80
67.0k
    array.m_NAL_unit_type = (byte & 0x3F);
81
82
67.0k
    int nUnits = range.read16();
83
135k
    for (int u = 0; u < nUnits && !range.error(); u++) {
84
85
68.4k
      std::vector<uint8_t> nal_unit;
86
68.4k
      int size = range.read16();
87
68.4k
      if (!size) {
88
        // Ignore empty NAL units.
89
4.43k
        continue;
90
4.43k
      }
91
92
64.0k
      if (range.prepare_read(size)) {
93
63.8k
        nal_unit.resize(size);
94
63.8k
        bool success = range.get_istream()->read((char*) nal_unit.data(), size);
95
63.8k
        if (!success) {
96
0
          return Error{heif_error_Invalid_input, heif_suberror_End_of_data, "error while reading hvcC box"};
97
0
        }
98
63.8k
      }
99
100
64.0k
      array.m_nal_units.push_back(std::move(nal_unit));
101
64.0k
    }
102
103
67.0k
    m_nal_array.push_back(std::move(array));
104
67.0k
  }
105
106
23.8k
  range.skip_to_end_of_box();
107
108
23.8k
  return range.get_error();
109
23.8k
}
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
      if (general_constraint_indicator_flags[i * 8 + b]) {
127
0
        byte |= 1;
128
0
      }
129
130
0
      byte = (uint8_t) (byte << 1);
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
Error Box_hvcC::parse(BitstreamRange& range, const heif_security_limits* limits)
195
23.8k
{
196
23.8k
  return m_configuration.parse(range, limits);
197
23.8k
}
198
199
200
std::string Box_hvcC::dump(Indent& indent) const
201
0
{
202
0
  std::ostringstream sstr;
203
0
  sstr << Box::dump(indent);
204
205
0
  const auto& c = m_configuration; // abbreviation
206
207
0
  sstr << indent << "configuration_version: " << ((int) c.configuration_version) << "\n"
208
0
       << indent << "general_profile_space: " << ((int) c.general_profile_space) << "\n"
209
0
       << indent << "general_tier_flag: " << c.general_tier_flag << "\n"
210
0
       << indent << "general_profile_idc: " << ((int) c.general_profile_idc) << "\n";
211
212
0
  sstr << indent << "general_profile_compatibility_flags: ";
213
0
  for (int i = 0; i < 32; i++) {
214
0
    sstr << ((c.general_profile_compatibility_flags >> (31 - i)) & 1);
215
0
    if ((i % 8) == 7) sstr << ' ';
216
0
    else if ((i % 4) == 3) sstr << '.';
217
0
  }
218
0
  sstr << "\n";
219
220
0
  sstr << indent << "general_constraint_indicator_flags: ";
221
0
  int cnt = 0;
222
0
  for (int i = 0; i < HEVCDecoderConfigurationRecord::NUM_CONSTRAINT_INDICATOR_FLAGS; i++) {
223
0
    bool b = c.general_constraint_indicator_flags[i];
224
225
0
    sstr << (b ? 1 : 0);
226
0
    cnt++;
227
0
    if ((cnt % 8) == 0)
228
0
      sstr << ' ';
229
0
  }
230
0
  sstr << "\n";
231
232
0
  sstr << indent << "general_level_idc: " << ((int) c.general_level_idc) << "\n"
233
0
       << indent << "min_spatial_segmentation_idc: " << c.min_spatial_segmentation_idc << "\n"
234
0
       << indent << "parallelism_type: " << ((int) c.parallelism_type) << "\n"
235
0
       << indent << "chroma_format: ";
236
237
0
  switch (c.chroma_format) {
238
0
    case 0:
239
0
      sstr << "monochrome";
240
0
      break;
241
0
    case 1:
242
0
      sstr << "4:2:0";
243
0
      break;
244
0
    case 2:
245
0
      sstr << "4:2:2";
246
0
      break;
247
0
    case 3:
248
0
      sstr << "4:4:4";
249
0
      break;
250
0
    default:
251
0
      sstr << ((int) c.chroma_format);
252
0
      break;
253
0
  }
254
255
0
  sstr << "\n"
256
0
       << indent << "bit_depth_luma: " << ((int) c.bit_depth_luma) << "\n"
257
0
       << indent << "bit_depth_chroma: " << ((int) c.bit_depth_chroma) << "\n"
258
0
       << indent << "avg_frame_rate: " << c.avg_frame_rate << "\n"
259
0
       << indent << "constant_frame_rate: " << ((int) c.constant_frame_rate) << "\n"
260
0
       << indent << "num_temporal_layers: " << ((int) c.num_temporal_layers) << "\n"
261
0
       << indent << "temporal_id_nested: " << ((int) c.temporal_id_nested) << "\n"
262
0
       << indent << "length_size: " << ((int) c.m_length_size) << "\n";
263
264
0
  for (const auto& array : c.m_nal_array) {
265
0
    sstr << indent << "<array>\n";
266
267
0
    indent++;
268
0
    sstr << indent << "array_completeness: " << ((int) array.m_array_completeness) << "\n"
269
0
         << indent << "NAL_unit_type: " << ((int) array.m_NAL_unit_type) << "\n";
270
271
0
    for (const auto& unit : array.m_nal_units) {
272
      //sstr << "  unit with " << unit.size() << " bytes of data\n";
273
0
      sstr << indent;
274
0
      for (uint8_t b : unit) {
275
0
        sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
276
0
      }
277
0
      sstr << "\n";
278
0
      sstr << std::dec;
279
0
    }
280
281
0
    indent--;
282
0
  }
283
284
0
  return sstr.str();
285
0
}
286
287
288
bool Box_hvcC::get_header_nals(std::vector<uint8_t>* dest) const
289
19.0k
{
290
  // Concatenate all header NALs, each prefixed by a 4-byte size.
291
292
56.4k
  for (const auto& array : m_configuration.m_nal_array) {
293
56.4k
    for (const auto& unit : array.m_nal_units) {
294
295
      // Write 4-byte NALs size
296
297
55.8k
      dest->push_back((unit.size() >> 24) & 0xFF);
298
55.8k
      dest->push_back((unit.size() >> 16) & 0xFF);
299
55.8k
      dest->push_back((unit.size() >> 8) & 0xFF);
300
55.8k
      dest->push_back((unit.size() >> 0) & 0xFF);
301
302
      // Copy NAL data
303
304
55.8k
      dest->insert(dest->end(), unit.begin(), unit.end());
305
55.8k
    }
306
56.4k
  }
307
308
19.0k
  return true;
309
19.0k
}
310
311
void Box_hvcC::append_nal_data(const uint8_t* data, size_t size)
312
0
{
313
0
  std::vector<uint8_t> nal;
314
0
  nal.resize(size);
315
0
  memcpy(nal.data(), data, size);
316
317
0
  append_nal_data(nal);
318
0
}
319
320
void Box_hvcC::append_nal_data(const std::vector<uint8_t>& nal)
321
0
{
322
0
  for (auto& nal_array : m_configuration.m_nal_array) {
323
0
    if (nal_array.m_NAL_unit_type == uint8_t(nal[0] >> 1)) {
324
325
      // kvazaar may send the same headers multiple times. Filter out the identical copies.
326
327
0
      for (auto& nal_unit : nal_array.m_nal_units) {
328
329
        // Note: sometimes kvazaar even sends the same packet twice, but with an extra zero byte.
330
        //       We detect this by comparing only the common length. This is correct since each NAL
331
        //       packet must be complete and thus, if a packet is longer than another complete packet,
332
        //       its extra data must be superfluous.
333
        //
334
        // Example:
335
        //| | | <array>
336
        //| | | | array_completeness: 1
337
        //| | | | NAL_unit_type: 34
338
        //| | | | 44 01 c1 71 82 99 20 00
339
        //| | | | 44 01 c1 71 82 99 20
340
341
        // Check whether packets have similar content.
342
343
0
        const size_t common_length = std::min(nal_unit.size(), nal.size());
344
0
        bool similar = true;
345
0
        for (size_t i = 0; i < common_length; i++) {
346
0
          if (nal_unit[i] != nal[i]) {
347
0
            similar = false;
348
0
            break;
349
0
          }
350
0
        }
351
352
0
        if (similar) {
353
          // If they are similar, keep the smaller one.
354
355
0
          if (nal_unit.size() > nal.size()) {
356
0
            nal_unit = std::move(nal);
357
0
          }
358
359
          // Exit. Do not add a copy of the packet.
360
361
0
          return;
362
0
        }
363
0
      }
364
365
0
      nal_array.m_nal_units.push_back(std::move(nal));
366
367
0
      return;
368
0
    }
369
0
  }
370
371
  // This is a new NAL type. Add a new NAL array.
372
373
0
  HEVCDecoderConfigurationRecord::NalArray array;
374
0
  array.m_array_completeness = 1;
375
0
  array.m_NAL_unit_type = uint8_t(nal[0] >> 1);
376
0
  array.m_nal_units.push_back(std::move(nal));
377
378
0
  m_configuration.m_nal_array.push_back(array);
379
0
}
380
381
382
Error Box_hvcC::write(StreamWriter& writer) const
383
0
{
384
0
  size_t box_start = reserve_box_header_space(writer);
385
386
0
  const auto& c = m_configuration; // abbreviation
387
388
0
  Error err = c.write(writer);
389
0
  if (err) {
390
0
    return err;
391
0
  }
392
393
0
  prepend_header(writer, box_start);
394
395
0
  return Error::Ok;
396
0
}
397
398
399
static double read_depth_rep_info_element(BitReader& reader)
400
0
{
401
0
  uint8_t sign_flag = reader.get_bits8(1);
402
0
  int exponent = reader.get_bits(7);
403
0
  auto mantissa_len = static_cast<uint8_t>(reader.get_bits8(5) + 1);
404
0
  if (mantissa_len < 1 || mantissa_len > 32) {
405
    // TODO err
406
0
  }
407
408
0
  if (exponent == 127) {
409
    // TODO value unspecified
410
0
  }
411
412
0
  uint32_t mantissa = reader.get_bits32(mantissa_len);
413
0
  double value;
414
415
  //printf("sign:%d exponent:%d mantissa_len:%d mantissa:%d\n",sign_flag,exponent,mantissa_len,mantissa);
416
417
  // TODO: this seems to be wrong. 'exponent' is never negative. How to read it correctly?
418
0
  if (exponent > 0) {
419
0
    value = pow(2.0, exponent - 31) * (1.0 + mantissa / pow(2.0, mantissa_len));
420
0
  }
421
0
  else {
422
0
    value = pow(2.0, -(30 + mantissa_len)) * mantissa;
423
0
  }
424
425
0
  if (sign_flag) {
426
0
    value = -value;
427
0
  }
428
429
0
  return value;
430
0
}
431
432
433
static Result<std::shared_ptr<SEIMessage>> read_depth_representation_info(BitReader& reader)
434
0
{
435
0
  auto msg = std::make_shared<SEIMessage_depth_representation_info>();
436
437
438
  // default values
439
440
0
  msg->version = 1;
441
442
0
  msg->disparity_reference_view = 0;
443
0
  msg->depth_nonlinear_representation_model_size = 0;
444
0
  msg->depth_nonlinear_representation_model = nullptr;
445
446
447
  // read header
448
449
0
  msg->has_z_near = (uint8_t) reader.get_bits(1);
450
0
  msg->has_z_far = (uint8_t) reader.get_bits(1);
451
0
  msg->has_d_min = (uint8_t) reader.get_bits(1);
452
0
  msg->has_d_max = (uint8_t) reader.get_bits(1);
453
454
0
  uint32_t rep_type;
455
0
  if (!reader.get_uvlc(&rep_type)) {
456
0
    return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "invalid depth representation type in input"};
457
0
  }
458
459
0
  if (rep_type > 3) {
460
0
    return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "input depth representation type out of range"};
461
0
  }
462
463
0
  msg->depth_representation_type = (enum heif_depth_representation_type) rep_type;
464
465
  //printf("flags: %d %d %d %d\n",msg->has_z_near,msg->has_z_far,msg->has_d_min,msg->has_d_max);
466
  //printf("type: %d\n",rep_type);
467
468
0
  if (msg->has_d_min || msg->has_d_max) {
469
0
    uint32_t ref_view;
470
0
    if (!reader.get_uvlc(&ref_view)) {
471
0
      return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "invalid disparity_reference_view in input"};
472
0
    }
473
0
    msg->disparity_reference_view = ref_view;
474
475
    //printf("ref_view: %d\n",msg->disparity_reference_view);
476
0
  }
477
478
0
  if (msg->has_z_near) msg->z_near = read_depth_rep_info_element(reader);
479
0
  if (msg->has_z_far) msg->z_far = read_depth_rep_info_element(reader);
480
0
  if (msg->has_d_min) msg->d_min = read_depth_rep_info_element(reader);
481
0
  if (msg->has_d_max) msg->d_max = read_depth_rep_info_element(reader);
482
483
  /*
484
  printf("z_near: %f\n",msg->z_near);
485
  printf("z_far: %f\n",msg->z_far);
486
  printf("dmin: %f\n",msg->d_min);
487
  printf("dmax: %f\n",msg->d_max);
488
  */
489
490
0
  if (msg->depth_representation_type == heif_depth_representation_type_nonuniform_disparity) {
491
    // TODO: load non-uniform response curve
492
0
  }
493
494
0
  return {msg};
495
0
}
496
497
498
// aux subtypes: 00 00 00 11 / 00 00 00 0d / 4e 01 / b1 09 / 35 1e 78 c8 01 03 c5 d0 20
499
500
Error decode_hevc_aux_sei_messages(const std::vector<uint8_t>& data,
501
                                   std::vector<std::shared_ptr<SEIMessage>>& msgs)
502
22
{
503
  // TODO: we probably do not need a full BitReader just for the array size.
504
  // Read this and the NAL size directly on the array data.
505
506
22
  BitReader reader(data.data(), (int) data.size());
507
22
  if (reader.get_bits_remaining() < 32) {
508
0
    return {heif_error_Invalid_input,
509
0
            heif_suberror_End_of_data,
510
0
            "HEVC SEI NAL too short"};
511
0
  }
512
513
22
  uint32_t len = reader.get_bits32(32);
514
515
22
  if (len > data.size() - 4) {
516
    // ERROR: read past end of data
517
20
  }
518
519
22
  while (reader.get_current_byte_index() < (int) len) {
520
14
    int currPos = reader.get_current_byte_index();
521
522
14
    BitReader sei_reader(data.data() + currPos, (int) data.size() - currPos);
523
524
14
    if (sei_reader.get_bits_remaining() < 32+8) {
525
0
      return {heif_error_Invalid_input,
526
0
              heif_suberror_End_of_data,
527
0
              "HEVC SEI NAL too short"};
528
0
    }
529
530
14
    uint32_t nal_size = sei_reader.get_bits32(32);
531
14
    (void) nal_size;
532
533
14
    auto nal_type = static_cast<uint8_t>(sei_reader.get_bits8(8) >> 1);
534
14
    sei_reader.skip_bits(8);
535
536
    // SEI
537
538
14
    if (nal_type == 39 ||
539
14
        nal_type == 40) {
540
541
6
      if (sei_reader.get_bits_remaining() < 16) {
542
0
        return {heif_error_Invalid_input,
543
0
                heif_suberror_End_of_data,
544
0
                "HEVC SEI NAL too short"};
545
0
      }
546
547
      // TODO: loading of multi-byte sei headers
548
6
      uint8_t payload_id = sei_reader.get_bits8(8);
549
6
      uint8_t payload_size = sei_reader.get_bits8(8);
550
6
      (void) payload_size;
551
552
6
      if (payload_id == 177) {
553
        // depth_representation_info
554
0
        Result<std::shared_ptr<SEIMessage>> seiResult = read_depth_representation_info(sei_reader);
555
0
        if (!seiResult) {
556
0
          return seiResult.error();
557
0
        }
558
559
0
        msgs.push_back(*seiResult);
560
0
      }
561
6
    }
562
563
14
    break; // TODO: read next SEI
564
14
  }
565
566
567
22
  return Error::Ok;
568
22
}
569
570
571
// Used for AVC, HEVC, and VVC.
572
std::vector<uint8_t> remove_start_code_emulation(const uint8_t* sps, size_t size)
573
20.0k
{
574
20.0k
  std::vector<uint8_t> out_data;
575
576
764k
  for (size_t i = 0; i < size; i++) {
577
744k
    if (i + 2 < size &&
578
704k
        sps[i] == 0 &&
579
163k
        sps[i + 1] == 0 &&
580
94.6k
        sps[i + 2] == 3) {
581
70.6k
      out_data.push_back(0);
582
70.6k
      out_data.push_back(0);
583
70.6k
      i += 2;
584
70.6k
    }
585
674k
    else {
586
674k
      out_data.push_back(sps[i]);
587
674k
    }
588
744k
  }
589
590
20.0k
  return out_data;
591
20.0k
}
592
593
594
Error parse_sps_for_hvcC_configuration(const uint8_t* sps, size_t size,
595
                                       HEVCDecoderConfigurationRecord* config,
596
                                       uint32_t* width, uint32_t* height,
597
                                       ImageSize* coded_size)
598
18.8k
{
599
  // remove start-code emulation bytes from SPS header stream
600
601
18.8k
  std::vector<uint8_t> sps_no_emul = remove_start_code_emulation(sps, size);
602
603
18.8k
  sps = sps_no_emul.data();
604
18.8k
  size = sps_no_emul.size();
605
606
607
18.8k
  BitReader reader(sps, (int) size);
608
609
  // skip NAL header
610
18.8k
  reader.skip_bits(2 * 8);
611
612
  // skip VPS ID
613
18.8k
  reader.skip_bits(4);
614
615
18.8k
  uint8_t nMaxSubLayersMinus1 = reader.get_bits8(3);
616
617
18.8k
  config->temporal_id_nested = reader.get_bits8(1);
618
619
  // --- profile_tier_level ---
620
621
18.8k
  config->general_profile_space = reader.get_bits8(2);
622
18.8k
  config->general_tier_flag = reader.get_bits8(1);
623
18.8k
  config->general_profile_idc = reader.get_bits8(5);
624
18.8k
  config->general_profile_compatibility_flags = reader.get_bits32(32);
625
626
18.8k
  reader.skip_bits(16); // skip reserved bits
627
18.8k
  reader.skip_bits(16); // skip reserved bits
628
18.8k
  reader.skip_bits(16); // skip reserved bits
629
630
18.8k
  config->general_level_idc = reader.get_bits8(8);
631
632
18.8k
  std::vector<bool> layer_profile_present(nMaxSubLayersMinus1);
633
18.8k
  std::vector<bool> layer_level_present(nMaxSubLayersMinus1);
634
635
19.8k
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
636
1.01k
    layer_profile_present[i] = reader.get_bits(1);
637
1.01k
    layer_level_present[i] = reader.get_bits(1);
638
1.01k
  }
639
640
18.8k
  if (nMaxSubLayersMinus1 > 0) {
641
2.44k
    for (int i = nMaxSubLayersMinus1; i < 8; i++) {
642
2.06k
      reader.skip_bits(2);
643
2.06k
    }
644
385
  }
645
646
19.8k
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
647
1.01k
    if (layer_profile_present[i]) {
648
256
      reader.skip_bits(2 + 1 + 5);
649
256
      reader.skip_bits(32);
650
256
      reader.skip_bits(16);
651
256
    }
652
653
1.01k
    if (layer_level_present[i]) {
654
202
      reader.skip_bits(8);
655
202
    }
656
1.01k
  }
657
658
659
  // --- SPS continued ---
660
661
18.8k
  Error invalidUVLC{
662
18.8k
    heif_error_Invalid_input,
663
18.8k
    heif_suberror_Invalid_parameter_value,
664
18.8k
    "Invalid variable length code in HEVC SPS header"
665
18.8k
  };
666
667
18.8k
  uint32_t dummy, value;
668
18.8k
  if (!reader.get_uvlc(&dummy) || // skip seq_parameter_seq_id
669
18.7k
      !reader.get_uvlc(&value)) {
670
110
    return invalidUVLC;
671
110
  }
672
18.7k
  config->chroma_format = (uint8_t) value;
673
674
18.7k
  if (config->chroma_format == 3) {
675
7.05k
    reader.skip_bits(1);
676
7.05k
  }
677
678
18.7k
  if (!reader.get_uvlc(width) ||
679
18.7k
      !reader.get_uvlc(height)) {
680
38
    return invalidUVLC;
681
38
  }
682
683
18.6k
  if (coded_size) {
684
18.6k
    coded_size->width = *width;
685
18.6k
    coded_size->height = *height;
686
18.6k
  }
687
688
18.6k
  bool conformance_window = reader.get_bits(1);
689
18.6k
  if (conformance_window) {
690
6.14k
    uint32_t left, right, top, bottom;
691
6.14k
    if (!reader.get_uvlc(&left) ||
692
6.13k
        !reader.get_uvlc(&right) ||
693
6.12k
        !reader.get_uvlc(&top) ||
694
6.10k
        !reader.get_uvlc(&bottom)) {
695
42
      return invalidUVLC;
696
42
    }
697
698
    //printf("conformance borders: %u %u %u %u\n",left,right,top,bottom);
699
700
6.10k
    uint32_t subH = 1, subV = 1;
701
6.10k
    if (config->chroma_format == 1) {
702
5.53k
      subV = 2;
703
5.53k
      subH = 2;
704
5.53k
    }
705
6.10k
    if (config->chroma_format == 2) { subH = 2; }
706
707
6.10k
    const uint64_t crop_w = (uint64_t)subH * ((uint64_t)left + (uint64_t)right);
708
6.10k
    const uint64_t crop_h = (uint64_t)subV * ((uint64_t)top + (uint64_t)bottom);
709
6.10k
    if (crop_w > *width || crop_h > *height) {
710
121
      return Error{heif_error_Invalid_input,
711
121
                   heif_suberror_Invalid_parameter_value,
712
121
                   "SPS conformance window exceeds image dimensions"};
713
121
    }
714
5.98k
    *width  -= (uint32_t)crop_w;
715
5.98k
    *height -= (uint32_t)crop_h;
716
5.98k
  }
717
718
18.5k
  if (!reader.get_uvlc(&value)) {
719
19
    return invalidUVLC;
720
19
  }
721
18.5k
  if (value > 8) {
722
133
    return Error{heif_error_Invalid_input,
723
133
                 heif_suberror_Invalid_parameter_value,
724
133
                 "SPS bit_depth_luma_minus8 out of range"};
725
133
  }
726
18.3k
  config->bit_depth_luma = (uint8_t) (value + 8);
727
728
18.3k
  if (!reader.get_uvlc(&value)) {
729
8
    return invalidUVLC;
730
8
  }
731
18.3k
  if (value > 8) {
732
68
    return Error{heif_error_Invalid_input,
733
68
                 heif_suberror_Invalid_parameter_value,
734
68
                 "SPS bit_depth_chroma_minus8 out of range"};
735
68
  }
736
18.3k
  config->bit_depth_chroma = (uint8_t) (value + 8);
737
738
739
740
  // --- init static configuration fields ---
741
742
18.3k
  config->configuration_version = 1;
743
18.3k
  config->min_spatial_segmentation_idc = 0; // TODO: get this value from the VUI, 0 should be safe
744
18.3k
  config->parallelism_type = 0; // TODO, 0 should be safe
745
18.3k
  config->avg_frame_rate = 0; // makes no sense for HEIF (TODO)
746
18.3k
  config->constant_frame_rate = 0; // makes no sense for HEIF (TODO)
747
18.3k
  config->num_temporal_layers = 1; // makes no sense for HEIF
748
749
18.3k
  return Error::Ok;
750
18.3k
}