diff options
-rw-r--r-- | indra/llimage/llimage.h | 2 | ||||
-rw-r--r-- | indra/llkdu/llimagej2ckdu.cpp | 112 |
2 files changed, 58 insertions, 56 deletions
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index b757547ab8..18f8ae2fbb 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -48,6 +48,8 @@ const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_S const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec +const S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (after header). Must be > to FIRST_PACKET_SIZE!! +const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit) const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2 const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048 diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 4468b8563b..78c9be7bfd 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -599,12 +599,6 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co comment.put_text(comment_text); } - // Set codestream options - int num_layer_specs = 0; - - kdu_long layer_bytes[64]; - U32 max_bytes = 0; - if (num_components >= 3) { // Note that we always use YCC and not YUV @@ -612,67 +606,70 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co set_default_colour_weights(codestream.access_siz()); } + // Set codestream options + int num_layer_specs = 0; + kdu_long layer_bytes[MAX_NB_LAYERS]; + U32 max_bytes = (U32)(base.getWidth() * base.getHeight() * base.getComponents()); + + // Rate is the argument passed into the LLImageJ2C which + // specifies the target compression rate. The default is 8:1. + // *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures. + if (base.mRate != 0.f) + { + max_bytes = (U32)((F32)(max_bytes) * base.mRate); + } + else + { + max_bytes = (U32)((F32)(max_bytes) / 8.0f); + } + + // If the image is very small, code it in a lossless way. + // Note: it'll also have only 1 layer which is fine as there's no point reordering blocks in that case. + if (max_bytes < FIRST_PACKET_SIZE) + { + reversible = true; + } + + // This code is where we specify the target number of bytes for each quality layer. + // We're using a logarithmic spacing rule that fits with our way of fetching texture data. + // Note: For more info on this layers business, read kdu_codestream::flush() doc in kdu_compressed.h + U32 i = FIRST_PACKET_SIZE; + while ((i < max_bytes) && (num_layer_specs < (MAX_NB_LAYERS-1))) + { + if (i == FIRST_PACKET_SIZE * 4) + { + // That really just means that the first layer is FIRST_PACKET_SIZE and the second is MIN_LAYER_SIZE + i = MIN_LAYER_SIZE; + } + layer_bytes[num_layer_specs] = i; + num_layer_specs++; + i *= 4; + } + if (reversible) { codestream.access_siz()->parse_string("Creversible=yes"); - // *TODO: we should use yuv in reversible mode and one level since those images are small. + // *TODO: we should use yuv in reversible mode and one res level since those images are small. // Don't turn this on now though as both create problems on decoding for the moment //codestream.access_siz()->parse_string("Clevels=1"); //codestream.access_siz()->parse_string("Cycc=no"); - // If we're doing reversible (i.e. lossless compression), assumes we're not using quality layers. - // *TODO: this is incorrect and unecessary. Try using the regular layer setting. - codestream.access_siz()->parse_string("Clayers=1"); - num_layer_specs = 1; - layer_bytes[0] = 0; + // In the reversible case, set the last entry of that table to 0 so that all generated bits will + // indeed be output by the time the last quality layer is encountered. + layer_bytes[num_layer_specs] = 0; } else { - // Rate is the argument passed into the LLImageJ2C which - // specifies the target compression rate. The default is 8:1. - // Possibly if max_bytes < 500, we should just use the default setting? - // *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures. - if (base.mRate != 0.f) - { - max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents()); - } - else - { - max_bytes = (U32)(base.getWidth()*base.getHeight()*base.getComponents()*0.125); - } - - const U32 min_bytes = FIRST_PACKET_SIZE; - if (max_bytes > min_bytes) - { - U32 i; - // This code is where we specify the target number of bytes for - // each layer. Not sure if we should do this for small images - // or not. The goal is to have this roughly align with - // different quality levels that we decode at. - for (i = min_bytes; i < max_bytes; i*=4) - { - if (i == min_bytes * 4) - { - i = 2000; - } - layer_bytes[num_layer_specs] = i; - num_layer_specs++; - } - layer_bytes[num_layer_specs] = max_bytes; - num_layer_specs++; - - std::string layer_string = llformat("Clayers=%d",num_layer_specs); - codestream.access_siz()->parse_string(layer_string.c_str()); - } - else - { - layer_bytes[0] = min_bytes; - num_layer_specs = 1; - std::string layer_string = llformat("Clayers=%d",num_layer_specs); - codestream.access_siz()->parse_string(layer_string.c_str()); - } + // Truncate the last quality layer if necessary so to fit the set compression ratio + layer_bytes[num_layer_specs] = max_bytes; } + num_layer_specs++; + + std::string layer_string = llformat("Clayers=%d",num_layer_specs); + codestream.access_siz()->parse_string(layer_string.c_str()); // Set up data ordering, markers, etc... if precincts or blocks specified + // Note: This code is *not* used in the encoding made by the viewer. It is currently used only + // by llimage_libtest to create various j2c and test alternative compression schemes. if ((mBlocksSize != -1) || (mPrecinctsSize != -1)) { if (mPrecinctsSize != -1) @@ -692,16 +689,19 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co std::string Parts_string = llformat("ORGtparts=R"); codestream.access_siz()->parse_string(Parts_string.c_str()); } + + // Set the number of wavelets subresolutions (aka levels) if (mLevels != 0) { std::string levels_string = llformat("Clevels=%d",mLevels); codestream.access_siz()->parse_string(levels_string.c_str()); } + // Complete the encode settings codestream.access_siz()->finalize_all(); codestream.change_appearance(transpose,vflip,hflip); - // Now we are ready for sample data processing. + // Now we are ready for sample data processing kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream); bool done = false; while (!done) |