diff options
author | Merov Linden <merov@lindenlab.com> | 2012-03-25 11:52:10 -0700 |
---|---|---|
committer | Merov Linden <merov@lindenlab.com> | 2012-03-25 11:52:10 -0700 |
commit | 5c86d19373ebfab446e8335729faefabc66ad15f (patch) | |
tree | c93dc6d7da22c56ce5a4d3e2d248d5325323b50a | |
parent | 1ebcb8039369175f7f43fc19956f32c923cfe1ba (diff) |
SH-3050 : Parse an input codestream without decompressing it to find discard levels boundaries (test only).
-rw-r--r-- | indra/llkdu/llimagej2ckdu.cpp | 202 | ||||
-rw-r--r-- | indra/llkdu/llimagej2ckdu.h | 1 | ||||
-rw-r--r-- | indra/llkdu/tests/llimagej2ckdu_test.cpp | 20 |
3 files changed, 222 insertions, 1 deletions
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index eed4139f3f..8b170a3206 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -32,6 +32,7 @@ #include "llmath.h" #include "llkdumem.h" +#include "kdu_block_coding.h" class kdc_flow_control { @@ -244,7 +245,7 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod mCodeStreamp->create(mInputp); // Set the maximum number of bytes to use from the codestream - mCodeStreamp->set_max_bytes(max_bytes); + mCodeStreamp->set_max_bytes(max_bytes,true); // If you want to flip or rotate the image for some reason, change // the resolution, or identify a restricted region of interest, this is @@ -369,6 +370,9 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco // To regain control, we throw an exception, and catch it here. try { + // Merov : Test!! DO NOT COMMIT!! + //findDiscardLevelsBoundaries(base); + base.updateRawDiscardLevel(); setupCodeStream(base, TRUE, mode); @@ -752,6 +756,202 @@ BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base) } } +/*****************************************************************************/ +/* STATIC copy_block */ +/*****************************************************************************/ + +static void copy_block(kdu_block *in, kdu_block *out) +{ + if (in->K_max_prime != out->K_max_prime) + { + std::cout << "Cannot copy blocks belonging to subbands with different quantization parameters." << std::endl; + return; + } + if ((in->size.x != out->size.x) || (in->size.y != out->size.y)) + { + std::cout << "Cannot copy code-blocks with different dimensions." << std::endl; + return; + } + out->missing_msbs = in->missing_msbs; + if (out->max_passes < (in->num_passes+2)) // Gives us enough to round up + out->set_max_passes(in->num_passes+2,false); // to the next whole bit-plane + out->num_passes = in->num_passes; + int num_bytes = 0; + for (int z=0; z < in->num_passes; z++) + { + num_bytes += (out->pass_lengths[z] = in->pass_lengths[z]); + out->pass_slopes[z] = in->pass_slopes[z]; + } + + // Just copy compressed code-bytes. Block transcoding not supported. + if (out->max_bytes < num_bytes) + out->set_max_bytes(num_bytes,false); + memcpy(out->byte_buffer,in->byte_buffer,(size_t) num_bytes); +} + +/*****************************************************************************/ +/* STATIC copy_tile */ +/*****************************************************************************/ + +static void +copy_tile(kdu_tile tile_in, kdu_tile tile_out, int tnum_in, int tnum_out, + kdu_params *siz_in, kdu_params *siz_out, int skip_components, + int &num_blocks) +{ + int num_components = tile_out.get_num_components(); + int new_tpart=0, next_tpart = 1; + + for (int c=0; c < num_components; c++) + { + kdu_tile_comp comp_in, comp_out; + comp_in = tile_in.access_component(c); + comp_out = tile_out.access_component(c); + int num_resolutions = comp_out.get_num_resolutions(); + for (int r=0; r < num_resolutions; r++) + { + kdu_resolution res_in; res_in = comp_in.access_resolution(r); + kdu_resolution res_out; res_out = comp_out.access_resolution(r); + int b, min_band; + int num_bands = res_in.get_valid_band_indices(min_band); + for (b=min_band; num_bands > 0; num_bands--, b++) + { + kdu_subband band_in; band_in = res_in.access_subband(b); + kdu_subband band_out; band_out = res_out.access_subband(b); + kdu_dims blocks_in; band_in.get_valid_blocks(blocks_in); + kdu_dims blocks_out; band_out.get_valid_blocks(blocks_out); + if ((blocks_in.size.x != blocks_out.size.x) || + (blocks_in.size.y != blocks_out.size.y)) + { + std::cout << "Transcoding operation cannot proceed: Code-block partitions for the input and output code-streams do not agree." << std::endl; + return; + } + kdu_coords idx; + for (idx.y=0; idx.y < blocks_out.size.y; idx.y++) + { + for (idx.x=0; idx.x < blocks_out.size.x; idx.x++) + { + kdu_block *in = + band_in.open_block(idx+blocks_in.pos,&new_tpart); + for (; next_tpart <= new_tpart; next_tpart++) + siz_out->copy_from(siz_in,tnum_in,tnum_out,next_tpart, + skip_components); + kdu_block *out = band_out.open_block(idx+blocks_out.pos); + copy_block(in,out); + band_in.close_block(in); + band_out.close_block(out); + num_blocks++; + } + } + } + } + } +} + +// Find the block boundary for each discard level in the input image. +// We parse the input blocks and copy them in a temporary output stream. +// For the moment, we do nothing more that parsing the raw list of blocks and outputing result. +void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base) +{ + // We need the number of levels in that image before starting. + getMetadata(base); + + for (int discard_level = 0; discard_level < mLevels; discard_level++) + { + // Create the input codestream object. + setupCodeStream(base, TRUE, MODE_FAST); + mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL); + //mCodeStreamp->set_max_bytes(max,true); + siz_params *siz_in = mCodeStreamp->access_siz(); + + // Create the output codestream object. + siz_params siz; + siz.copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false); + siz.set(Scomponents,0,0,mCodeStreamp->get_num_components()); + + U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents(); + max_output_size = (max_output_size < 1000 ? 1000 : max_output_size); + U8 *output_buffer = new U8[max_output_size]; + U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size + LLKDUMemTarget output(output_buffer, output_size, max_output_size); + kdu_codestream codestream_out; + codestream_out.create(&siz,&output); + //codestream_out.share_buffering(*mCodeStreamp); + siz_params *siz_out = codestream_out.access_siz(); + siz_out->copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false); + codestream_out.access_siz()->finalize_all(-1); + + // Set up rate control variables + kdu_long max_bytes = KDU_LONG_MAX; + kdu_params *cod = siz_out->access_cluster(COD_params); + int total_layers; cod->get(Clayers,0,0,total_layers); + kdu_long *layer_bytes = new kdu_long[total_layers]; + int nel, non_empty_layers = 0; + + // Now ready to perform the transfer of compressed data between streams + int flush_counter = INT_MAX; + kdu_dims tile_indices_in; + mCodeStreamp->get_valid_tiles(tile_indices_in); + kdu_dims tile_indices_out; + codestream_out.get_valid_tiles(tile_indices_out); + assert((tile_indices_in.size.x == tile_indices_out.size.x) && + (tile_indices_in.size.y == tile_indices_out.size.y)); + int num_blocks=0; + + kdu_coords idx; + for (idx.y=0; idx.y < tile_indices_out.size.y; idx.y++) + { + for (idx.x=0; idx.x < tile_indices_out.size.x; idx.x++) + { + kdu_tile tile_in = mCodeStreamp->open_tile(idx+tile_indices_in.pos); + int tnum_in = tile_in.get_tnum(); + int tnum_out = idx.x + idx.y*tile_indices_out.size.x; + siz_out->copy_from(siz_in,tnum_in,tnum_out,0,0,discard_level,false,false,false); + siz_out->finalize_all(tnum_out); + // Note: do not open the output tile without first copying any tile-specific code-stream parameters + kdu_tile tile_out = codestream_out.open_tile(idx+tile_indices_out.pos); + assert(tnum_out == tile_out.get_tnum()); + copy_tile(tile_in,tile_out,tnum_in,tnum_out,siz_in,siz_out,0,num_blocks); + tile_in.close(); + tile_out.close(); + flush_counter--; + if ((flush_counter <= 0) && codestream_out.ready_for_flush()) + { + flush_counter = INT_MAX; + nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers); + non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers; + } + } + } + + // Generate the output code-stream + if (codestream_out.ready_for_flush()) + { + nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers); + non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers; + } + if (non_empty_layers > total_layers) + non_empty_layers = total_layers; // Can happen if a tile has more layers + + // Print out stats + std::cout << "Code stream parsing for discard level = " << discard_level << std::endl; + std::cout << " Total compressed memory in = " << mCodeStreamp->get_compressed_data_memory() << " bytes" << std::endl; + std::cout << " Total compressed memory out = " << codestream_out.get_compressed_data_memory() << " bytes" << std::endl; + //std::cout << " Output contains " << total_layers << " quality layers" << std::endl; + std::cout << " Transferred " << num_blocks << " code-blocks from in to out" << std::endl; + //std::cout << " Read " << mCodeStreamp->get_num_tparts() << " tile-part(s) from a total of " << (int) tile_indices_in.area() << " tile(s)" << std::endl; + std::cout << " Total bytes read = " << mCodeStreamp->get_total_bytes() << std::endl; + //std::cout << " Wrote " << codestream_out.get_num_tparts() << " tile-part(s) in a total of " << (int) tile_indices_out.area() << " tile(s)" << std::endl; + std::cout << " Total bytes written = " << codestream_out.get_total_bytes() << std::endl; + std::cout << "-------------" << std::endl; + + // Clean-up + cleanupCodeStream(); + codestream_out.destroy(); + delete[] output_buffer; + } + return; +} + void set_default_colour_weights(kdu_params *siz) { kdu_params *cod = siz->access_cluster(COD_params); diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h index 1489dbf704..9ab0b9e4a7 100644 --- a/indra/llkdu/llimagej2ckdu.h +++ b/indra/llkdu/llimagej2ckdu.h @@ -60,6 +60,7 @@ protected: BOOL reversible=FALSE); /*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL); /*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0); + void findDiscardLevelsBoundaries(LLImageJ2C &base); private: BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL); diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp index ab60ab6d50..feb6671e40 100644 --- a/indra/llkdu/tests/llimagej2ckdu_test.cpp +++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp @@ -29,6 +29,7 @@ // Class to test #include "llimagej2ckdu.h" #include "llkdumem.h" +#include "kdu_block_coding.h" // Tut header #include "lltut.h" @@ -107,16 +108,25 @@ bool LLKDUMemIn::get(int, kdu_line_buf&, int) { return false; } // Stub Kakadu Library calls kdu_tile_comp kdu_tile::access_component(int ) { kdu_tile_comp a; return a; } +kdu_block_encoder::kdu_block_encoder() { } +kdu_block_decoder::kdu_block_decoder() { } +void kdu_block::set_max_passes(int , bool ) { } +void kdu_block::set_max_bytes(int , bool ) { } +void kdu_block::set_max_samples(int ) { } void kdu_tile::close(kdu_thread_env* ) { } int kdu_tile::get_num_components() { return 0; } bool kdu_tile::get_ycc() { return false; } void kdu_tile::set_components_of_interest(int , const int* ) { } +int kdu_tile::get_tnum() { return 0; } kdu_resolution kdu_tile_comp::access_resolution() { kdu_resolution a; return a; } +kdu_resolution kdu_tile_comp::access_resolution(int ) { kdu_resolution a; return a; } int kdu_tile_comp::get_bit_depth(bool ) { return 8; } bool kdu_tile_comp::get_reversible() { return false; } +int kdu_tile_comp::get_num_resolutions() { return 1; } kdu_subband kdu_resolution::access_subband(int ) { kdu_subband a; return a; } void kdu_resolution::get_dims(kdu_dims& ) { } int kdu_resolution::which() { return 0; } +int kdu_resolution::get_valid_band_indices(int &) { return 1; } kdu_decoder::kdu_decoder(kdu_subband , kdu_sample_allocator*, bool , float, int, kdu_thread_env*, kdu_thread_queue*) { } kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, bool, float, kdu_thread_env*, kdu_thread_queue*) { } kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) { } @@ -124,6 +134,7 @@ kdu_params::~kdu_params() { } void kdu_params::set(const char* , int , int , bool ) { } void kdu_params::set(const char* , int , int , int ) { } void kdu_params::finalize_all(bool ) { } +void kdu_params::finalize_all(int, bool ) { } void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool) { } bool kdu_params::parse_string(const char*) { return false; } bool kdu_params::get(const char*, int, int, bool&, bool, bool, bool) { return false; } @@ -148,9 +159,18 @@ void kdu_codestream::get_subsampling(int , kdu_coords&, bool ) { } void kdu_codestream::flush(kdu_long *, int , kdu_uint16 *, bool, bool, double, kdu_thread_env*) { } void kdu_codestream::set_resilient(bool ) { } int kdu_codestream::get_num_components(bool ) { return 0; } +kdu_long kdu_codestream::get_total_bytes(bool ) { return 0; } +kdu_long kdu_codestream::get_compressed_data_memory(bool ) {return 0; } +void kdu_codestream::share_buffering(kdu_codestream ) { } +int kdu_codestream::get_num_tparts() { return 0; } +int kdu_codestream::trans_out(kdu_long, kdu_long*, int, bool, kdu_thread_env* ) { return 0; } +bool kdu_codestream::ready_for_flush(kdu_thread_env*) { return false; } siz_params* kdu_codestream::access_siz() { return NULL; } kdu_tile kdu_codestream::open_tile(kdu_coords , kdu_thread_env* ) { kdu_tile a; return a; } kdu_codestream_comment kdu_codestream::add_comment() { kdu_codestream_comment a; return a; } +void kdu_subband::close_block(kdu_block*, kdu_thread_env*) { } +void kdu_subband::get_valid_blocks(kdu_dims &indices) { } +kdu_block* kdu_subband::open_block(kdu_coords, int*, kdu_thread_env*) { return NULL; } bool kdu_codestream_comment::put_text(const char*) { return false; } void kdu_customize_warnings(kdu_message*) { } void kdu_customize_errors(kdu_message*) { } |