Coverage Report

Created: 2026-08-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/codecs/avc_boxes.cc
Line
Count
Source
1
/*
2
 * HEIF AVC codec.
3
 * Copyright (c) 2023 Brad Hards <bradh@frogmouth.net>
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 "avc_boxes.h"
22
#include <cstdint>
23
#include <iomanip>
24
#include <iostream>
25
#include <vector>
26
#include "file.h"
27
#include "context.h"
28
#include "avc_dec.h"
29
#include "hevc_boxes.h"
30
#include <utility>
31
#include <set>
32
33
34
Error Box_avcC::parse(BitstreamRange& range, const heif_security_limits* limits)
35
8.06k
{
36
8.06k
  m_configuration.configuration_version = range.read8();
37
8.06k
  m_configuration.AVCProfileIndication = range.read8();
38
8.06k
  m_configuration.profile_compatibility = range.read8();
39
8.06k
  m_configuration.AVCLevelIndication = range.read8();
40
8.06k
  uint8_t lengthSizeMinusOneWithReserved = range.read8();
41
8.06k
  m_configuration.lengthSize =
42
8.06k
      (lengthSizeMinusOneWithReserved & 0b00000011) + 1;
43
44
8.06k
  uint8_t numOfSequenceParameterSets = (range.read8() & 0b00011111);
45
13.4k
  for (int i = 0; i < numOfSequenceParameterSets; i++) {
46
5.38k
    uint16_t sequenceParameterSetLength = range.read16();
47
5.38k
    std::vector<uint8_t> sps(sequenceParameterSetLength);
48
5.38k
    range.read(sps.data(), sps.size());
49
5.38k
    m_sps.push_back(sps);
50
5.38k
  }
51
52
8.06k
  uint8_t numOfPictureParameterSets = range.read8();
53
21.5k
  for (int i = 0; i < numOfPictureParameterSets; i++) {
54
13.4k
    uint16_t pictureParameterSetLength = range.read16();
55
13.4k
    std::vector<uint8_t> pps(pictureParameterSetLength);
56
13.4k
    range.read(pps.data(), pps.size());
57
13.4k
    m_pps.push_back(pps);
58
13.4k
  }
59
60
  // See ISO/IEC 14496-15 2017 Section 5.3.3.1.2
61
8.06k
  if (range.get_remaining_bytes() > 0) {
62
4.71k
    if ((m_configuration.AVCProfileIndication != 66) &&
63
4.40k
        (m_configuration.AVCProfileIndication != 77) &&
64
3.95k
        (m_configuration.AVCProfileIndication != 88)) {
65
3.55k
      m_configuration.chroma_format = (heif_chroma) (range.read8() & 0b00000011);
66
3.55k
      m_configuration.bit_depth_luma = 8 + (range.read8() & 0b00000111);
67
3.55k
      m_configuration.bit_depth_chroma = 8 + (range.read8() & 0b00000111);
68
3.55k
      uint8_t numOfSequenceParameterSetExt = range.read8();
69
19.9k
      for (int i = 0; i < numOfSequenceParameterSetExt; i++) {
70
16.4k
        uint16_t sequenceParameterSetExtLength = range.read16();
71
16.4k
        std::vector<uint8_t> sps_ext(sequenceParameterSetExtLength);
72
16.4k
        range.read(sps_ext.data(), sps_ext.size());
73
16.4k
        m_sps_ext.push_back(sps_ext);
74
16.4k
      }
75
3.55k
    }
76
4.71k
  }
77
78
8.06k
  return range.get_error();
79
8.06k
}
80
81
Error Box_avcC::write(StreamWriter& writer) const
82
165
{
83
165
  size_t box_start = reserve_box_header_space(writer);
84
85
165
  writer.write8(m_configuration.configuration_version);
86
165
  writer.write8(m_configuration.AVCProfileIndication);
87
165
  writer.write8(m_configuration.profile_compatibility);
88
165
  writer.write8(m_configuration.AVCLevelIndication);
89
165
  uint8_t lengthSizeMinusOneWithReserved = 0b11111100 | ((m_configuration.lengthSize - 1) & 0b11);
90
165
  writer.write8(lengthSizeMinusOneWithReserved);
91
92
165
  if (m_sps.size() > 0b00011111) {
93
0
    return {
94
0
      heif_error_Encoding_error,
95
0
      heif_suberror_Unspecified,
96
0
      "Cannot write more than 31 PPS into avcC box."
97
0
    };
98
0
  }
99
100
165
  uint8_t numSpsWithReserved = 0b11100000 | (m_sps.size() & 0b00011111);
101
165
  writer.write8(numSpsWithReserved);
102
165
  for (const auto& sps : m_sps) {
103
165
    if (sps.size() > 0xFFFF) {
104
0
      return {
105
0
        heif_error_Encoding_error,
106
0
        heif_suberror_Unspecified,
107
0
        "Cannot write SPS larger than 65535 bytes into avcC box."
108
0
      };
109
0
    }
110
165
    writer.write16((uint16_t) sps.size());
111
165
    writer.write(sps);
112
165
  }
113
114
165
  if (m_pps.size() > 0xFF) {
115
0
    return {
116
0
      heif_error_Encoding_error,
117
0
      heif_suberror_Unspecified,
118
0
      "Cannot write more than 255 PPS into avcC box."
119
0
    };
120
0
  }
121
122
165
  writer.write8(m_pps.size() & 0xFF);
123
165
  for (const auto& pps : m_pps) {
124
165
    if (pps.size() > 0xFFFF) {
125
0
      return {
126
0
        heif_error_Encoding_error,
127
0
        heif_suberror_Unspecified,
128
0
        "Cannot write PPS larger than 65535 bytes into avcC box."
129
0
      };
130
0
    }
131
165
    writer.write16((uint16_t) pps.size());
132
165
    writer.write(pps);
133
165
  }
134
135
165
  if ((m_configuration.AVCProfileIndication != 66) &&
136
165
      (m_configuration.AVCProfileIndication != 77) &&
137
45
      (m_configuration.AVCProfileIndication != 88)) {
138
45
    writer.write8(m_configuration.chroma_format);
139
45
    writer.write8(m_configuration.bit_depth_luma - 8);
140
45
    writer.write8(m_configuration.bit_depth_chroma - 8);
141
142
45
    if (m_sps_ext.size() > 0xFF) {
143
0
      return {
144
0
        heif_error_Encoding_error,
145
0
        heif_suberror_Unspecified,
146
0
        "Cannot write more than 255 SPS-Ext into avcC box."
147
0
      };
148
0
    }
149
150
45
    writer.write8(m_sps_ext.size() & 0xFF);
151
45
    for (const auto& spsext : m_sps_ext) {
152
0
      if (spsext.size() > 0xFFFF) {
153
0
        return {
154
0
          heif_error_Encoding_error,
155
0
          heif_suberror_Unspecified,
156
0
          "Cannot write SPS-Ext larger than 65535 bytes into avcC box."
157
0
        };
158
0
      }
159
0
      writer.write16((uint16_t) spsext.size());
160
0
      writer.write(spsext);
161
0
    }
162
45
  }
163
164
165
  prepend_header(writer, box_start);
165
166
165
  return Error::Ok;
167
165
}
168
169
std::string Box_avcC::dump(Indent& indent) const
170
4.33k
{
171
4.33k
  std::ostringstream sstr;
172
4.33k
  sstr << Box::dump(indent);
173
4.33k
  sstr << indent << "configuration_version: " << ((int) m_configuration.configuration_version) << "\n"
174
4.33k
      << indent << "AVCProfileIndication: " << ((int) m_configuration.AVCProfileIndication) << " (" << profileIndicationAsText() << ")\n"
175
4.33k
      << indent << "profile_compatibility: " << ((int) m_configuration.profile_compatibility) << "\n"
176
4.33k
      << indent << "AVCLevelIndication: " << ((int) m_configuration.AVCLevelIndication) << "\n"
177
4.33k
      << indent << "Chroma format: ";
178
179
4.33k
  switch (m_configuration.chroma_format) {
180
1.01k
    case heif_chroma_monochrome:
181
1.01k
      sstr << "4:0:0\n";
182
1.01k
      break;
183
3.24k
    case heif_chroma_420:
184
3.24k
      sstr << "4:2:0\n";
185
3.24k
      break;
186
31
    case heif_chroma_422:
187
31
      sstr << "4:2:2\n";
188
31
      break;
189
47
    case heif_chroma_444:
190
47
      sstr << "4:4:4\n";
191
47
      break;
192
0
    default:
193
0
      sstr << "unsupported\n";
194
0
      break;
195
4.33k
  }
196
197
4.33k
  sstr << indent << "Bit depth luma: " << ((int) m_configuration.bit_depth_luma) << "\n"
198
4.33k
      << indent << "Bit depth chroma: " << ((int) m_configuration.bit_depth_chroma) << "\n";
199
200
4.33k
  for (const auto& sps : m_sps) {
201
1.94k
    sstr << indent << "SPS: ";
202
619k
    for (uint8_t b : sps) {
203
619k
      sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
204
619k
    }
205
1.94k
    sstr << "\n";
206
1.94k
    sstr << std::dec;
207
1.94k
  }
208
209
4.33k
  for (const auto& spsext : m_sps_ext) {
210
2.75k
    sstr << indent << "SPS-EXT: ";
211
5.86k
    for (uint8_t b : spsext) {
212
5.86k
      sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
213
5.86k
    }
214
2.75k
    sstr << "\n";
215
2.75k
    sstr << std::dec;
216
2.75k
  }
217
218
4.33k
  for (const auto& pps : m_pps) {
219
2.04k
    sstr << indent << "PPS: ";
220
310k
    for (uint8_t b : pps) {
221
310k
      sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
222
310k
    }
223
2.04k
    sstr << "\n";
224
2.04k
    sstr << std::dec;
225
2.04k
  }
226
227
4.33k
  return sstr.str();
228
4.33k
}
229
230
std::string Box_avcC::profileIndicationAsText() const
231
4.33k
{
232
  // See ISO/IEC 14496-10:2022 Annex A
233
4.33k
  switch (m_configuration.AVCProfileIndication) {
234
486
    case 44:
235
486
      return "CALVC 4:4:4";
236
393
    case 66:
237
393
      return "Constrained Baseline";
238
2.04k
    case 77:
239
2.04k
      return "Main";
240
425
    case 88:
241
425
      return "Extended";
242
162
    case 100:
243
162
      return "High variant";
244
72
    case 110:
245
72
      return "High 10";
246
201
    case 122:
247
201
      return "High 4:2:2";
248
212
    case 244:
249
212
      return "High 4:4:4";
250
340
    default:
251
340
      return "Unknown";
252
4.33k
  }
253
4.33k
}
254
255
256
void Box_avcC::get_header_nals(std::vector<uint8_t>& data) const
257
1.15k
{
258
1.15k
  for (const auto& sps : m_sps) {
259
691
    data.push_back((sps.size() >> 24) & 0xFF);
260
691
    data.push_back((sps.size() >> 16) & 0xFF);
261
691
    data.push_back((sps.size() >> 8) & 0xFF);
262
691
    data.push_back((sps.size() >> 0) & 0xFF);
263
264
691
    data.insert(data.end(), sps.begin(), sps.end());
265
691
  }
266
267
1.16k
  for (const auto& spsext : m_sps_ext) {
268
1.16k
    data.push_back((spsext.size() >> 24) & 0xFF);
269
1.16k
    data.push_back((spsext.size() >> 16) & 0xFF);
270
1.16k
    data.push_back((spsext.size() >> 8) & 0xFF);
271
1.16k
    data.push_back((spsext.size() >> 0) & 0xFF);
272
273
1.16k
    data.insert(data.end(), spsext.begin(), spsext.end());
274
1.16k
  }
275
276
1.15k
  for (const auto& pps : m_pps) {
277
483
    data.push_back((pps.size() >> 24) & 0xFF);
278
483
    data.push_back((pps.size() >> 16) & 0xFF);
279
483
    data.push_back((pps.size() >> 8) & 0xFF);
280
483
    data.push_back((pps.size() >> 0) & 0xFF);
281
282
483
    data.insert(data.end(), pps.begin(), pps.end());
283
483
  }
284
1.15k
}
285
286
287
void Box_avcC::append_sps_nal(const uint8_t* data, size_t size)
288
165
{
289
165
  std::vector<uint8_t> vec(data, data + size);
290
165
  m_sps.emplace_back(std::move(vec));
291
165
}
292
293
void Box_avcC::append_sps_ext_nal(const uint8_t* data, size_t size)
294
0
{
295
0
  std::vector<uint8_t> vec(data, data + size);
296
0
  m_sps_ext.emplace_back(std::move(vec));
297
0
}
298
299
void Box_avcC::append_pps_nal(const uint8_t* data, size_t size)
300
165
{
301
165
  std::vector<uint8_t> vec(data, data + size);
302
165
  m_pps.emplace_back(std::move(vec));
303
165
}
304
305
static bool skip_scaling_list(BitReader& reader, int sizeOfScalingList)
306
745
{
307
745
  int lastScale = 8;
308
745
  int nextScale = 8;
309
310
  // TODO: it seems that this can be simplified by exiting the loop
311
  //       as soon as nextScale==0.
312
313
#if 0
314
  // original version
315
  for (int j = 0; j < sizeOfScalingList; j++) {
316
    if (nextScale != 0) {
317
      int32_t delta_scale;
318
      if (!reader.get_svlc(&delta_scale)) {
319
        return false;
320
      }
321
      nextScale = (lastScale + delta_scale + 256) % 256;
322
    }
323
324
    lastScale = (nextScale == 0) ? lastScale : nextScale;
325
  }
326
#else
327
  // fast version
328
12.6k
  for (int j = 0; j < sizeOfScalingList; j++) {
329
12.2k
    int32_t delta_scale;
330
12.2k
    if (!reader.get_svlc(&delta_scale)) {
331
142
      return false;
332
142
    }
333
12.0k
    nextScale = (lastScale + delta_scale + 256) % 256;
334
335
12.0k
    if (nextScale == 0) {
336
134
      break;
337
134
    }
338
339
11.9k
    lastScale = nextScale;
340
11.9k
  }
341
603
#endif
342
343
603
  return true;
344
745
}
345
346
347
Error parse_sps_for_avcC_configuration(const uint8_t* sps, size_t size,
348
                                       Box_avcC::configuration* config,
349
                                       uint32_t* width, uint32_t* height,
350
                                       ImageSize* coded_size)
351
994
{
352
  // remove start-code emulation bytes from SPS header stream
353
354
994
  std::vector<uint8_t> sps_no_emul = remove_start_code_emulation(sps, size);
355
356
994
  sps = sps_no_emul.data();
357
994
  size = sps_no_emul.size();
358
359
360
994
  BitReader reader(sps, size);
361
362
  // skip NAL header
363
994
  reader.skip_bits(8);
364
365
994
  config->configuration_version = 1;
366
994
  config->AVCProfileIndication = reader.get_bits8(8);
367
994
  config->profile_compatibility = reader.get_bits8(8);
368
994
  config->AVCLevelIndication = reader.get_bits8(8);
369
994
  config->lengthSize = 4;
370
371
994
  Error invalidUVLC{
372
994
    heif_error_Invalid_input,
373
994
    heif_suberror_Unspecified,
374
994
    "Invalid variable length code in AVC SPS header"
375
994
  };
376
377
994
  uint32_t value;
378
994
  if (!reader.get_uvlc(&value)) { return invalidUVLC; } // SPS ID
379
380
988
  if (std::set<int>{100, 110, 122, 244, 44, 83, 86}.contains(config->AVCProfileIndication)) {
381
800
    if (!reader.get_uvlc(&value)) {
382
6
      return invalidUVLC;
383
6
    }
384
385
794
    if (value > heif_chroma_444) {
386
22
      return {
387
22
        heif_error_Invalid_input,
388
22
        heif_suberror_Unspecified,
389
22
        "Invalid chroma format in AVC SPS header"
390
22
      };
391
22
    }
392
393
772
    config->chroma_format = static_cast<heif_chroma>(value);
394
772
    if (config->chroma_format == heif_chroma_444) {
395
62
      reader.skip_bits(1);
396
62
    }
397
398
772
    if (!reader.get_uvlc(&value)) {
399
2
      return invalidUVLC;
400
2
    }
401
770
    config->bit_depth_luma = static_cast<uint8_t>(8 + value);
402
403
770
    if (!reader.get_uvlc(&value)) {
404
6
      return invalidUVLC;
405
6
    }
406
764
    config->bit_depth_chroma = static_cast<uint8_t>(8 + value);
407
408
764
    reader.skip_bits(1);
409
764
    int seq_scaling_matrix_present_flag = reader.get_bits(1);
410
764
    if (seq_scaling_matrix_present_flag) {
411
1.55k
      for (int i = 0; i < ((config->chroma_format != heif_chroma_444) ? 8 : 12); i++) {
412
1.45k
        int scaling_list_present_flag = reader.get_bits(1);
413
1.45k
        if (scaling_list_present_flag) {
414
745
          if (!skip_scaling_list(reader, i < 6 ? 16 : 64)) {
415
142
            return invalidUVLC;
416
142
          }
417
745
        }
418
1.45k
      }
419
241
    }
420
764
  }
421
188
  else {
422
188
    config->chroma_format = heif_chroma_420;
423
188
    config->bit_depth_luma = 8;
424
188
    config->bit_depth_chroma = 8;
425
188
  }
426
427
810
  if (!reader.get_uvlc(&value)) { return invalidUVLC; } // log2_max_frame_num_minus4
428
810
  uint32_t pic_order_cnt_type;
429
810
  if (!reader.get_uvlc(&pic_order_cnt_type)) { return invalidUVLC; }
430
809
  if (pic_order_cnt_type == 0) {
431
606
    if (!reader.get_uvlc(&value)) { return invalidUVLC; }
432
606
  }
433
203
  else if (pic_order_cnt_type == 1) {
434
117
    reader.get_bits(1);
435
117
    int32_t svalue;
436
117
    if (!reader.get_svlc(&svalue) ||
437
111
        !reader.get_svlc(&svalue)) { return invalidUVLC; }
438
107
    uint32_t num_ref_franes_in_pic_order_cnt_cycle;
439
107
    if (!reader.get_uvlc(&num_ref_franes_in_pic_order_cnt_cycle)) { return invalidUVLC; }
440
2.87k
    for (uint32_t i = 0; i < num_ref_franes_in_pic_order_cnt_cycle; i++) {
441
2.77k
      if (!reader.get_uvlc(&value)) { return invalidUVLC; }
442
2.77k
    }
443
104
  }
444
445
784
  if (!reader.get_uvlc(&value)) { return invalidUVLC; } // num_ref_frames
446
784
  reader.skip_bits(1);
447
448
784
  uint32_t pic_width_in_mbs_minus1;
449
784
  uint32_t pic_height_in_mbs_minus1;
450
784
  if (!reader.get_uvlc(&pic_width_in_mbs_minus1) ||
451
783
      !reader.get_uvlc(&pic_height_in_mbs_minus1)) {
452
7
    return invalidUVLC;
453
7
  }
454
455
777
  if (pic_width_in_mbs_minus1 > (UINT32_MAX / 16) - 1 ||
456
777
      pic_height_in_mbs_minus1 > (UINT32_MAX / 16) - 1) {
457
0
    return {heif_error_Invalid_input,
458
0
            heif_suberror_Invalid_image_size,
459
0
            "AVC SPS image size too large"};
460
0
  }
461
462
777
  *width = (pic_width_in_mbs_minus1 + 1) * 16;
463
777
  *height = (pic_height_in_mbs_minus1 + 1) * 16;
464
465
777
  if (coded_size) {
466
612
    coded_size->width = *width;
467
612
    coded_size->height = *height;
468
612
  }
469
470
777
  uint32_t frame_mbs_only_flag = reader.get_bits(1);
471
777
  if (!frame_mbs_only_flag) {
472
76
    reader.skip_bits(1);
473
76
  }
474
777
  reader.skip_bits(1);
475
777
  uint32_t frame_cropping_flag = reader.get_bits(1);
476
777
  if (frame_cropping_flag) {
477
334
    uint32_t left, right, top, bottom;
478
334
    if (!reader.get_uvlc(&left) ||
479
334
        !reader.get_uvlc(&right) ||
480
331
        !reader.get_uvlc(&top) ||
481
331
        !reader.get_uvlc(&bottom)) {
482
3
      return invalidUVLC;
483
3
    }
484
485
331
    uint64_t crop_horizontal = static_cast<uint64_t>(left) + right;
486
331
    uint64_t crop_vertical = static_cast<uint64_t>(top) + bottom;
487
331
    if (crop_horizontal > *width || crop_vertical > *height) {
488
9
      return {heif_error_Invalid_input,
489
9
              heif_suberror_Invalid_image_size,
490
9
              "AVC SPS cropping exceeds image size"};
491
9
    }
492
493
322
    *width -= static_cast<uint32_t>(crop_horizontal);
494
322
    *height -= static_cast<uint32_t>(crop_vertical);
495
322
  }
496
497
765
  return {};
498
777
}