Coverage Report

Created: 2026-04-01 07:24

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
8.24k
{
39
8.24k
  uint8_t byte;
40
41
8.24k
  configuration_version = range.read8();
42
8.24k
  byte = range.read8();
43
8.24k
  general_profile_space = (byte >> 6) & 3;
44
8.24k
  general_tier_flag = (byte >> 5) & 1;
45
8.24k
  general_profile_idc = (byte & 0x1F);
46
47
8.24k
  general_profile_compatibility_flags = range.read32();
48
49
57.7k
  for (int i = 0; i < 6; i++) {
50
49.4k
    byte = range.read8();
51
52
445k
    for (int b = 0; b < 8; b++) {
53
395k
      general_constraint_indicator_flags[i * 8 + b] = (byte >> (7 - b)) & 1;
54
395k
    }
55
49.4k
  }
56
57
8.24k
  general_level_idc = range.read8();
58
8.24k
  min_spatial_segmentation_idc = range.read16() & 0x0FFF;
59
8.24k
  parallelism_type = range.read8() & 0x03;
60
8.24k
  chroma_format = range.read8() & 0x03;
61
8.24k
  bit_depth_luma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
62
8.24k
  bit_depth_chroma = static_cast<uint8_t>((range.read8() & 0x07) + 8);
63
8.24k
  avg_frame_rate = range.read16();
64
65
8.24k
  byte = range.read8();
66
8.24k
  constant_frame_rate = (byte >> 6) & 0x03;
67
8.24k
  num_temporal_layers = (byte >> 3) & 0x07;
68
8.24k
  temporal_id_nested = (byte >> 2) & 1;
69
70
8.24k
  m_length_size = static_cast<uint8_t>((byte & 0x03) + 1);
71
72
8.24k
  int nArrays = range.read8();
73
74
31.2k
  for (int i = 0; i < nArrays && !range.error(); i++) {
75
23.0k
    byte = range.read8();
76
77
23.0k
    NalArray array;
78
79
23.0k
    array.m_array_completeness = (byte >> 6) & 1;
80
23.0k
    array.m_NAL_unit_type = (byte & 0x3F);
81
82
23.0k
    int nUnits = range.read16();
83
45.8k
    for (int u = 0; u < nUnits && !range.error(); u++) {
84
85
22.8k
      std::vector<uint8_t> nal_unit;
86
22.8k
      int size = range.read16();
87
22.8k
      if (!size) {
88
        // Ignore empty NAL units.
89
314
        continue;
90
314
      }
91
92
22.5k
      if (range.prepare_read(size)) {
93
22.5k
        nal_unit.resize(size);
94
22.5k
        bool success = range.get_istream()->read((char*) nal_unit.data(), size);
95
22.5k
        if (!success) {
96
0
          return Error{heif_error_Invalid_input, heif_suberror_End_of_data, "error while reading hvcC box"};
97
0
        }
98
22.5k
      }
99
100
22.5k
      array.m_nal_units.push_back(std::move(nal_unit));
101
22.5k
    }
102
103
23.0k
    m_nal_array.push_back(std::move(array));
104
23.0k
  }
105
106
8.24k
  range.skip_to_end_of_box();
107
108
8.24k
  return range.get_error();
109
8.24k
}
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_compatibile(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
8.24k
{
196
8.24k
  return m_configuration.parse(range, limits);
197
8.24k
}
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
5.81k
{
290
  // Concatenate all header NALs, each prefixed by a 4-byte size.
291
292
17.3k
  for (const auto& array : m_configuration.m_nal_array) {
293
17.3k
    for (const auto& unit : array.m_nal_units) {
294
295
      // Write 4-byte NALs size
296
297
17.2k
      dest->push_back((unit.size() >> 24) & 0xFF);
298
17.2k
      dest->push_back((unit.size() >> 16) & 0xFF);
299
17.2k
      dest->push_back((unit.size() >> 8) & 0xFF);
300
17.2k
      dest->push_back((unit.size() >> 0) & 0xFF);
301
302
      // Copy NAL data
303
304
17.2k
      dest->insert(dest->end(), unit.begin(), unit.end());
305
17.2k
    }
306
17.3k
  }
307
308
5.81k
  return true;
309
5.81k
}
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
  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
1
{
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
1
  BitReader reader(data.data(), (int) data.size());
507
1
  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
1
  uint32_t len = reader.get_bits32(32);
514
515
1
  if (len > data.size() - 4) {
516
    // ERROR: read past end of data
517
1
  }
518
519
1
  while (reader.get_current_byte_index() < (int) len) {
520
1
    int currPos = reader.get_current_byte_index();
521
522
1
    BitReader sei_reader(data.data() + currPos, (int) data.size() - currPos);
523
524
1
    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
1
    uint32_t nal_size = sei_reader.get_bits32(32);
531
1
    (void) nal_size;
532
533
1
    auto nal_type = static_cast<uint8_t>(sei_reader.get_bits8(8) >> 1);
534
1
    sei_reader.skip_bits(8);
535
536
    // SEI
537
538
1
    if (nal_type == 39 ||
539
1
        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
1
    break; // TODO: read next SEI
564
1
  }
565
566
567
1
  return Error::Ok;
568
1
}
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
0
{
574
0
  std::vector<uint8_t> out_data;
575
576
0
  for (size_t i = 0; i < size; i++) {
577
0
    if (i + 2 < size &&
578
0
        sps[i] == 0 &&
579
0
        sps[i + 1] == 0 &&
580
0
        sps[i + 2] == 3) {
581
0
      out_data.push_back(0);
582
0
      out_data.push_back(0);
583
0
      i += 2;
584
0
    }
585
0
    else {
586
0
      out_data.push_back(sps[i]);
587
0
    }
588
0
  }
589
590
0
  return out_data;
591
0
}
592
593
594
Error parse_sps_for_hvcC_configuration(const uint8_t* sps, size_t size,
595
                                       HEVCDecoderConfigurationRecord* config,
596
                                       int* width, int* height)
597
0
{
598
  // remove start-code emulation bytes from SPS header stream
599
600
0
  std::vector<uint8_t> sps_no_emul = remove_start_code_emulation(sps, size);
601
602
0
  sps = sps_no_emul.data();
603
0
  size = sps_no_emul.size();
604
605
606
0
  BitReader reader(sps, (int) size);
607
608
  // skip NAL header
609
0
  reader.skip_bits(2 * 8);
610
611
  // skip VPS ID
612
0
  reader.skip_bits(4);
613
614
0
  uint8_t nMaxSubLayersMinus1 = reader.get_bits8(3);
615
616
0
  config->temporal_id_nested = reader.get_bits8(1);
617
618
  // --- profile_tier_level ---
619
620
0
  config->general_profile_space = reader.get_bits8(2);
621
0
  config->general_tier_flag = reader.get_bits8(1);
622
0
  config->general_profile_idc = reader.get_bits8(5);
623
0
  config->general_profile_compatibility_flags = reader.get_bits32(32);
624
625
0
  reader.skip_bits(16); // skip reserved bits
626
0
  reader.skip_bits(16); // skip reserved bits
627
0
  reader.skip_bits(16); // skip reserved bits
628
629
0
  config->general_level_idc = reader.get_bits8(8);
630
631
0
  std::vector<bool> layer_profile_present(nMaxSubLayersMinus1);
632
0
  std::vector<bool> layer_level_present(nMaxSubLayersMinus1);
633
634
0
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
635
0
    layer_profile_present[i] = reader.get_bits(1);
636
0
    layer_level_present[i] = reader.get_bits(1);
637
0
  }
638
639
0
  if (nMaxSubLayersMinus1 > 0) {
640
0
    for (int i = nMaxSubLayersMinus1; i < 8; i++) {
641
0
      reader.skip_bits(2);
642
0
    }
643
0
  }
644
645
0
  for (int i = 0; i < nMaxSubLayersMinus1; i++) {
646
0
    if (layer_profile_present[i]) {
647
0
      reader.skip_bits(2 + 1 + 5);
648
0
      reader.skip_bits(32);
649
0
      reader.skip_bits(16);
650
0
    }
651
652
0
    if (layer_level_present[i]) {
653
0
      reader.skip_bits(8);
654
0
    }
655
0
  }
656
657
658
  // --- SPS continued ---
659
660
0
  int dummy, value;
661
0
  reader.get_uvlc(&dummy); // skip seq_parameter_seq_id
662
663
0
  reader.get_uvlc(&value);
664
0
  config->chroma_format = (uint8_t) value;
665
666
0
  if (config->chroma_format == 3) {
667
0
    reader.skip_bits(1);
668
0
  }
669
670
0
  reader.get_uvlc(width);
671
0
  reader.get_uvlc(height);
672
673
0
  bool conformance_window = reader.get_bits(1);
674
0
  if (conformance_window) {
675
0
    int left, right, top, bottom;
676
0
    reader.get_uvlc(&left);
677
0
    reader.get_uvlc(&right);
678
0
    reader.get_uvlc(&top);
679
0
    reader.get_uvlc(&bottom);
680
681
    //printf("conformance borders: %d %d %d %d\n",left,right,top,bottom);
682
683
0
    int subH = 1, subV = 1;
684
0
    if (config->chroma_format == 1) {
685
0
      subV = 2;
686
0
      subH = 2;
687
0
    }
688
0
    if (config->chroma_format == 2) { subH = 2; }
689
690
0
    *width -= subH * (left + right);
691
0
    *height -= subV * (top + bottom);
692
0
  }
693
694
0
  reader.get_uvlc(&value);
695
0
  config->bit_depth_luma = (uint8_t) (value + 8);
696
697
0
  reader.get_uvlc(&value);
698
0
  config->bit_depth_chroma = (uint8_t) (value + 8);
699
700
701
702
  // --- init static configuration fields ---
703
704
0
  config->configuration_version = 1;
705
0
  config->min_spatial_segmentation_idc = 0; // TODO: get this value from the VUI, 0 should be safe
706
0
  config->parallelism_type = 0; // TODO, 0 should be safe
707
0
  config->avg_frame_rate = 0; // makes no sense for HEIF (TODO)
708
0
  config->constant_frame_rate = 0; // makes no sense for HEIF (TODO)
709
0
  config->num_temporal_layers = 1; // makes no sense for HEIF
710
711
0
  return Error::Ok;
712
0
}