Skip to content

Commit 20efde9

Browse files
committed
unci: write multi-component images with bytealign_component_interleave
1 parent ba8319e commit 20efde9

File tree

4 files changed

+62
-65
lines changed

4 files changed

+62
-65
lines changed

libheif/codecs/uncompressed/unc_boxes.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ bool is_valid_component_format(uint8_t format)
4646

4747
static std::map<heif_uncompressed_component_format, const char*> sNames_uncompressed_component_format{
4848
{component_format_unsigned, "unsigned"},
49+
{component_format_signed, "signed"},
4950
{component_format_float, "float"},
5051
{component_format_complex, "complex"}
5152
};

libheif/codecs/uncompressed/unc_encoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class HeifPixelImage;
3535

3636
heif_uncompressed_component_type heif_channel_to_component_type(heif_channel channel);
3737

38+
heif_uncompressed_component_format to_unc_component_format(heif_channel_datatype channel_datatype);
39+
3840

3941
class unc_encoder
4042
{

libheif/codecs/uncompressed/unc_encoder_bytealign_component_interleave.cc

Lines changed: 54 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -44,61 +44,53 @@ std::unique_ptr<const unc_encoder> unc_encoder_factory_bytealign_component_inter
4444
}
4545

4646

47-
void unc_encoder_bytealign_component_interleave::add_channel_if_exists(const std::shared_ptr<const HeifPixelImage>& image, heif_channel channel)
48-
{
49-
if (image->has_channel(channel)) {
50-
m_components.push_back({channel, heif_channel_to_component_type(channel)});
51-
}
52-
}
53-
54-
5547
unc_encoder_bytealign_component_interleave::unc_encoder_bytealign_component_interleave(const std::shared_ptr<const HeifPixelImage>& image,
5648
const heif_encoding_options& options)
5749
{
58-
// Special case for heif_channel_Y:
59-
// - if this an YCbCr image, use component_type_Y,
60-
// - otherwise, use component_type_monochrome
50+
bool is_nonvisual = (image->get_colorspace() == heif_colorspace_nonvisual);
51+
uint32_t num_components = image->get_number_of_components();
52+
53+
for (uint32_t idx = 0; idx < num_components; idx++) {
54+
heif_uncompressed_component_type comp_type;
6155

62-
if (image->has_channel(heif_channel_Y)) {
63-
if (image->has_channel(heif_channel_Cb) && image->has_channel(heif_channel_Cr)) {
64-
m_components.push_back({heif_channel_Y, heif_uncompressed_component_type::component_type_Y});
56+
if (is_nonvisual) {
57+
comp_type = static_cast<heif_uncompressed_component_type>(image->get_component_type(idx));
6558
}
6659
else {
67-
m_components.push_back({heif_channel_Y, heif_uncompressed_component_type::component_type_monochrome});
60+
heif_channel ch = image->get_component_channel(idx);
61+
if (ch == heif_channel_Y && !image->has_channel(heif_channel_Cb)) {
62+
comp_type = component_type_monochrome;
63+
}
64+
else {
65+
comp_type = heif_channel_to_component_type(ch);
66+
}
6867
}
69-
}
7068

71-
add_channel_if_exists(image, heif_channel_Cb);
72-
add_channel_if_exists(image, heif_channel_Cr);
73-
add_channel_if_exists(image, heif_channel_R);
74-
add_channel_if_exists(image, heif_channel_G);
75-
add_channel_if_exists(image, heif_channel_B);
76-
add_channel_if_exists(image, heif_channel_Alpha);
77-
add_channel_if_exists(image, heif_channel_filter_array);
78-
add_channel_if_exists(image, heif_channel_depth);
79-
add_channel_if_exists(image, heif_channel_disparity);
69+
uint8_t bpp = image->get_component_bits_per_pixel(idx);
70+
auto datatype = image->get_component_datatype(idx);
71+
auto comp_format = to_unc_component_format(datatype);
8072

73+
m_components.push_back({idx, comp_type, comp_format, bpp});
74+
}
8175

82-
// if we have any component > 8 bits, we enable this
76+
// Build cmpd/uncC boxes
8377
bool little_endian = false;
8478

85-
uint16_t index = 0;
86-
for (channel_component channelcomponent : m_components) {
87-
m_cmpd->add_component({channelcomponent.component_type});
88-
89-
uint8_t bpp = image->get_bits_per_pixel(channelcomponent.channel);
90-
uint8_t component_align_size = static_cast<uint8_t>((bpp + 7) / 8);
79+
uint16_t box_index = 0;
80+
for (const auto& comp : m_components) {
81+
m_cmpd->add_component({comp.component_type});
9182

92-
if (bpp % 8 == 0) {
83+
uint8_t component_align_size = static_cast<uint8_t>((comp.bpp + 7) / 8);
84+
if (comp.bpp % 8 == 0) {
9385
component_align_size = 0;
9486
}
9587

96-
if (bpp > 8) {
97-
little_endian = true; // TODO: depending on the host endianness
88+
if (comp.bpp > 8) {
89+
little_endian = true;
9890
}
9991

100-
m_uncC->add_component({index, bpp, component_format_unsigned, component_align_size});
101-
index++;
92+
m_uncC->add_component({box_index, comp.bpp, comp.component_format, component_align_size});
93+
box_index++;
10294
}
10395

10496
m_uncC->set_interleave_type(interleave_mode_component);
@@ -114,19 +106,20 @@ unc_encoder_bytealign_component_interleave::unc_encoder_bytealign_component_inte
114106
m_uncC->set_sampling_type(sampling_mode_no_subsampling);
115107
}
116108

117-
118109
// --- compute bytes per pixel
119110

120111
m_bytes_per_pixel_x4 = 0;
121112

122-
for (channel_component channelcomponent : m_components) {
123-
int bpp = image->get_bits_per_pixel(channelcomponent.channel);
124-
int bytes_per_pixel = 4 * (bpp + 7) / 8;
113+
for (const auto& comp : m_components) {
114+
int bytes_per_pixel = 4 * (comp.bpp + 7) / 8;
125115

126-
if (channelcomponent.channel == heif_channel_Cb ||
127-
channelcomponent.channel == heif_channel_Cr) {
128-
int downsampling = chroma_h_subsampling(image->get_chroma_format()) * chroma_v_subsampling(image->get_chroma_format());
129-
bytes_per_pixel /= downsampling;
116+
if (!is_nonvisual) {
117+
heif_channel ch = image->get_component_channel(comp.component_idx);
118+
if (ch == heif_channel_Cb || ch == heif_channel_Cr) {
119+
int downsampling = chroma_h_subsampling(image->get_chroma_format())
120+
* chroma_v_subsampling(image->get_chroma_format());
121+
bytes_per_pixel /= downsampling;
122+
}
130123
}
131124

132125
m_bytes_per_pixel_x4 += bytes_per_pixel;
@@ -142,36 +135,37 @@ uint64_t unc_encoder_bytealign_component_interleave::compute_tile_data_size_byte
142135

143136
std::vector<uint8_t> unc_encoder_bytealign_component_interleave::encode_tile(const std::shared_ptr<const HeifPixelImage>& src_image) const
144137
{
145-
std::vector<uint8_t> data;
146-
147138
// compute total size of all components
148139

149140
uint64_t total_size = 0;
150141

151-
for (channel_component channelcomponent : m_components) {
152-
int bpp = src_image->get_bits_per_pixel(channelcomponent.channel);
153-
int bytes_per_pixel = (bpp + 7) / 8;
154-
155-
total_size += static_cast<uint64_t>(src_image->get_height(channelcomponent.channel)) * src_image->get_width(channelcomponent.channel) * bytes_per_pixel;
142+
for (const auto& comp : m_components) {
143+
int bytes_per_pixel = (comp.bpp + 7) / 8;
144+
uint32_t w = src_image->get_component_width(comp.component_idx);
145+
uint32_t h = src_image->get_component_height(comp.component_idx);
146+
total_size += static_cast<uint64_t>(h) * w * bytes_per_pixel;
156147
}
157148

149+
std::vector<uint8_t> data;
158150
data.resize(total_size);
159151

160152
// output all component planes
161153

162154
uint64_t out_data_start_pos = 0;
163155

164-
for (channel_component channelcomponent : m_components) {
165-
int bpp = src_image->get_bits_per_pixel(channelcomponent.channel);
166-
int bytes_per_pixel = (bpp + 7) / 8;
156+
for (const auto& comp : m_components) {
157+
int bytes_per_pixel = (comp.bpp + 7) / 8;
158+
uint32_t w = src_image->get_component_width(comp.component_idx);
159+
uint32_t h = src_image->get_component_height(comp.component_idx);
167160

168161
size_t src_stride;
169-
const uint8_t* src_data = src_image->get_plane(channelcomponent.channel, &src_stride);
162+
const uint8_t* src_data = src_image->get_component(comp.component_idx, &src_stride);
170163

171-
for (uint32_t y = 0; y < src_image->get_height(channelcomponent.channel); y++) {
172-
uint32_t width = src_image->get_width(channelcomponent.channel);
173-
memcpy(data.data() + out_data_start_pos, src_data + src_stride * y, width * bytes_per_pixel);
174-
out_data_start_pos += width * bytes_per_pixel;
164+
for (uint32_t y = 0; y < h; y++) {
165+
memcpy(data.data() + out_data_start_pos,
166+
src_data + src_stride * y,
167+
w * bytes_per_pixel);
168+
out_data_start_pos += w * bytes_per_pixel;
175169
}
176170
}
177171

libheif/codecs/uncompressed/unc_encoder_bytealign_component_interleave.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ class unc_encoder_bytealign_component_interleave : public unc_encoder
3838
[[nodiscard]] std::vector<uint8_t> encode_tile(const std::shared_ptr<const HeifPixelImage>& image) const override;
3939

4040
private:
41-
struct channel_component
41+
struct encoded_component
4242
{
43-
heif_channel channel;
43+
uint32_t component_idx;
4444
heif_uncompressed_component_type component_type;
45+
heif_uncompressed_component_format component_format;
46+
uint8_t bpp;
4547
};
4648

47-
std::vector<channel_component> m_components;
49+
std::vector<encoded_component> m_components;
4850
uint32_t m_bytes_per_pixel_x4;
49-
50-
void add_channel_if_exists(const std::shared_ptr<const HeifPixelImage>& image, heif_channel channel);
5151
};
5252

5353

0 commit comments

Comments
 (0)