From 2a3f1c5447c595ad747e232bcbd9f743baf11763 Mon Sep 17 00:00:00 2001 From: Pierre-Anthony Lemieux Date: Thu, 12 Dec 2024 16:13:10 -0800 Subject: [PATCH] Add support for 32-bit and sub-sampling --- cmake/OpenEXRSetup.cmake | 2 +- src/lib/OpenEXRCore/internal_ht.cpp | 292 +++++++++++++++++---- src/lib/OpenEXRCore/internal_ht_common.cpp | 50 ++-- src/lib/OpenEXRCore/internal_ht_common.h | 7 +- src/lib/OpenEXRCore/internal_htk.cpp | 2 +- 5 files changed, 278 insertions(+), 75 deletions(-) diff --git a/cmake/OpenEXRSetup.cmake b/cmake/OpenEXRSetup.cmake index e8618d7d1..fc0340cbe 100644 --- a/cmake/OpenEXRSetup.cmake +++ b/cmake/OpenEXRSetup.cmake @@ -270,7 +270,7 @@ include(FetchContent) FetchContent_Declare( openjph GIT_REPOSITORY https://github.com/aous72/OpenJPH - GIT_TAG origin/master + GIT_TAG 0.18.2 ) FetchContent_MakeAvailable(openjph) diff --git a/src/lib/OpenEXRCore/internal_ht.cpp b/src/lib/OpenEXRCore/internal_ht.cpp index e40d41225..52a754287 100644 --- a/src/lib/OpenEXRCore/internal_ht.cpp +++ b/src/lib/OpenEXRCore/internal_ht.cpp @@ -3,6 +3,8 @@ ** Copyright Contributors to the OpenEXR Project. */ +#include + #include "internal_compress.h" #include "internal_decompress.h" @@ -32,8 +34,8 @@ internal_exr_undo_ht ( { exr_result_t rv = EXR_ERR_SUCCESS; - std::vector cs_to_file_ch (decode->channel_count); - bool isRGB = make_channel_map ( + std::vector cs_to_file_ch (decode->channel_count); + bool isRGB = make_channel_map ( decode->channel_count, decode->channels, cs_to_file_ch); ojph::mem_infile infile; @@ -44,41 +46,131 @@ internal_exr_undo_ht ( cs.read_headers (&infile); ojph::param_siz siz = cs.access_siz (); - ojph::ui32 width = siz.get_image_extent ().x - siz.get_image_offset ().x; - ojph::ui32 height = siz.get_image_extent ().y - siz.get_image_offset ().y; + ojph::param_nlt nlt = cs.access_nlt (); - assert (decode->chunk.width == width); - assert (decode->chunk.height == height); - assert (decode->channel_count == siz.get_num_components ()); + ojph::ui32 image_width = + siz.get_image_extent ().x - siz.get_image_offset ().x; + ojph::ui32 image_height = + siz.get_image_extent ().y - siz.get_image_offset ().y; - assert (decode->channel_count * 2 * width * height == uncompressed_size); + int bpl = 0; + bool is_planar = false; + for (ojph::ui32 c = 0; c < decode->channel_count; c++) + { + bpl += + decode->channels[c].bytes_per_element * decode->channels[c].width; + if (decode->channels[c].x_samples > 1 || + decode->channels[c].y_samples > 1) + { is_planar = true; } + } + cs.set_planar (is_planar); - cs.set_planar (false); + assert (decode->chunk.width == image_width); + assert (decode->chunk.height == image_height); + assert (decode->channel_count == siz.get_num_components ()); cs.create (); - assert (sizeof (int16_t) == 2); - int16_t* line_pixels = static_cast (uncompressed_data); - - for (uint32_t i = 0; i < height; ++i) + assert (sizeof (uint16_t) == 2); + assert (sizeof (uint32_t) == 4); + ojph::ui32 next_comp = 0; + ojph::line_buf* cur_line; + if (cs.is_planar ()) { - for (uint32_t c = 0; c < decode->channel_count; c++) { - ojph::ui32 next_comp = 0; - ojph::line_buf* cur_line = cs.pull (next_comp); + int file_c = cs_to_file_ch[c].file_index; + assert ( + siz.get_recon_height (c) == decode->channels[file_c].height); + assert (decode->channels[file_c].width == siz.get_recon_width (c)); - assert (next_comp == c); + if (decode->channels[file_c].height == 0) continue; - int16_t* channel_pixels = line_pixels + width * cs_to_file_ch[c]; + uint8_t* line_pixels = static_cast (uncompressed_data); - for (uint32_t p = 0; p < width; p++) + for (int64_t y = decode->chunk.start_y; + y < image_height + decode->chunk.start_y; + y++) { - *channel_pixels++ = (int16_t) (cur_line->i32[p]); + for (ojph::ui32 line_c = 0; line_c < decode->channel_count; + line_c++) + { + if (y % decode->channels[line_c].y_samples != 0) continue; + + if (line_c == file_c) + { + cur_line = cs.pull (next_comp); + assert (next_comp == c); + + if (decode->channels[file_c].data_type == + EXR_PIXEL_HALF) + { + int16_t* channel_pixels = (int16_t*) line_pixels; + for (uint32_t p = 0; + p < decode->channels[file_c].width; + p++) + { + *channel_pixels++ = cur_line->i32[p]; + // assert (*(channel_pixels - 1) == 0); + } + } + else + { + int32_t* channel_pixels = (int32_t*) line_pixels; + for (uint32_t p = 0; + p < decode->channels[file_c].width; + p++) + { + *channel_pixels++ = cur_line->i32[p]; + // assert (*(channel_pixels - 1) == 0); + } + } + } + + line_pixels += decode->channels[line_c].bytes_per_element * + decode->channels[line_c].width; + } } } + } + else + { + uint8_t* line_pixels = static_cast (uncompressed_data); - line_pixels += width * decode->channel_count; + assert (bpl * image_height == uncompressed_size); + + for (uint32_t y = 0; y < image_height; ++y) + { + for (uint32_t c = 0; c < decode->channel_count; c++) + { + int file_c = cs_to_file_ch[c].file_index; + cur_line = cs.pull (next_comp); + assert (next_comp == c); + if (decode->channels[file_c].data_type == EXR_PIXEL_HALF) + { + int16_t* channel_pixels = + (int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset); + for (uint32_t p = 0; p < decode->channels[file_c].width; + p++) + { + *channel_pixels++ = cur_line->i32[p]; + // assert (*(channel_pixels - 1) == 0); + } + } + else + { + int32_t* channel_pixels = + (int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset); + for (uint32_t p = 0; p < decode->channels[file_c].width; + p++) + { + *channel_pixels++ = cur_line->i32[p]; + // assert (*(channel_pixels - 1) == 0); + } + } + } + line_pixels += bpl; + } } infile.close (); @@ -91,71 +183,162 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode) { exr_result_t rv = EXR_ERR_SUCCESS; - std::vector cs_to_file_ch(encode->channel_count); - bool isRGB = make_channel_map ( + std::vector cs_to_file_ch (encode->channel_count); + bool isRGB = make_channel_map ( encode->channel_count, encode->channels, cs_to_file_ch); - int height = encode->channels[0].height; - int width = encode->channels[0].width; + int image_height = encode->chunk.height; + int image_width = encode->chunk.width; ojph::codestream cs; - cs.set_planar (false); ojph::param_siz siz = cs.access_siz (); + ojph::param_nlt nlt = cs.access_nlt (); + bool isPlanar = false; siz.set_num_components (encode->channel_count); + int bpl = 0; for (ojph::ui32 c = 0; c < encode->channel_count; c++) - siz.set_component (c, ojph::point (1, 1), 16, true); + { + int file_c = cs_to_file_ch[c].file_index; + nlt.set_type3_transformation ( + c, encode->channels[file_c].data_type != EXR_PIXEL_UINT); + + siz.set_component ( + c, + ojph::point ( + encode->channels[file_c].x_samples, + encode->channels[file_c].y_samples), + encode->channels[file_c].data_type == EXR_PIXEL_HALF ? 16 : 32, + encode->channels[file_c].data_type != EXR_PIXEL_UINT); + + if (encode->channels[file_c].x_samples > 1 || + encode->channels[file_c].y_samples > 1) + { isPlanar = true; } + + // std::cout << " Component number, color, bitdepth: " << c << ", " << encode->channels[file_c].channel_name << ", " << siz.get_bit_depth(c) << std::endl; + + bpl += encode->channels[file_c].bytes_per_element * + encode->channels[file_c].width; + } + + cs.set_planar (isPlanar); siz.set_image_offset (ojph::point (0, 0)); - siz.set_tile_offset (ojph::point (0, 0)); - siz.set_image_extent (ojph::point (width, height)); - siz.set_tile_size (ojph::size (width, height)); + siz.set_image_extent (ojph::point (image_width, image_height)); ojph::param_cod cod = cs.access_cod (); - cod.set_color_transform (isRGB); + cod.set_color_transform (isRGB && !isPlanar); cod.set_reversible (true); cod.set_block_dims (128, 32); cod.set_num_decomposition (5); - ojph::param_nlt nlt = cs.access_nlt(); - nlt.set_type3_transformation(65535, true); - ojph::mem_outfile output; output.open (); cs.write_headers (&output); - assert ( - encode->packed_bytes == (encode->channel_count * 2 * height * width)); - - const int16_t* line_pixels = - static_cast (encode->packed_buffer); ojph::ui32 next_comp = 0; ojph::line_buf* cur_line = cs.exchange (NULL, next_comp); - for (ojph::ui32 i = 0; i < height; ++i) + if (cs.is_planar ()) { - const char* in_buf; - for (ojph::ui32 c = 0; c < encode->channel_count; c++) { - assert (next_comp == c); + if (encode->channels[c].height == 0) continue; - const int16_t* channel_pixels = - line_pixels + width * cs_to_file_ch[c]; + const uint8_t* line_pixels = + static_cast (encode->packed_buffer); + int file_c = cs_to_file_ch[c].file_index; - for (uint32_t p = 0; p < width; p++) + for (int64_t y = encode->chunk.start_y; + y < image_height + encode->chunk.start_y; + y++) { - cur_line->i32[p] = static_cast (*channel_pixels++); + for (ojph::ui32 line_c = 0; line_c < encode->channel_count; + line_c++) + { + + if (y % encode->channels[line_c].y_samples != 0) continue; + + if (line_c == file_c) + { + if (encode->channels[file_c].data_type == + EXR_PIXEL_HALF) + { + int16_t* channel_pixels = (int16_t*) (line_pixels); + for (uint32_t p = 0; + p < encode->channels[file_c].width; + p++) + { + // assert (*channel_pixels == 0); + cur_line->i32[p] = *channel_pixels++; + } + } + else + { + int32_t* channel_pixels = (int32_t*) (line_pixels); + for (uint32_t p = 0; + p < encode->channels[file_c].width; + p++) + { + // assert (*channel_pixels == 0); + cur_line->i32[p] = *channel_pixels++; + } + } + + assert (next_comp == c); + cur_line = cs.exchange (cur_line, next_comp); + } + + line_pixels += encode->channels[line_c].bytes_per_element * + encode->channels[line_c].width; + } } - - cur_line = cs.exchange (cur_line, next_comp); } + } + else + { + const uint8_t* line_pixels = + static_cast (encode->packed_buffer); - line_pixels += width * encode->channel_count; + assert (bpl * image_height == encode->packed_bytes); + + for (int y = 0; y < image_height; y++) + { + for (ojph::ui32 c = 0; c < encode->channel_count; c++) + { + int file_c = cs_to_file_ch[c].file_index; + + if (encode->channels[file_c].data_type == EXR_PIXEL_HALF) + { + int16_t* channel_pixels = + (int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset); + for (uint32_t p = 0; p < encode->channels[file_c].width; + p++) + { + cur_line->i32[p] = *channel_pixels++; + //assert (cur_line->i32[p] == 0); + } + } + else + { + int32_t* channel_pixels = + (int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset); + for (uint32_t p = 0; p < encode->channels[file_c].width; + p++) + { + cur_line->i32[p] = *channel_pixels++; + //assert (cur_line->i32[p] == 0); + } + } + assert (next_comp == c); + cur_line = cs.exchange (cur_line, next_comp); + } + line_pixels += bpl; + } } cs.flush (); @@ -164,12 +347,19 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode) int compressed_sz = static_cast (output.tell ()); + // std::ofstream outf ("out7.j2c", std::ios::binary); + // outf.write ((char*) output.get_data (), compressed_sz); + // outf.close (); + if (compressed_sz < encode->packed_bytes) { memcpy (encode->compressed_buffer, output.get_data (), compressed_sz); encode->compressed_bytes = compressed_sz; } - else { encode->compressed_bytes = encode->packed_bytes; } + else + { + encode->compressed_bytes = encode->packed_bytes; + } return rv; } diff --git a/src/lib/OpenEXRCore/internal_ht_common.cpp b/src/lib/OpenEXRCore/internal_ht_common.cpp index 36ec92940..14a5fdaa2 100644 --- a/src/lib/OpenEXRCore/internal_ht_common.cpp +++ b/src/lib/OpenEXRCore/internal_ht_common.cpp @@ -19,7 +19,7 @@ bool make_channel_map ( - int channel_count, exr_coding_channel_info_t* channels, std::vector& cs_to_file_ch) + int channel_count, exr_coding_channel_info_t* channels, std::vector& cs_to_file_ch) { int r_index = -1; int g_index = -1; @@ -29,10 +29,6 @@ make_channel_map ( for (size_t i = 0; i < channel_count; i++) { - assert (channels[i].data_type == EXR_PIXEL_HALF); - assert (channels[i].x_samples == 1); - assert (channels[i].y_samples == 1); - std::string c_name(channels[i].channel_name); if (c_name == "R") { r_index = i; } @@ -40,32 +36,44 @@ make_channel_map ( else if (c_name == "B") { b_index = i; } } - bool isRGB; + bool isRGB = r_index >= 0 && g_index >= 0 && b_index >= 0 && + channels[r_index].data_type == channels[g_index].data_type && + channels[r_index].data_type == channels[b_index].data_type; - if (r_index >= 0 && g_index >= 0 && b_index >= 0) + if (isRGB) { - isRGB = true; - - cs_to_file_ch[0] = r_index; - cs_to_file_ch[1] = g_index; - cs_to_file_ch[2] = b_index; + cs_to_file_ch[0].file_index = r_index; + cs_to_file_ch[1].file_index = g_index; + cs_to_file_ch[2].file_index = b_index; - int cs_i = 3; - for (size_t i = 0; i < channel_count; i++) + int avail_cs_i = 3; + int offset = 0; + for (size_t file_i = 0; file_i < channel_count; file_i++) { - if (i != r_index && i != g_index && i != b_index) - { - cs_to_file_ch[cs_i++] = i; + int cs_i; + if (file_i == r_index) { + cs_i = 0; + } else if (file_i == g_index) { + cs_i = 1; + } else if (file_i == b_index) { + cs_i = 2; + } else { + cs_i = avail_cs_i++; } + + cs_to_file_ch[cs_i].file_index = file_i; + cs_to_file_ch[cs_i].raster_line_offset = offset; + offset += channels[file_i].width * channels[file_i].bytes_per_element; } } else { - isRGB = false; - - for (size_t i = 0; i < channel_count; i++) + int offset = 0; + for (size_t file_i = 0; file_i < channel_count; file_i++) { - cs_to_file_ch[i] = i; + cs_to_file_ch[file_i].file_index = file_i; + cs_to_file_ch[file_i].raster_line_offset = offset; + offset += channels[file_i].width * channels[file_i].bytes_per_element; } } diff --git a/src/lib/OpenEXRCore/internal_ht_common.h b/src/lib/OpenEXRCore/internal_ht_common.h index 1c357b35d..ad71dd1f2 100644 --- a/src/lib/OpenEXRCore/internal_ht_common.h +++ b/src/lib/OpenEXRCore/internal_ht_common.h @@ -17,8 +17,13 @@ #include "openexr_compression.h" +struct CodestreamChannelInfo { + int file_index; + size_t raster_line_offset; +}; + bool make_channel_map ( - int channel_count, exr_coding_channel_info_t* channels, std::vector& cs_to_file_ch); + int channel_count, exr_coding_channel_info_t* channels, std::vector& cs_to_file_ch); #endif /* OPENEXR_PRIVATE_HT_COMMON_H */ diff --git a/src/lib/OpenEXRCore/internal_htk.cpp b/src/lib/OpenEXRCore/internal_htk.cpp index 902bb93ba..6519a9474 100644 --- a/src/lib/OpenEXRCore/internal_htk.cpp +++ b/src/lib/OpenEXRCore/internal_htk.cpp @@ -17,7 +17,7 @@ #include #include -#ifdef KDU_AVAILABLE +#if 0 # include "openexr_compression.h" # include "kdu_elementary.h"