Skip to content

Commit 7148b01

Browse files
committed
Add channel map
1 parent 543be54 commit 7148b01

File tree

2 files changed

+173
-9
lines changed

2 files changed

+173
-9
lines changed

src/lib/OpenEXRCore/internal_ht.cpp

+168-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,137 @@
1717
#include "openexr_encode.h"
1818
#include "internal_ht_common.h"
1919

20+
/***********************************
21+
22+
Structure of the HT256 chunk
23+
- MAGIC = 0x4854: magic number
24+
- PLEN: length of header payload (big endian uint32_t)
25+
- header payload
26+
- NCH: number of channels in channel map (big endian uint16_t)
27+
- for(i = 0; i < NCH; i++)
28+
- CS_TO_F[i]: OpenEXR channel index corresponding to J2K component index i (big endian uint16_t)
29+
- any number of opaque bytes
30+
- CS: JPEG 2000 Codestream
31+
32+
***********************************/
33+
34+
class MemoryReader
35+
{
36+
public:
37+
MemoryReader (uint8_t* buffer, size_t max_sz)
38+
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
39+
40+
uint32_t pull_uint32 ()
41+
{
42+
if (this->end - this->cur < 4)
43+
throw std::out_of_range ("Insufficient data to pull uint32_t");
44+
45+
uint32_t v = *this->cur++;
46+
v = (v << 8) + *this->cur++;
47+
v = (v << 8) + *this->cur++;
48+
return (v << 8) + *cur++;
49+
}
50+
51+
uint16_t pull_uint16 ()
52+
{
53+
if (this->end - this->cur < 2)
54+
throw std::out_of_range ("Insufficient data to pull uint16_t");
55+
56+
uint32_t v = *cur++;
57+
return (v << 8) + *cur++;
58+
}
59+
60+
protected:
61+
uint8_t* buffer;
62+
uint8_t* cur;
63+
uint8_t* end;
64+
};
65+
66+
class MemoryWriter
67+
{
68+
public:
69+
MemoryWriter (uint8_t* buffer, size_t max_sz)
70+
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
71+
72+
void push_uint32 (uint32_t value)
73+
{
74+
if (this->end - this->cur < 4)
75+
throw std::out_of_range ("Insufficient data to push uint32_t");
76+
77+
*this->cur++ = (value >> 24) & 0xFF;
78+
*this->cur++ = (value >> 16) & 0xFF;
79+
*this->cur++ = (value >> 8) & 0xFF;
80+
*this->cur++ = value & 0xFF;
81+
}
82+
83+
void push_uint16 (uint16_t value)
84+
{
85+
if (this->end - this->cur < 2)
86+
throw std::out_of_range ("Insufficient data to push uint32_t");
87+
88+
*this->cur++ = (value >> 8) & 0xFF;
89+
*this->cur++ = value & 0xFF;
90+
}
91+
92+
size_t get_size () { return this->cur - this->buffer; }
93+
94+
uint8_t* get_buffer () { return this->buffer; }
95+
96+
uint8_t* get_cur () { return this->cur; }
97+
98+
protected:
99+
uint8_t* buffer;
100+
uint8_t* cur;
101+
uint8_t* end;
102+
};
103+
104+
constexpr uint16_t HEADER_MARKER = 'H' * 256 + 'T';
105+
106+
size_t
107+
write_header (
108+
uint8_t* buffer,
109+
size_t max_sz,
110+
const std::vector<CodestreamChannelInfo>& map)
111+
{
112+
constexpr uint16_t HEADER_SZ = 6;
113+
MemoryWriter payload (buffer + HEADER_SZ, max_sz - HEADER_SZ);
114+
payload.push_uint16 (map.size ());
115+
for (size_t i = 0; i < map.size (); i++)
116+
{
117+
payload.push_uint16 (map.at (i).file_index);
118+
}
119+
120+
MemoryWriter header (buffer, max_sz);
121+
header.push_uint16 (HEADER_MARKER);
122+
header.push_uint32 (payload.get_size ());
123+
124+
return header.get_size () + payload.get_size ();
125+
}
126+
127+
void
128+
read_header (
129+
void* buffer,
130+
size_t max_sz,
131+
size_t& length,
132+
std::vector<CodestreamChannelInfo>& map)
133+
{
134+
MemoryReader header ((uint8_t*) buffer, max_sz);
135+
if (header.pull_uint16 () != HEADER_MARKER)
136+
throw std::runtime_error (
137+
"HT256 chunk header missing does not start with magic number.");
138+
139+
length = header.pull_uint32 ();
140+
141+
if (length < 2)
142+
throw std::runtime_error ("Error while reading the channel map");
143+
144+
map.resize (header.pull_uint16 ());
145+
for (size_t i = 0; i < map.size (); i++)
146+
{
147+
map.at (i).file_index = header.pull_uint16 ();
148+
}
149+
}
150+
20151
extern "C" exr_result_t
21152
internal_exr_undo_ht (
22153
exr_decode_pipeline_t* decode,
@@ -28,12 +159,33 @@ internal_exr_undo_ht (
28159
exr_result_t rv = EXR_ERR_SUCCESS;
29160

30161
std::vector<CodestreamChannelInfo> cs_to_file_ch (decode->channel_count);
31-
bool isRGB = make_channel_map (
32-
decode->channel_count, decode->channels, cs_to_file_ch);
162+
163+
/* read the channel map */
164+
165+
size_t header_sz;
166+
read_header (
167+
(uint8_t*) compressed_data, comp_buf_size, header_sz, cs_to_file_ch);
168+
if (decode->channel_count != cs_to_file_ch.size ())
169+
throw std::runtime_error ("Unexpected number of channels");
170+
171+
std::vector<size_t> offsets (decode->channel_count);
172+
offsets[0] = 0;
173+
for (int file_i = 1; file_i < decode->channel_count; file_i++)
174+
{
175+
offsets[file_i] = offsets[file_i - 1] +
176+
decode->channels[file_i - 1].width *
177+
decode->channels[file_i - 1].bytes_per_element;
178+
}
179+
for (int cs_i = 0; cs_i < decode->channel_count; cs_i++)
180+
{
181+
cs_to_file_ch[cs_i].raster_line_offset =
182+
offsets[cs_to_file_ch[cs_i].file_index];
183+
}
33184

34185
ojph::mem_infile infile;
35186
infile.open (
36-
reinterpret_cast<const ojph::ui8*> (compressed_data), comp_buf_size);
187+
reinterpret_cast<const ojph::ui8*> (compressed_data) + header_sz,
188+
comp_buf_size - header_sz);
37189

38190
ojph::codestream cs;
39191
cs.read_headers (&infile);
@@ -192,7 +344,8 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
192344
int file_c = cs_to_file_ch[c].file_index;
193345
if (encode->channels[file_c].data_type != EXR_PIXEL_UINT)
194346
nlt.set_nonlinear_transform (
195-
c, ojph::param_nlt::nonlinearity::OJPH_NLT_BINARY_COMPLEMENT_NLT);
347+
c,
348+
ojph::param_nlt::nonlinearity::OJPH_NLT_BINARY_COMPLEMENT_NLT);
196349
siz.set_component (
197350
c,
198351
ojph::point (
@@ -326,13 +479,20 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
326479

327480
cs.flush ();
328481

329-
assert (output.tell () >= 0);
482+
size_t header_sz = write_header (
483+
(uint8_t*) encode->compressed_buffer,
484+
encode->packed_bytes,
485+
cs_to_file_ch);
330486

487+
assert (output.tell () >= 0);
331488
int compressed_sz = static_cast<size_t> (output.tell ());
332-
if (compressed_sz < encode->packed_bytes)
489+
if (compressed_sz + header_sz < encode->packed_bytes)
333490
{
334-
memcpy (encode->compressed_buffer, output.get_data (), compressed_sz);
335-
encode->compressed_bytes = compressed_sz;
491+
memcpy (
492+
((uint8_t*) encode->compressed_buffer) + header_sz,
493+
output.get_data (),
494+
compressed_sz);
495+
encode->compressed_bytes = compressed_sz + header_sz;
336496
}
337497
else
338498
{

src/lib/OpenEXRCore/internal_ht_common.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ make_channel_map (
2929

3030
bool isRGB = r_index >= 0 && g_index >= 0 && b_index >= 0 &&
3131
channels[r_index].data_type == channels[g_index].data_type &&
32-
channels[r_index].data_type == channels[b_index].data_type;
32+
channels[r_index].data_type == channels[b_index].data_type &&
33+
channels[r_index].x_samples == channels[g_index].x_samples &&
34+
channels[r_index].x_samples == channels[b_index].x_samples &&
35+
channels[r_index].y_samples == channels[g_index].y_samples &&
36+
channels[r_index].y_samples == channels[b_index].y_samples;
3337

3438
if (isRGB)
3539
{

0 commit comments

Comments
 (0)