diff options
| author | Merov Linden <merov@lindenlab.com> | 2012-04-04 15:59:52 -0700 | 
|---|---|---|
| committer | Merov Linden <merov@lindenlab.com> | 2012-04-04 15:59:52 -0700 | 
| commit | c6511d9c857c079e0360f88c05328feb70a8bc0d (patch) | |
| tree | 7197cd2a1261e2f02865b11b68490fb4ca4e2a23 /indra | |
| parent | df09fd8e8b5b73330e4942c2cb218a216d7aca99 (diff) | |
SH-3075 : Fix encoding for reversible images and small textures
Diffstat (limited to 'indra')
| -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) | 
