Coverage Report

Created: 2025-12-21 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/brands.cc
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2025 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 "brands.h"
22
#include "file.h"
23
#include "sequences/track_visual.h"
24
#include <utility>
25
26
27
static bool check_mif1(const HeifContext* ctx)
28
0
{
29
0
  auto file = ctx->get_heif_file();
30
31
0
  auto meta = file->get_meta_box();
32
0
  if (!meta || meta->get_version() != 0) {
33
0
    return false;
34
0
  }
35
36
0
  auto hdlr = meta->get_child_box<Box_hdlr>();
37
0
  if (!hdlr || hdlr->get_version() != 0) {
38
0
    return false;
39
0
  }
40
41
0
  auto iloc = meta->get_child_box<Box_iloc>();
42
0
  if (!iloc || iloc->get_version() > 2) {
43
0
    return false;
44
0
  }
45
46
0
  auto iinf = meta->get_child_box<Box_iinf>();
47
0
  if (!iinf || iinf->get_version() > 1) {
48
0
    return false;
49
0
  }
50
51
0
  auto infe = iinf->get_child_box<Box_infe>();
52
0
  if (!infe || infe->get_version() < 2 || infe->get_version() > 3) {
53
0
    return false;
54
0
  }
55
56
0
  auto pitm = meta->get_child_box<Box_pitm>();
57
0
  if (!pitm || pitm->get_version() > 1) {
58
0
    return false;
59
0
  }
60
61
0
  auto iprp = meta->get_child_box<Box_iprp>();
62
0
  if (!iprp) {
63
0
    return false;
64
0
  }
65
66
0
  return true;
67
0
}
68
69
70
std::vector<std::shared_ptr<const ImageItem>> get_primary_and_alternative_images(const HeifContext* ctx)
71
0
{
72
0
  auto img = ctx->get_primary_image(false);
73
0
  if (img) {
74
0
    return {std::move(img)};
75
0
  }
76
0
  else {
77
0
    return {};
78
0
  }
79
0
}
80
81
82
std::vector<heif_brand2> compute_compatible_brands(const HeifContext* ctx, heif_brand2* out_main_brand)
83
0
{
84
0
  std::vector<heif_brand2> compatible_brands;
85
86
0
  heif_brand2 dummy;
87
0
  if (out_main_brand == nullptr) {
88
0
    out_main_brand = &dummy; // so that we do not have to check for NULL out_main_brand in the following
89
0
  }
90
91
0
  *out_main_brand = 0;
92
93
  // --- "mif" brands
94
95
0
  bool is_mif1 = check_mif1(ctx);
96
97
0
  if (is_mif1) {
98
0
    compatible_brands.push_back(heif_brand2_mif1);
99
0
    *out_main_brand = heif_brand2_mif1;
100
0
  }
101
102
0
  bool is_structural_image = is_mif1;
103
104
105
  // --- image brand
106
107
0
  std::vector<std::shared_ptr<const ImageItem>> images = get_primary_and_alternative_images(ctx);
108
109
0
  bool miaf_compatible = true;
110
111
0
  for (auto& img : images) {
112
0
    heif_brand2 brand = img->get_compatible_brand();
113
0
    if (brand != 0 &&
114
0
        is_structural_image &&
115
0
        std::find(compatible_brands.begin(),
116
0
                  compatible_brands.end(),
117
0
                  brand) == compatible_brands.end()) {
118
0
      compatible_brands.push_back(brand);
119
0
    }
120
121
0
    if (!img->is_miaf_compatible()) {
122
0
      miaf_compatible = false;
123
0
    }
124
0
  }
125
126
  // --- "miaf"
127
128
0
  if (miaf_compatible && is_structural_image) {
129
0
    compatible_brands.push_back(heif_brand2_miaf);
130
0
  }
131
132
133
  // --- main brand is first image brand
134
135
0
  if (!images.empty()) {
136
0
    heif_brand2 brand = images[0]->get_compatible_brand();
137
0
    if (brand != 0) {
138
0
      *out_main_brand = brand;
139
0
    }
140
0
  }
141
142
  // --- --- sequences
143
144
0
  if (ctx->has_sequence()) {
145
0
    compatible_brands.push_back(heif_brand2_msf1);
146
0
    compatible_brands.push_back(heif_brand2_iso8);
147
148
0
    auto track_result = ctx->get_track(0);
149
0
    assert(track_result);
150
151
0
    std::shared_ptr<const Track> track = *track_result;
152
0
    std::shared_ptr<const Track_Visual> visual_track = std::dynamic_pointer_cast<const Track_Visual>(track);
153
154
0
    heif_brand2 track_brand = visual_track->get_compatible_brand();
155
0
    if (track_brand != 0) {
156
0
      compatible_brands.push_back(track_brand);
157
158
      // overwrite any image brand
159
0
      *out_main_brand = track_brand;
160
0
    }
161
162
    // if we don't have a track brand, use at least the sequence structural brand
163
0
    if (*out_main_brand == 0) {
164
0
      *out_main_brand = heif_brand2_msf1;
165
0
    }
166
0
  }
167
168
0
  return compatible_brands;
169
0
}
170