Coverage Report

Created: 2025-06-16 07:00

/src/libheif/libheif/codecs/avif_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 "pixelimage.h"
22
#include "avif_boxes.h"
23
#include "avif_dec.h"
24
#include "bitstream.h"
25
#include "common_utils.h"
26
#include "libheif/api_structs.h"
27
#include "file.h"
28
#include <iomanip>
29
#include <limits>
30
#include <string>
31
#include <cstring>
32
33
// https://aomediacodec.github.io/av1-spec/av1-spec.pdf
34
35
36
Error Box_av1C::parse(BitstreamRange& range, const heif_security_limits* limits)
37
1.30k
{
38
  //parse_full_box_header(range);
39
40
1.30k
  if (!has_fixed_box_size()) {
41
    // Note: in theory, it is allowed to have an av1C box with unspecified size (until the end of the file),
42
    // but that would be very uncommon and give us problems in the calculation of `configOBUs_bytes` below.
43
    // It's better to error on this case than to open a DoS vulnerability.
44
2
    return Error{heif_error_Invalid_input, heif_suberror_Unspecified, "av1C with unspecified box size"};
45
2
  }
46
47
1.29k
  uint8_t byte;
48
49
1.29k
  auto& c = m_configuration; // abbreviation
50
51
1.29k
  byte = range.read8();
52
1.29k
  if ((byte & 0x80) == 0) {
53
    // error: marker bit not set
54
52
  }
55
56
1.29k
  c.version = byte & 0x7F;
57
58
1.29k
  byte = range.read8();
59
1.29k
  c.seq_profile = (byte >> 5) & 0x7;
60
1.29k
  c.seq_level_idx_0 = byte & 0x1f;
61
62
1.29k
  byte = range.read8();
63
1.29k
  c.seq_tier_0 = (byte >> 7) & 1;
64
1.29k
  c.high_bitdepth = (byte >> 6) & 1;
65
1.29k
  c.twelve_bit = (byte >> 5) & 1;
66
1.29k
  c.monochrome = (byte >> 4) & 1;
67
1.29k
  c.chroma_subsampling_x = (byte >> 3) & 1;
68
1.29k
  c.chroma_subsampling_y = (byte >> 2) & 1;
69
1.29k
  c.chroma_sample_position = byte & 3;
70
71
1.29k
  byte = range.read8();
72
1.29k
  c.initial_presentation_delay_present = (byte >> 4) & 1;
73
1.29k
  if (c.initial_presentation_delay_present) {
74
41
    c.initial_presentation_delay_minus_one = byte & 0x0F;
75
41
  }
76
77
1.29k
  const size_t configOBUs_bytes = range.get_remaining_bytes();
78
1.29k
  m_config_OBUs.resize(configOBUs_bytes);
79
80
1.29k
  if (!range.read(m_config_OBUs.data(), configOBUs_bytes)) {
81
    // error
82
0
  }
83
84
1.29k
  return range.get_error();
85
1.30k
}
86
87
88
Error Box_av1C::write(StreamWriter& writer) const
89
0
{
90
0
  size_t box_start = reserve_box_header_space(writer);
91
92
0
  const auto& c = m_configuration; // abbreviation
93
94
0
  writer.write8(c.version | 0x80);
95
96
0
  writer.write8((uint8_t) (((c.seq_profile & 0x7) << 5) |
97
0
                           (c.seq_level_idx_0 & 0x1f)));
98
99
0
  writer.write8((uint8_t) ((c.seq_tier_0 ? 0x80 : 0) |
100
0
                           (c.high_bitdepth ? 0x40 : 0) |
101
0
                           (c.twelve_bit ? 0x20 : 0) |
102
0
                           (c.monochrome ? 0x10 : 0) |
103
0
                           (c.chroma_subsampling_x ? 0x08 : 0) |
104
0
                           (c.chroma_subsampling_y ? 0x04 : 0) |
105
0
                           (c.chroma_sample_position & 0x03)));
106
107
0
  writer.write8(0); // TODO initial_presentation_delay
108
109
0
  prepend_header(writer, box_start);
110
111
0
  return Error::Ok;
112
0
}
113
114
115
std::string Box_av1C::dump(Indent& indent) const
116
0
{
117
0
  std::ostringstream sstr;
118
0
  sstr << Box::dump(indent);
119
120
0
  const auto& c = m_configuration; // abbreviation
121
122
0
  sstr << indent << "version: " << ((int) c.version) << "\n"
123
0
       << indent << "seq_profile: " << ((int) c.seq_profile) << "\n"
124
0
       << indent << "seq_level_idx_0: " << ((int) c.seq_level_idx_0) << "\n"
125
0
       << indent << "high_bitdepth: " << ((int) c.high_bitdepth) << "\n"
126
0
       << indent << "twelve_bit: " << ((int) c.twelve_bit) << "\n"
127
0
       << indent << "monochrome: " << ((int) c.monochrome) << "\n"
128
0
       << indent << "chroma_subsampling_x: " << ((int) c.chroma_subsampling_x) << "\n"
129
0
       << indent << "chroma_subsampling_y: " << ((int) c.chroma_subsampling_y) << "\n"
130
0
       << indent << "chroma_sample_position: " << ((int) c.chroma_sample_position) << "\n"
131
0
       << indent << "initial_presentation_delay: ";
132
133
0
  if (c.initial_presentation_delay_present) {
134
0
    sstr << c.initial_presentation_delay_minus_one + 1 << "\n";
135
0
  }
136
0
  else {
137
0
    sstr << "not present\n";
138
0
  }
139
140
0
  sstr << indent << "config OBUs:";
141
0
  for (size_t i = 0; i < m_config_OBUs.size(); i++) {
142
0
    sstr << " " << std::hex << std::setfill('0') << std::setw(2)
143
0
         << ((int) m_config_OBUs[i]);
144
0
  }
145
0
  sstr << std::dec << "\n";
146
147
0
  return sstr.str();
148
0
}
149
150
151
Error fill_av1C_configuration(Box_av1C::configuration* inout_config, const std::shared_ptr<HeifPixelImage>& image)
152
0
{
153
0
  int bpp = image->get_bits_per_pixel(heif_channel_Y);
154
0
  heif_chroma chroma = image->get_chroma_format();
155
156
0
  uint8_t profile = compute_avif_profile(bpp, chroma);
157
158
0
  int width = image->get_width(heif_channel_Y);
159
0
  int height = image->get_height(heif_channel_Y);
160
161
0
  uint8_t level;
162
163
0
  if (width <= 8192 && height <= 4352 && (width * height) <= 8912896) {
164
0
    level = 13; // 5.1
165
0
  }
166
0
  else if (width <= 16384 && height <= 8704 && (width * height) <= 35651584) {
167
0
    level = 17; // 6.1
168
0
  }
169
0
  else {
170
0
    level = 31; // maximum
171
0
  }
172
173
0
  inout_config->seq_profile = profile;
174
0
  inout_config->seq_level_idx_0 = level;
175
0
  inout_config->high_bitdepth = (bpp > 8) ? 1 : 0;
176
0
  inout_config->twelve_bit = (bpp >= 12) ? 1 : 0;
177
0
  inout_config->monochrome = (chroma == heif_chroma_monochrome) ? 1 : 0;
178
0
  inout_config->chroma_subsampling_x = uint8_t(chroma_h_subsampling(chroma) >> 1);
179
0
  inout_config->chroma_subsampling_y = uint8_t(chroma_v_subsampling(chroma) >> 1);
180
181
  // 0 - CSP_UNKNOWN
182
  // 1 - CSP_VERTICAL
183
  // 2 - CSP_COLOCATED
184
  // 3 - CSP_RESERVED
185
186
0
  inout_config->chroma_sample_position = (chroma == heif_chroma_420 ? 0 : 2);
187
188
189
0
  return Error::Ok;
190
0
}
191
192
193
Error Box_a1op::parse(BitstreamRange& range, const heif_security_limits* limits)
194
8
{
195
8
  op_index = range.read8();
196
197
8
  return range.get_error();
198
8
}
199
200
201
std::string Box_a1op::dump(Indent& indent) const
202
0
{
203
0
  std::ostringstream sstr;
204
0
  sstr << Box::dump(indent);
205
206
0
  sstr << indent << "op-index: " << ((int) op_index) << "\n";
207
208
0
  return sstr.str();
209
0
}
210
211
212
Error Box_a1op::write(StreamWriter& writer) const
213
0
{
214
0
  size_t box_start = reserve_box_header_space(writer);
215
216
0
  writer.write8(op_index);
217
218
0
  prepend_header(writer, box_start);
219
220
0
  return Error::Ok;
221
0
}
222
223
224
Error Box_a1lx::parse(BitstreamRange& range, const heif_security_limits* limits)
225
38
{
226
38
  uint8_t flags = range.read8();
227
228
152
  for (int i = 0; i < 3; i++) {
229
114
    if (flags & 1) {
230
33
      layer_size[i] = range.read32();
231
33
    }
232
81
    else {
233
81
      layer_size[i] = range.read16();
234
81
    }
235
114
  }
236
237
38
  return range.get_error();
238
38
}
239
240
241
std::string Box_a1lx::dump(Indent& indent) const
242
0
{
243
0
  std::ostringstream sstr;
244
0
  sstr << Box::dump(indent);
245
246
0
  sstr << indent << "layer-sizes: [" << layer_size[0] << "," << layer_size[1] << "," << layer_size[2] << "]\n";
247
248
0
  return sstr.str();
249
0
}
250
251
252
Error Box_a1lx::write(StreamWriter& writer) const
253
0
{
254
0
  size_t box_start = reserve_box_header_space(writer);
255
256
0
  bool large = (layer_size[0] > 0xFFFF || layer_size[1] > 0xFFFF || layer_size[2] > 0xFFFF);
257
0
  writer.write8(large ? 1 : 0);
258
259
0
  for (int i = 0; i < 3; i++) {
260
0
    if (large) {
261
0
      writer.write32(layer_size[i]);
262
0
    }
263
0
    else {
264
0
      writer.write16((uint16_t) layer_size[i]);
265
0
    }
266
0
  }
267
268
0
  prepend_header(writer, box_start);
269
270
0
  return Error::Ok;
271
0
}
272
273
274
static uint64_t leb128(BitReader& reader)
275
0
{
276
0
  uint64_t val = 0;
277
0
  for (int i = 0; i < 8; i++) {
278
0
    int64_t v = reader.get_bits(8);
279
0
    val |= (v & 0x7F) << (i * 7);
280
0
    if (!(v & 0x80)) {
281
0
      break;
282
0
    }
283
0
  }
284
285
0
  return val;
286
0
}
287
288
289
struct obu_header_info
290
{
291
  int type;
292
  bool has_size;
293
  uint64_t size = 0;
294
};
295
296
static obu_header_info read_obu_header_type(BitReader& reader)
297
0
{
298
0
  obu_header_info info;
299
300
0
  reader.skip_bits(1);
301
0
  info.type = reader.get_bits(4);
302
0
  bool has_extension = reader.get_bits(1);
303
0
  info.has_size = reader.get_bits(1);
304
0
  reader.skip_bits(1);
305
306
0
  if (has_extension) {
307
0
    reader.skip_bits(8);
308
0
  }
309
310
0
  if (info.has_size) {
311
0
    info.size = leb128(reader);
312
0
  }
313
314
0
  return info;
315
0
}
316
317
318
const static int HEIF_OBU_SEQUENCE_HEADER = 1;
319
const static int CP_UNSPECIFIED = 2;
320
const static int TC_UNSPECIFIED = 2;
321
const static int MC_UNSPECIFIED = 2;
322
const static int CP_BT_709 = 1;
323
const static int TC_SRGB = 13;
324
const static int MC_IDENTITY = 0;
325
326
const static int HEIF_CSP_UNKNOWN = 0;
327
// 1 - CSP_VERTICAL
328
// 2 - CSP_COLOCATED
329
// 3 - CSP_RESERVED
330
331
bool fill_av1C_configuration_from_stream(Box_av1C::configuration* out_config, const uint8_t* data, int dataSize)
332
0
{
333
0
  BitReader reader(data, dataSize);
334
335
  // --- find OBU_SEQUENCE_HEADER
336
337
0
  bool seq_header_found = false;
338
339
0
  while (reader.get_bits_remaining() > 0) {
340
0
    obu_header_info header_info = read_obu_header_type(reader);
341
0
    if (header_info.type == HEIF_OBU_SEQUENCE_HEADER) {
342
0
      seq_header_found = true;
343
0
      break;
344
0
    }
345
0
    else if (header_info.has_size) {
346
0
      if (header_info.size > (uint64_t)std::numeric_limits<int>::max()) {
347
0
        return false;
348
0
      }
349
350
0
      reader.skip_bytes((int)header_info.size);
351
0
    }
352
0
    else {
353
0
      return false;
354
0
    }
355
0
  }
356
357
0
  if (!seq_header_found) {
358
0
    return false;
359
0
  }
360
361
362
  // --- read sequence header
363
364
0
  int dummy; // throw away value
365
366
0
  bool decoder_model_info_present = false;
367
0
  int buffer_delay_length_minus1 = 0;
368
369
0
  out_config->seq_profile = (uint8_t)reader.get_bits(3);
370
0
  bool still_picture = reader.get_bits(1);
371
0
  (void) still_picture;
372
373
0
  bool reduced_still_picture = reader.get_bits(1);
374
0
  if (reduced_still_picture) {
375
0
    out_config->seq_level_idx_0 = (uint8_t)reader.get_bits(5);
376
0
    out_config->seq_tier_0 = 0;
377
0
  }
378
0
  else {
379
0
    bool timing_info_present_flag = reader.get_bits(1);
380
0
    if (timing_info_present_flag) {
381
      // --- skip timing info
382
0
      reader.skip_bytes(2 * 4);
383
0
      bool equal_picture_interval = reader.get_bits(1);
384
0
      if (equal_picture_interval) {
385
0
        reader.get_uvlc(&dummy);
386
0
      }
387
388
      // --- skip decoder_model_info
389
0
      decoder_model_info_present = reader.get_bits(1);
390
0
      if (decoder_model_info_present) {
391
0
        buffer_delay_length_minus1 = reader.get_bits(5);
392
0
        reader.skip_bits(32);
393
0
        reader.skip_bits(10);
394
0
      }
395
0
    }
396
397
0
    bool initial_display_delay_present_flag = reader.get_bits(1);
398
0
    int operating_points_cnt_minus1 = reader.get_bits(5);
399
0
    for (int i = 0; i <= operating_points_cnt_minus1; i++) {
400
0
      reader.skip_bits(12);
401
0
      auto level = (uint8_t) reader.get_bits(5);
402
0
      if (i == 0) {
403
0
        out_config->seq_level_idx_0 = level;
404
0
      }
405
0
      if (level > 7) {
406
0
        auto tier = (uint8_t) reader.get_bits(1);
407
0
        if (i == 0) {
408
0
          out_config->seq_tier_0 = tier;
409
0
        }
410
0
      }
411
412
0
      if (decoder_model_info_present) {
413
0
        bool decoder_model_present_for_this = reader.get_bits(1);
414
0
        if (decoder_model_present_for_this) {
415
0
          int n = buffer_delay_length_minus1 + 1;
416
0
          reader.skip_bits(n);
417
0
          reader.skip_bits(n);
418
0
          reader.skip_bits(1);
419
0
        }
420
0
      }
421
422
0
      if (initial_display_delay_present_flag) {
423
0
        bool initial_display_delay_present_for_this = reader.get_bits(1);
424
0
        if (i==0) {
425
0
          out_config->initial_presentation_delay_present = initial_display_delay_present_for_this;
426
0
        }
427
428
0
        if (initial_display_delay_present_for_this) {
429
0
          auto delay = (uint8_t)reader.get_bits(4);
430
0
          if (i==0) {
431
0
            out_config->initial_presentation_delay_minus_one = delay;
432
0
          }
433
0
        }
434
0
      }
435
0
    }
436
0
  }
437
438
0
  int frame_width_bits_minus1 = reader.get_bits(4);
439
0
  int frame_height_bits_minus1 = reader.get_bits(4);
440
0
  int max_frame_width_minus1 = reader.get_bits(frame_width_bits_minus1 + 1);
441
0
  int max_frame_height_minus1 = reader.get_bits(frame_height_bits_minus1 + 1);
442
0
  (void)max_frame_width_minus1;
443
0
  (void)max_frame_height_minus1;
444
445
  // printf("max size: %d x %d\n", max_frame_width_minus1+1, max_frame_height_minus1+1);
446
447
0
  int frame_id_numbers_present_flag = 0;
448
0
  if (!reduced_still_picture) {
449
0
    frame_id_numbers_present_flag = reader.get_bits(1);
450
0
  }
451
0
  if (frame_id_numbers_present_flag) {
452
0
    reader.skip_bits(7);
453
0
  }
454
455
0
  reader.skip_bits(3);
456
0
  if (!reduced_still_picture) {
457
0
    reader.skip_bits(4);
458
459
    // order hint
460
0
    bool enable_order_hint = reader.get_bits(1);
461
0
    if (enable_order_hint) {
462
0
      reader.skip_bits(2);
463
0
    }
464
465
    // screen content
466
0
    int force_screen_content_tools = 2;
467
0
    if (reader.get_bits(1) == 0) {
468
0
      force_screen_content_tools = reader.get_bits(1);
469
0
    }
470
471
0
    if (force_screen_content_tools > 0) {
472
      // integer mv
473
0
      if (reader.get_bits(1) == 0) {
474
0
        reader.skip_bits(1);
475
0
      }
476
0
    }
477
478
0
    if (enable_order_hint) {
479
0
      reader.skip_bits(3);
480
0
    }
481
0
  }
482
483
0
  reader.skip_bits(3);
484
485
  // --- color config
486
487
0
  out_config->high_bitdepth = (uint8_t)reader.get_bits(1);
488
0
  if (out_config->seq_profile == 2 && out_config->high_bitdepth) {
489
0
    out_config->twelve_bit = (uint8_t)reader.get_bits(1);
490
0
  }
491
0
  else {
492
0
    out_config->twelve_bit = 0;
493
0
  }
494
495
0
  if (out_config->seq_profile == 1) {
496
0
    out_config->monochrome = 0;
497
0
  }
498
0
  else {
499
0
    out_config->monochrome = (uint8_t)reader.get_bits(1);
500
0
  }
501
502
0
  int color_primaries = CP_UNSPECIFIED;
503
0
  int transfer_characteristics = TC_UNSPECIFIED;
504
0
  int matrix_coefficients = MC_UNSPECIFIED;
505
506
0
  bool color_description_preset_flag = reader.get_bits(1);
507
0
  if (color_description_preset_flag) {
508
0
    color_primaries = reader.get_bits(8);
509
0
    transfer_characteristics = reader.get_bits(8);
510
0
    matrix_coefficients = reader.get_bits(8);
511
0
  }
512
0
  else {
513
    // color description unspecified
514
0
  }
515
516
0
  if (out_config->monochrome) {
517
0
    reader.skip_bits(1);
518
0
    out_config->chroma_subsampling_x = 1;
519
0
    out_config->chroma_subsampling_y = 1;
520
0
    out_config->chroma_sample_position = HEIF_CSP_UNKNOWN;
521
0
  }
522
0
  else if (color_primaries == CP_BT_709 &&
523
0
           transfer_characteristics == TC_SRGB &&
524
0
           matrix_coefficients == MC_IDENTITY) {
525
0
    out_config->chroma_subsampling_x = 0;
526
0
    out_config->chroma_subsampling_y = 0;
527
0
  }
528
0
  else {
529
0
    reader.skip_bits(1);
530
0
    if (out_config->seq_profile == 0) {
531
0
      out_config->chroma_subsampling_x = 1;
532
0
      out_config->chroma_subsampling_y = 1;
533
0
    }
534
0
    else if (out_config->seq_profile == 1) {
535
0
      out_config->chroma_subsampling_x = 0;
536
0
      out_config->chroma_subsampling_y = 0;
537
0
    }
538
0
    else {
539
0
      if (out_config->twelve_bit) {
540
0
        out_config->chroma_subsampling_x = (uint8_t)reader.get_bits(1);
541
0
        if (out_config->chroma_subsampling_x) {
542
0
          out_config->chroma_subsampling_y = (uint8_t)reader.get_bits(1);
543
0
        }
544
0
        else {
545
0
          out_config->chroma_subsampling_y = 0;
546
0
        }
547
0
      }
548
0
      else {
549
0
        out_config->chroma_subsampling_x = 1;
550
0
        out_config->chroma_subsampling_y = 0;
551
0
      }
552
0
    }
553
554
0
    if (out_config->chroma_subsampling_x &&
555
0
        out_config->chroma_subsampling_y) {
556
0
      out_config->chroma_sample_position = (uint8_t)reader.get_bits(2);
557
0
    }
558
0
  }
559
560
0
  reader.skip_bits(1); // separate_uv_delta
561
562
0
  return true;
563
0
}