Skip to content

Commit 45ee127

Browse files
authored
Remove realloc from HTJ2K coder (#2061)
Signed-off-by: Pierre-Anthony Lemieux <pal@palemieux.com>
1 parent d8a5996 commit 45ee127

File tree

1 file changed

+222
-88
lines changed

1 file changed

+222
-88
lines changed

src/lib/OpenEXRCore/internal_ht.cpp

Lines changed: 222 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <ojph_params.h>
1313
#include <ojph_mem.h>
1414
#include <ojph_codestream.h>
15+
#include <ojph_message.h>
1516

1617
#include "openexr_decode.h"
1718
#include "openexr_encode.h"
@@ -148,6 +149,146 @@ read_header (
148149
}
149150
}
150151

152+
/**
153+
* OpenJPH output file that is backed by a fixed-size memory buffer
154+
*/
155+
class staticmem_outfile : public ojph::outfile_base
156+
{
157+
public:
158+
/** A constructor */
159+
staticmem_outfile() {
160+
is_open = false;
161+
max_size = used_size = 0;
162+
buf = cur_ptr = NULL;
163+
}
164+
/** A destructor */
165+
~staticmem_outfile() override {
166+
is_open = false;
167+
max_size = used_size = 0;
168+
buf = cur_ptr = NULL;
169+
}
170+
171+
/**
172+
* @brief Call this function to write a codestream to an existing memory buffer
173+
*
174+
*
175+
* @param buf pointer to existing memory buffer.
176+
* @param buf_size size of the existing memory buffer.
177+
*/
178+
void open(void* buf, size_t buf_size) {
179+
assert(this->is_open == false);
180+
181+
this->is_open = true;
182+
this->max_size = buf_size;
183+
this->used_size = 0;
184+
this->buf = (ojph::ui8*) buf;
185+
this->cur_ptr = this->buf;
186+
}
187+
188+
/**
189+
* @brief Call this function to write data to the memory file.
190+
*
191+
* This function adds new data to the memory file. The memory buffer
192+
* of the file grows as needed.
193+
*
194+
* @param ptr is a pointer to new data.
195+
* @param size the number of bytes in the new data.
196+
*/
197+
size_t write (const void* ptr, size_t sz)
198+
{
199+
assert (this->is_open);
200+
assert (this->max_size);
201+
assert (this->buf);
202+
assert (this->cur_ptr);
203+
204+
size_t needed_size = (size_t) tell () + sz; //needed size
205+
if (needed_size > this->max_size) {
206+
throw std::range_error("Buffer size exceeded");
207+
}
208+
209+
// copy bytes into buffer and adjust cur_ptr
210+
memcpy (this->cur_ptr, ptr, sz);
211+
cur_ptr += sz;
212+
used_size = ojph_max (used_size, (size_t) tell ());
213+
214+
return sz;
215+
}
216+
/**
217+
* @brief Call this function to know the file size (i.e., number of
218+
* bytes used to store the file).
219+
*
220+
* @return the file size.
221+
*/
222+
ojph::si64 tell() override { return cur_ptr - buf; }
223+
224+
/**
225+
* @brief Call this function to change write pointer location; the
226+
* function can expand file storage.
227+
*
228+
* @return 0 on success, non-zero otherwise.
229+
*/
230+
int seek (ojph::si64 offset, enum outfile_base::seek origin) override
231+
{
232+
if (origin == OJPH_SEEK_SET)
233+
; // do nothing
234+
else if (origin == OJPH_SEEK_CUR)
235+
offset += tell ();
236+
else if (origin == OJPH_SEEK_END)
237+
offset += (ojph::si64) this->used_size;
238+
else
239+
{
240+
assert (0);
241+
return -1;
242+
}
243+
244+
cur_ptr = buf + offset;
245+
return 0;
246+
}
247+
248+
/** Call this function to close the file and deallocate memory
249+
*
250+
* The object can be used again after calling close
251+
*/
252+
void close() override{
253+
is_open = false;
254+
}
255+
256+
/**
257+
* @brief Call this function to access memory file data.
258+
*
259+
* It is not recommended to store the returned value because buffer
260+
* storage address can change between write calls.
261+
*
262+
* @return a constant pointer to the data.
263+
*/
264+
const ojph::ui8* get_data() { return buf; }
265+
266+
/**
267+
* @brief Call this function to access memory file data (for const
268+
* objects)
269+
*
270+
* This is similar to the above function, except that it can be used
271+
* with constant objects.
272+
*
273+
* @return a constant pointer to the data.
274+
*/
275+
const ojph::ui8* get_data() const { return buf; }
276+
277+
/**
278+
* Returns the size of the written data
279+
*
280+
* @return size of the data stored in the file
281+
*/
282+
size_t get_size() const { return this->used_size; }
283+
284+
private:
285+
bool is_open;
286+
size_t max_size;
287+
size_t used_size;
288+
ojph::ui8 *buf;
289+
ojph::ui8 *cur_ptr;
290+
};
291+
151292
extern "C" exr_result_t
152293
internal_exr_undo_ht (
153294
exr_decode_pipeline_t* decode,
@@ -374,128 +515,121 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
374515
cod.set_block_dims (128, 32);
375516
cod.set_num_decomposition (5);
376517

377-
ojph::mem_outfile output;
518+
/* write the header */
519+
size_t header_sz = write_header (
520+
(uint8_t*) encode->compressed_buffer,
521+
encode->packed_bytes,
522+
cs_to_file_ch);
378523

379-
output.open ();
524+
/* write the codestream */
525+
staticmem_outfile output;
526+
output.open ( ((uint8_t*) encode->compressed_buffer) + header_sz, encode->packed_bytes - header_sz);
380527

381-
cs.write_headers (&output);
528+
try {
529+
cs.write_headers (&output);
382530

383-
ojph::ui32 next_comp = 0;
384-
ojph::line_buf* cur_line = cs.exchange (NULL, next_comp);
531+
ojph::ui32 next_comp = 0;
532+
ojph::line_buf* cur_line = cs.exchange (NULL, next_comp);
385533

386-
if (cs.is_planar ())
387-
{
388-
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
534+
if (cs.is_planar ())
389535
{
390-
if (encode->channels[c].height == 0) continue;
536+
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
537+
{
538+
if (encode->channels[c].height == 0) continue;
391539

392-
const uint8_t* line_pixels =
393-
static_cast<const uint8_t*> (encode->packed_buffer);
394-
int file_c = cs_to_file_ch[c].file_index;
540+
const uint8_t* line_pixels =
541+
static_cast<const uint8_t*> (encode->packed_buffer);
542+
int file_c = cs_to_file_ch[c].file_index;
395543

396-
for (int64_t y = encode->chunk.start_y;
397-
y < image_height + encode->chunk.start_y;
398-
y++)
399-
{
400-
for (ojph::ui32 line_c = 0; line_c < encode->channel_count;
401-
line_c++)
544+
for (int64_t y = encode->chunk.start_y;
545+
y < image_height + encode->chunk.start_y;
546+
y++)
402547
{
548+
for (ojph::ui32 line_c = 0; line_c < encode->channel_count;
549+
line_c++)
550+
{
403551

404-
if (y % encode->channels[line_c].y_samples != 0) continue;
552+
if (y % encode->channels[line_c].y_samples != 0) continue;
405553

406-
if (line_c == file_c)
407-
{
408-
if (encode->channels[file_c].data_type ==
409-
EXR_PIXEL_HALF)
554+
if (line_c == file_c)
410555
{
411-
int16_t* channel_pixels = (int16_t*) (line_pixels);
412-
for (uint32_t p = 0;
413-
p < encode->channels[file_c].width;
414-
p++)
556+
if (encode->channels[file_c].data_type ==
557+
EXR_PIXEL_HALF)
415558
{
416-
cur_line->i32[p] = *channel_pixels++;
559+
int16_t* channel_pixels = (int16_t*) (line_pixels);
560+
for (uint32_t p = 0;
561+
p < encode->channels[file_c].width;
562+
p++)
563+
{
564+
cur_line->i32[p] = *channel_pixels++;
565+
}
417566
}
418-
}
419-
else
420-
{
421-
int32_t* channel_pixels = (int32_t*) (line_pixels);
422-
for (uint32_t p = 0;
423-
p < encode->channels[file_c].width;
424-
p++)
567+
else
425568
{
426-
cur_line->i32[p] = *channel_pixels++;
569+
int32_t* channel_pixels = (int32_t*) (line_pixels);
570+
for (uint32_t p = 0;
571+
p < encode->channels[file_c].width;
572+
p++)
573+
{
574+
cur_line->i32[p] = *channel_pixels++;
575+
}
427576
}
577+
578+
assert (next_comp == c);
579+
cur_line = cs.exchange (cur_line, next_comp);
428580
}
429581

430-
assert (next_comp == c);
431-
cur_line = cs.exchange (cur_line, next_comp);
582+
line_pixels += encode->channels[line_c].bytes_per_element *
583+
encode->channels[line_c].width;
432584
}
433-
434-
line_pixels += encode->channels[line_c].bytes_per_element *
435-
encode->channels[line_c].width;
436585
}
437586
}
438587
}
439-
}
440-
else
441-
{
442-
const uint8_t* line_pixels =
443-
static_cast<const uint8_t*> (encode->packed_buffer);
588+
else
589+
{
590+
const uint8_t* line_pixels =
591+
static_cast<const uint8_t*> (encode->packed_buffer);
444592

445-
assert (bpl * image_height == encode->packed_bytes);
593+
assert (bpl * image_height == encode->packed_bytes);
446594

447-
for (int y = 0; y < image_height; y++)
448-
{
449-
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
595+
for (int y = 0; y < image_height; y++)
450596
{
451-
int file_c = cs_to_file_ch[c].file_index;
452-
453-
if (encode->channels[file_c].data_type == EXR_PIXEL_HALF)
597+
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
454598
{
455-
int16_t* channel_pixels =
456-
(int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
457-
for (uint32_t p = 0; p < encode->channels[file_c].width;
458-
p++)
599+
int file_c = cs_to_file_ch[c].file_index;
600+
601+
if (encode->channels[file_c].data_type == EXR_PIXEL_HALF)
459602
{
460-
cur_line->i32[p] = *channel_pixels++;
603+
int16_t* channel_pixels =
604+
(int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
605+
for (uint32_t p = 0; p < encode->channels[file_c].width;
606+
p++)
607+
{
608+
cur_line->i32[p] = *channel_pixels++;
609+
}
461610
}
462-
}
463-
else
464-
{
465-
int32_t* channel_pixels =
466-
(int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
467-
for (uint32_t p = 0; p < encode->channels[file_c].width;
468-
p++)
611+
else
469612
{
470-
cur_line->i32[p] = *channel_pixels++;
613+
int32_t* channel_pixels =
614+
(int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
615+
for (uint32_t p = 0; p < encode->channels[file_c].width;
616+
p++)
617+
{
618+
cur_line->i32[p] = *channel_pixels++;
619+
}
471620
}
621+
assert (next_comp == c);
622+
cur_line = cs.exchange (cur_line, next_comp);
472623
}
473-
assert (next_comp == c);
474-
cur_line = cs.exchange (cur_line, next_comp);
624+
line_pixels += bpl;
475625
}
476-
line_pixels += bpl;
477626
}
478-
}
479-
480-
cs.flush ();
481627

482-
size_t header_sz = write_header (
483-
(uint8_t*) encode->compressed_buffer,
484-
encode->packed_bytes,
485-
cs_to_file_ch);
628+
cs.flush ();
486629

487-
assert (output.tell () >= 0);
488-
int compressed_sz = static_cast<size_t> (output.tell ());
489-
if (compressed_sz + header_sz < encode->packed_bytes)
490-
{
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;
496-
}
497-
else
498-
{
630+
assert (output.get_size () >= 0);
631+
encode->compressed_bytes = output.get_size () + header_sz;
632+
} catch (const std::range_error& e) {
499633
encode->compressed_bytes = encode->packed_bytes;
500634
}
501635

0 commit comments

Comments
 (0)