|
12 | 12 | #include <ojph_params.h> |
13 | 13 | #include <ojph_mem.h> |
14 | 14 | #include <ojph_codestream.h> |
| 15 | +#include <ojph_message.h> |
15 | 16 |
|
16 | 17 | #include "openexr_decode.h" |
17 | 18 | #include "openexr_encode.h" |
@@ -148,6 +149,146 @@ read_header ( |
148 | 149 | } |
149 | 150 | } |
150 | 151 |
|
| 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 | + |
151 | 292 | extern "C" exr_result_t |
152 | 293 | internal_exr_undo_ht ( |
153 | 294 | exr_decode_pipeline_t* decode, |
@@ -374,128 +515,121 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode) |
374 | 515 | cod.set_block_dims (128, 32); |
375 | 516 | cod.set_num_decomposition (5); |
376 | 517 |
|
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); |
378 | 523 |
|
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); |
380 | 527 |
|
381 | | - cs.write_headers (&output); |
| 528 | + try { |
| 529 | + cs.write_headers (&output); |
382 | 530 |
|
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); |
385 | 533 |
|
386 | | - if (cs.is_planar ()) |
387 | | - { |
388 | | - for (ojph::ui32 c = 0; c < encode->channel_count; c++) |
| 534 | + if (cs.is_planar ()) |
389 | 535 | { |
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; |
391 | 539 |
|
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; |
395 | 543 |
|
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++) |
402 | 547 | { |
| 548 | + for (ojph::ui32 line_c = 0; line_c < encode->channel_count; |
| 549 | + line_c++) |
| 550 | + { |
403 | 551 |
|
404 | | - if (y % encode->channels[line_c].y_samples != 0) continue; |
| 552 | + if (y % encode->channels[line_c].y_samples != 0) continue; |
405 | 553 |
|
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) |
410 | 555 | { |
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) |
415 | 558 | { |
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 | + } |
417 | 566 | } |
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 |
425 | 568 | { |
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 | + } |
427 | 576 | } |
| 577 | + |
| 578 | + assert (next_comp == c); |
| 579 | + cur_line = cs.exchange (cur_line, next_comp); |
428 | 580 | } |
429 | 581 |
|
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; |
432 | 584 | } |
433 | | - |
434 | | - line_pixels += encode->channels[line_c].bytes_per_element * |
435 | | - encode->channels[line_c].width; |
436 | 585 | } |
437 | 586 | } |
438 | 587 | } |
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); |
444 | 592 |
|
445 | | - assert (bpl * image_height == encode->packed_bytes); |
| 593 | + assert (bpl * image_height == encode->packed_bytes); |
446 | 594 |
|
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++) |
450 | 596 | { |
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++) |
454 | 598 | { |
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) |
459 | 602 | { |
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 | + } |
461 | 610 | } |
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 |
469 | 612 | { |
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 | + } |
471 | 620 | } |
| 621 | + assert (next_comp == c); |
| 622 | + cur_line = cs.exchange (cur_line, next_comp); |
472 | 623 | } |
473 | | - assert (next_comp == c); |
474 | | - cur_line = cs.exchange (cur_line, next_comp); |
| 624 | + line_pixels += bpl; |
475 | 625 | } |
476 | | - line_pixels += bpl; |
477 | 626 | } |
478 | | - } |
479 | | - |
480 | | - cs.flush (); |
481 | 627 |
|
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 (); |
486 | 629 |
|
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) { |
499 | 633 | encode->compressed_bytes = encode->packed_bytes; |
500 | 634 | } |
501 | 635 |
|
|
0 commit comments