Coverage Report

Created: 2025-08-11 08:01

/src/libheif/libheif/codecs/hevc_boxes.cc
Line
Count
Source (jump to first uncovered line)
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
10.7k
{
39
10.7k
  uint8_t byte;
40
41
10.7k
  configuration_version = range.read8();
42
10.7k
  byte = range.read8();
43
10.7k
  general_profile_space = (byte >> 6) & 3;
44
10.7k
  general_tier_flag = (byte >> 5) & 1;
45
10.7k
  general_profile_idc = (byte & 0x1F);
46
47
10.7k
  general_profile_compatibility_flags = range.read32();
48
49
75.4k
  for (int i = 0; i < 6; i++) {
50
64.7k
    byte = range.read8();
51
52
582k
    for (int b = 0; b < 8; b++) {
53
517k
      general_constraint_indicator_flags[i * 8 + b] = (byte >> (7 - b)) & 1;
54
517k
    }
55
64.7k
  }
56
57
10.7k
  general_level_idc = range.read8();
58
10.7k
  min_spatial_segmentation_idc = range.read16() & 0x0FFF;
59
10.7k
  parallelism_type = range.read8() & 0x03;
60
10.7k
  chroma_format = range.read8() & 0x03;
61
10.7k
  bit_depth_luma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
62
10.7k
  bit_depth_chroma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
63
10.7k
  avg_frame_rate = range.read16();
64
65
10.7k
  byte = range.read8();
66
10.7k
  constant_frame_rate = (byte >> 6) & 0x03;
67
10.7k
  num_temporal_layers = (byte >> 3) & 0x07;
68
10.7k
  temporal_id_nested = (byte >> 2) & 1;
69
70
10.7k
  m_length_size = static_cast<uint8_t>((byte & 0x03) + 1);
71
72
10.7k
  int nArrays = range.read8();
73
74
42.1k
  for (int i = 0; i < nArrays && !range.error(); i++) {
75
31.3k
    byte = range.read8();
76
77
31.3k
    NalArray array;
78
79
31.3k
    array.m_array_completeness = (byte >> 6) & 1;
80
31.3k
    array.m_NAL_unit_type = (byte & 0x3F);
81
82
31.3k
    int nUnits = range.read16();
83
63.7k
    for (int u = 0; u < nUnits && !range.error(); u++) {
84
85
32.3k
      std::vector<uint8_t> nal_unit;
86
32.3k
      int size = range.read16();
87
32.3k
      if (!size) {
88
        // Ignore empty NAL units.
89
1.96k
        continue;
90
1.96k
      }
91
92
30.4k
      if (range.prepare_read(size)) {
93
30.3k
        nal_unit.resize(size);
94
30.3k
        bool success = range.get_istream()->read((char*) nal_unit.data(), size);
95
30.3k
        if (!success) {
96
0
          return Error{heif_error_Invalid_input, heif_suberror_End_of_data, "error while reading hvcC box"};
97
0
        }
98
30.3k
      }
99
100
30.4k
      array.m_nal_units.push_back(std::move(nal_unit));
101
30.4k
    }
102
103
31.3k
    m_nal_array.push_back(std::move(array));
104
31.3k
  }
105
106
10.7k
  range.skip_to_end_of_box();
107
108
10.7k
  return range.get_error();
109
10.7k
}
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
0
  if (nArrays > 0xFF) {
151
    // TODO: error: too many NAL units
152
0
  }
153
154
0
  writer.write8((uint8_t) nArrays);
155
156
0
  for (const HEVCDecoderConfigurationRecord::NalArray& array : m_nal_array) {
157
158
0
    writer.write8((uint8_t) (((array.m_array_completeness & 1) << 6) |
159
0
                             (array.m_NAL_unit_type & 0x3F)));
160
161
0
    size_t nUnits = array.m_nal_units.size();
162
0
    if (nUnits > 0xFFFF) {
163
      // TODO: error: too many NAL units
164
0
    }
165
166
0
    writer.write16((uint16_t) nUnits);
167
168
0
    for (const std::vector<uint8_t>& nal_unit : array.m_nal_units) {
169
0
      writer.write16((uint16_t) nal_unit.size());
170
0
      writer.write(nal_unit);
171
0
    }
172
0
  }
173
174
0
  return Error::Ok;
175
0
}
176
177
178
bool HEVCDecoderConfigurationRecord::get_general_profile_compatibility_flag(int idx) const
179
0
{
180
0
  return general_profile_compatibility_flags & (UINT32_C(0x80000000) >> idx);
181
0
}
182
183
184
bool HEVCDecoderConfigurationRecord::is_profile_compatibile(Profile profile) const
185
0
{
186
0
  return (general_profile_idc == profile ||
187
0
          get_general_profile_compatibility_flag(profile));
188
0
}
189
190
191
Error Box_hvcC::parse(BitstreamRange& range, const heif_security_limits* limits)
192
10.7k
{
193
  //parse_full_box_header(range);
194
195
10.7k
  return m_configuration.parse(range, limits);
196
10.7k
}
197
198
199
std::string Box_hvcC::dump(Indent& indent) const
200
0
{
201
0
  std::ostringstream sstr;
202
0
  sstr << Box::dump(indent);
203
204
0
  const auto& c = m_configuration; // abbreviation
205
206
0
  sstr << indent << "configuration_version: " << ((int) c.configuration_version) << "\n"
207
0
       << indent << "general_profile_space: " << ((int) c.general_profile_space) << "\n"
208
0
       << indent << "general_tier_flag: " << c.general_tier_flag << "\n"
209
0
       << indent << "general_profile_idc: " << ((int) c.general_profile_idc) << "\n";
210
211
0
  sstr << indent << "general_profile_compatibility_flags: ";
212
0
  for (int i = 0; i < 32; i++) {
213
0
    sstr << ((c.general_profile_compatibility_flags >> (31 - i)) & 1);
214
0
    if ((i % 8) == 7) sstr << ' ';
215
0
    else if ((i % 4) == 3) sstr << '.';
216
0
  }
217
0
  sstr << "\n";
218
219
0
  sstr << indent << "general_constraint_indicator_flags: ";
220
0
  int cnt = 0;
221
0
  for (int i = 0; i < HEVCDecoderConfigurationRecord::NUM_CONSTRAINT_INDICATOR_FLAGS; i++) {
222
0
    bool b = c.general_constraint_indicator_flags[i];
223
224
0
    sstr << (b ? 1 : 0);
225
0
    cnt++;
226
0
    if ((cnt % 8) == 0)
227
0
      sstr << ' ';
228
0
  }
229
0
  sstr << "\n";
230
231
0
  sstr << indent << "general_level_idc: " << ((int) c.general_level_idc) << "\n"
232
0
       << indent << "min_spatial_segmentation_idc: " << c.min_spatial_segmentation_idc << "\n"
233
0
       << indent << "parallelism_type: " << ((int) c.parallelism_type) << "\n"
234
0
       << indent << "chroma_format: ";
235
236
0
  switch (c.chroma_format) {
237
0
    case 1:
238
0
      sstr << "4:2:0";
239
0
      break;
240
0
    case 2:
241
0
      sstr << "4:2:2";
242
0
      break;
243
0
    case 3:
244
0
      sstr << "4:4:4";
245
0
      break;
246
0
    default:
247
0
      sstr << ((int) c.chroma_format);
248
0
      break;
249
0
  }
250
251
0
  sstr << "\n"
252
0
       << indent << "bit_depth_luma: " << ((int) c.bit_depth_luma) << "\n"
253
0
       << indent << "bit_depth_chroma: " << ((int) c.bit_depth_chroma) << "\n"
254
0
       << indent << "avg_frame_rate: " << c.avg_frame_rate << "\n"
255
0
       << indent << "constant_frame_rate: " << ((int) c.constant_frame_rate) << "\n"
256
0
       << indent << "num_temporal_layers: " << ((int) c.num_temporal_layers) << "\n"
257
0
       << indent << "temporal_id_nested: " << ((int) c.temporal_id_nested) << "\n"
258
0
       << indent << "length_size: " << ((int) c.m_length_size) << "\n";
259
260
0
  for (const auto& array : c.m_nal_array) {
261
0
    sstr << indent << "<array>\n";
262
263
0
    indent++;
264
0
    sstr << indent << "array_completeness: " << ((int) array.m_array_completeness) << "\n"
265
0
         << indent << "NAL_unit_type: " << ((int) array.m_NAL_unit_type) << "\n";
266
267
0
    for (const auto& unit : array.m_nal_units) {
268
      //sstr << "  unit with " << unit.size() << " bytes of data\n";
269
0
      sstr << indent;
270
0
      for (uint8_t b : unit) {
271
0
        sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
272
0
      }
273
0
      sstr << "\n";
274
0
      sstr << std::dec;
275
0
    }
276
277
0
    indent--;
278
0
  }
279
280
0
  return sstr.str();
281
0
}
282
283
284
bool Box_hvcC::get_headers(std::vector<uint8_t>* dest) const
285
8.82k
{
286
26.3k
  for (const auto& array : m_configuration.m_nal_array) {
287
26.3k
    for (const auto& unit : array.m_nal_units) {
288
289
26.0k
      dest->push_back((unit.size() >> 24) & 0xFF);
290
26.0k
      dest->push_back((unit.size() >> 16) & 0xFF);
291
26.0k
      dest->push_back((unit.size() >> 8) & 0xFF);
292
26.0k
      dest->push_back((unit.size() >> 0) & 0xFF);
293
294
      /*
295
      dest->push_back(0);
296
      dest->push_back(0);
297
      dest->push_back(1);
298
      */
299
300
26.0k
      dest->insert(dest->end(), unit.begin(), unit.end());
301
26.0k
    }
302
26.3k
  }
303
304
8.82k
  return true;
305
8.82k
}
306
307
308
void Box_hvcC::append_nal_data(const std::vector<uint8_t>& nal)
309
0
{
310
0
  HEVCDecoderConfigurationRecord::NalArray array;
311
0
  array.m_array_completeness = 0;
312
0
  array.m_NAL_unit_type = uint8_t(nal[0] >> 1);
313
0
  array.m_nal_units.push_back(nal);
314
315
0
  m_configuration.m_nal_array.push_back(array);
316
0
}
317
318
void Box_hvcC::append_nal_data(const uint8_t* data, size_t size)
319
0
{
320
0
  std::vector<uint8_t> nal;
321
0
  nal.resize(size);
322
0
  memcpy(nal.data(), data, size);
323
324
0
  for (auto& nal_array : m_configuration.m_nal_array) {
325
0
    if (nal_array.m_NAL_unit_type == uint8_t(nal[0] >> 1)) {
326
327
      // kvazaar may send the same headers multiple times. Filter out the identical copies.
328
329
0
      for (auto& nal_unit : nal_array.m_nal_units) {
330
331
        // Note: sometimes kvazaar even sends the same packet twice, but with an extra zero byte.
332
        //       We detect this by comparing only the common length. This is correct since each NAL
333
        //       packet must be complete and thus, if a packet is longer than another complete packet,
334
        //       its extra data must be superfluous.
335
        //
336
        // Example:
337
        //| | | <array>
338
        //| | | | array_completeness: 1
339
        //| | | | NAL_unit_type: 34
340
        //| | | | 44 01 c1 71 82 99 20 00
341
        //| | | | 44 01 c1 71 82 99 20
342
343
        // Check whether packets have similar content.
344
345
0
        size_t common_length = std::min(nal_unit.size(), nal.size());
346
0
        bool similar = true;
347
0
        for (size_t i = 0; i < common_length; i++) {
348
0
          if (nal_unit[i] != nal[i]) {
349
0
            similar = false;
350
0
            break;
351
0
          }
352
0
        }
353
354
0
        if (similar) {
355
          // If they are similar, keep the smaller one.
356
357
0
          if (nal_unit.size() > nal.size()) {
358
0
            nal_unit = std::move(nal);
359
0
          }
360
361
          // Exit. Do not add a copy of the packet.
362
363
0
          return;
364
0
        }
365
0
      }
366
367
0
      nal_array.m_nal_units.push_back(std::move(nal));
368
369
0
      return;
370
0
    }
371
0
  }
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
  int 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 < 0 || 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
    int 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
0
{
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
0
  BitReader reader(data.data(), (int) data.size());
507
0
  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
0
  uint32_t len = reader.get_bits32(32);
514
515
0
  if (len > data.size() - 4) {
516
    // ERROR: read past end of data
517
0
  }
518
519
0
  while (reader.get_current_byte_index() < (int) len) {
520
0
    int currPos = reader.get_current_byte_index();
521
522
0
    BitReader sei_reader(data.data() + currPos, (int) data.size() - currPos);
523
524
0
    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
0
    uint32_t nal_size = sei_reader.get_bits32(32);
531
0
    (void) nal_size;
532
533
0
    auto nal_type = static_cast<uint8_t>(sei_reader.get_bits8(8) >> 1);
534
0
    sei_reader.skip_bits(8);
535
536
    // SEI
537
538
0
    if (nal_type == 39 ||
539
0
        nal_type == 40) {
540
541
0
      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
0
      uint8_t payload_id = sei_reader.get_bits8(8);
549
0
      uint8_t payload_size = sei_reader.get_bits8(8);
550
0
      (void) payload_size;
551
552
0
      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
0
    }
562
563
0
    break; // TODO: read next SEI
564
0
  }
565
566
567
0
  return Error::Ok;
568
0
}
569
570
571
static std::vector<uint8_t> remove_start_code_emulation(const uint8_t* sps, size_t size)
572
0
{
573
0
  std::vector<uint8_t> out_data;
574
575
0
  for (size_t i = 0; i < size; i++) {
576
0
    if (i + 2 < size &&
577
0
        sps[i] == 0 &&
578
0
        sps[i + 1] == 0 &&
579
0
        sps[i + 2] == 3) {
580
0
      out_data.push_back(0);
581
0
      out_data.push_back(0);
582
0
      i += 2;
583
0
    }
584
0
    else {
585
0
      out_data.push_back(sps[i]);
586
0
    }
587
0
  }
588
589
0
  return out_data;
590
0
}
591
592
593
Error parse_sps_for_hvcC_configuration(const uint8_t* sps, size_t size,
594
                                       HEVCDecoderConfigurationRecord* config,
595
                                       int* width, int* height)
596
0
{
597
  // remove start-code emulation bytes from SPS header stream
598
599
0
  std::vector<uint8_t> sps_no_emul = remove_start_code_emulation(sps, size);
600
601
0
  sps = sps_no_emul.data();
602
0
  size = sps_no_emul.size();
603
604
605
0
  BitReader reader(sps, (int) size);
606
607
  // skip NAL header
608
0
  reader.skip_bits(2 * 8);
609
610
  // skip VPS ID
611
0
  reader.skip_bits(4);
612
613
0
  uint8_t nMaxSubLayersMinus1 = reader.get_bits8(3);
614
615
0
  config->temporal_id_nested = reader.get_bits8(1);
616
617
  // --- profile_tier_level ---
618
619
0
  config->general_profile_space = reader.get_bits8(2);
620
0
  config->general_tier_flag = reader.get_bits8(1);
621
0
  config->general_profile_idc = reader.get_bits8(5);
622
0
  config->general_profile_compatibility_flags = reader.get_bits32(32);
623
624
0
  reader.skip_bits(16); // skip reserved bits
625
0
  reader.skip_bits(16); // skip reserved bits
626
0
  reader.skip_bits(16); // skip reserved bits
627
628
0
  config->general_level_idc = reader.get_bits8(8);
629
630
0
  std::vector<bool> layer_profile_present(nMaxSubLayersMinus1);
631
0
  std::vector<bool> layer_level_present(nMaxSubLayersMinus1);
632
633
0
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
634
0
    layer_profile_present[i] = reader.get_bits(1);
635
0
    layer_level_present[i] = reader.get_bits(1);
636
0
  }
637
638
0
  if (nMaxSubLayersMinus1 > 0) {
639
0
    for (int i = nMaxSubLayersMinus1; i < 8; i++) {
640
0
      reader.skip_bits(2);
641
0
    }
642
0
  }
643
644
0
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
645
0
    if (layer_profile_present[i]) {
646
0
      reader.skip_bits(2 + 1 + 5);
647
0
      reader.skip_bits(32);
648
0
      reader.skip_bits(16);
649
0
    }
650
651
0
    if (layer_level_present[i]) {
652
0
      reader.skip_bits(8);
653
0
    }
654
0
  }
655
656
657
  // --- SPS continued ---
658
659
0
  int dummy, value;
660
0
  reader.get_uvlc(&dummy); // skip seq_parameter_seq_id
661
662
0
  reader.get_uvlc(&value);
663
0
  config->chroma_format = (uint8_t) value;
664
665
0
  if (config->chroma_format == 3) {
666
0
    reader.skip_bits(1);
667
0
  }
668
669
0
  reader.get_uvlc(width);
670
0
  reader.get_uvlc(height);
671
672
0
  bool conformance_window = reader.get_bits(1);
673
0
  if (conformance_window) {
674
0
    int left, right, top, bottom;
675
0
    reader.get_uvlc(&left);
676
0
    reader.get_uvlc(&right);
677
0
    reader.get_uvlc(&top);
678
0
    reader.get_uvlc(&bottom);
679
680
    //printf("conformance borders: %d %d %d %d\n",left,right,top,bottom);
681
682
0
    int subH = 1, subV = 1;
683
0
    if (config->chroma_format == 1) {
684
0
      subV = 2;
685
0
      subH = 2;
686
0
    }
687
0
    if (config->chroma_format == 2) { subH = 2; }
688
689
0
    *width -= subH * (left + right);
690
0
    *height -= subV * (top + bottom);
691
0
  }
692
693
0
  reader.get_uvlc(&value);
694
0
  config->bit_depth_luma = (uint8_t) (value + 8);
695
696
0
  reader.get_uvlc(&value);
697
0
  config->bit_depth_chroma = (uint8_t) (value + 8);
698
699
700
701
  // --- init static configuration fields ---
702
703
0
  config->configuration_version = 1;
704
0
  config->min_spatial_segmentation_idc = 0; // TODO: get this value from the VUI, 0 should be safe
705
0
  config->parallelism_type = 0; // TODO, 0 should be safe
706
0
  config->avg_frame_rate = 0; // makes no sense for HEIF
707
0
  config->constant_frame_rate = 0; // makes no sense for HEIF
708
0
  config->num_temporal_layers = 1; // makes no sense for HEIF
709
710
0
  return Error::Ok;
711
0
}