Skip to content
Snippets Groups Projects
llimagej2ckdu.cpp 45.7 KiB
Newer Older
		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;
		//std::cout << "Parsing tiles : x = " << tile_indices_out.size.x << " to y = " << tile_indices_out.size.y << std::endl;
		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);
	assert(cod != NULL);

	bool can_use_ycc = true;
	bool rev0 = false;
	int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
	for (int c = 0; c < 3; c++)
		int depth = 0; siz->get(Sprecision,c,0,depth);
		int sub_y = 1; siz->get(Ssampling,c,0,sub_y);
		int sub_x = 1; siz->get(Ssampling,c,1,sub_x);
		kdu_params *coc = cod->access_relation(-1,c);
		bool rev = false; coc->get(Creversible,0,0,rev);
		{
			rev0 = rev; depth0 = depth; sub_x0 = sub_x; sub_y0 = sub_y;
		}
		else if ((rev != rev0) || (depth != depth0) || 
				 (sub_x != sub_x0) || (sub_y != sub_y0))
		{
Rye Mutt's avatar
Rye Mutt committed

	cod = siz->access_cluster(ENC_params);
	assert(cod != NULL);

	if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
	{
		// Weights already specified explicitly -> nothing to do
		return; 
	}
	// These example weights are adapted from numbers generated by Marcus Nadenau
	// at EPFL, for a viewing distance of 15 cm and a display resolution of
	// 300 DPI.

	cod->parse_string("Cband_weights:C0="
		"{0.0901},{0.2758},{0.2758},"
		"{0.7018},{0.8378},{0.8378},{1}");
	cod->parse_string("Cband_weights:C1="
		"{0.0263},{0.0863},{0.0863},"
		"{0.1362},{0.2564},{0.2564},"
		"{0.3346},{0.4691},{0.4691},"
		"{0.5444},{0.6523},{0.6523},"
		"{0.7078},{0.7797},{0.7797},{1}");
	cod->parse_string("Cband_weights:C2="
		"{0.0773},{0.1835},{0.1835},"
		"{0.2598},{0.4130},{0.4130},"
		"{0.5040},{0.6464},{0.6464},"
		"{0.7220},{0.8254},{0.8254},"
		"{0.8769},{0.9424},{0.9424},{1}");
}

/******************************************************************************/
/*                              transfer_bytes                                */
/******************************************************************************/

void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision)
/* Transfers source samples from the supplied line buffer into the output
byte buffer, spacing successive output samples apart by `gap' bytes
(to allow for interleaving of colour components).  The function performs
all necessary level shifting, type conversion, rounding and truncation. */
{
	int width = src.get_width();
	if (src.get_buf32() != NULL)
	{ // Decompressed samples have a 32-bit representation (integer or float)
		assert(precision >= 8); // Else would have used 16 bit representation
		kdu_sample32 *sp = src.get_buf32();
		if (!src.is_absolute())
		{ // Transferring normalized floating point data.
			float scale16 = (float)(1<<16);
			kdu_int32 val;

			for (; width > 0; width--, sp++, dest+=gap)
			{
				val = (kdu_int32)(sp->fval*scale16);
				val = (val+128)>>8; // May be faster than true rounding
				val += 128;
				if (val & ((0xffffffffU)<<8))
				}
				*dest = (kdu_byte) val;
			}
		}
		else
		{ // Transferring 32-bit absolute integers.
			kdu_int32 val;
			kdu_int32 downshift = precision-8;
			kdu_int32 offset = (1<<downshift)>>1;

			for (; width > 0; width--, sp++, dest+=gap)
			{
				val = sp->ival;
				val = (val+offset)>>downshift;
				val += 128;
				if (val & ((0xffffffffU)<<8))
				}
				*dest = (kdu_byte) val;
			}
		}
	}
	else
	{ // Source data is 16 bits.
		kdu_sample16 *sp = src.get_buf16();
		if (!src.is_absolute())
		{ // Transferring 16-bit fixed point quantities
			kdu_int16 val;

			if (precision >= 8)
			{ // Can essentially ignore the bit-depth.
				for (; width > 0; width--, sp++, dest+=gap)
				{
					val = sp->ival;
					val += (1<<(KDU_FIX_POINT-8))>>1;
					val >>= (KDU_FIX_POINT-8);
					val += 128;
					if (val & ((0xffffffffU)<<8))
					}
					*dest = (kdu_byte) val;
				}
			}
			else
			{ // Need to force zeros into one or more least significant bits.
				kdu_int16 downshift = KDU_FIX_POINT-precision;
				kdu_int16 upshift = 8-precision;
				kdu_int16 offset = 1<<(downshift-1);

				for (; width > 0; width--, sp++, dest+=gap)
				{
					val = sp->ival;
					val = (val+offset)>>downshift;
					val <<= upshift;
					val += 128;
					if (val & ((0xffffffffU)<<8))
						val = (val < 0 ? 0 : 256 - (1<<upshift));
					}
					*dest = (kdu_byte) val;
				}
			}
		}
		else
		{ // Transferring 16-bit absolute integers.
			kdu_int16 val;

			if (precision >= 8)
			{
				kdu_int16 downshift = precision-8;
				kdu_int16 offset = (1<<downshift)>>1;

				for (; width > 0; width--, sp++, dest+=gap)
				{
					val = sp->ival;
					val = (val+offset)>>downshift;
					val += 128;
					if (val & ((0xffffffffU)<<8))
					}
					*dest = (kdu_byte) val;
				}
			}
			else
			{
				kdu_int16 upshift = 8-precision;

				for (; width > 0; width--, sp++, dest+=gap)
				{
					val = sp->ival;
					val <<= upshift;
					val += 128;
					if (val & ((0xffffffffU)<<8))
						val = (val < 0 ? 0 : 256 - (1<<upshift));
LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
								   kdu_codestream* codestreamp)
{
	S32 c;

	mTile = tile;
	mBuf = buf;
	mRowGap = row_gap;

	mNumComponents = tile.get_num_components();

	{
		mReversible[c] = false;
		mBitDepths[c] = 0;
	}

	// Open tile-components and create processing engines and resources
	{
		mComps[c] = mTile.access_component(c);
		mReversible[c] = mComps[c].get_reversible();
		mBitDepths[c] = mComps[c].get_bit_depth();
		kdu_resolution res = mComps[c].access_resolution(); // Get top resolution
		kdu_dims comp_dims; res.get_dims(comp_dims);
		if (c == 0)
		{
			mDims = comp_dims;
		}
		else
		{
			llassert(mDims == comp_dims); // Safety check; the caller has ensured this
		}
		bool use_shorts = (mComps[c].get_bit_depth(true) <= 16);
		mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts,0,0);
Rye Mutt's avatar
Rye Mutt committed
			mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,mPushPullParams,use_shorts);
Rye Mutt's avatar
Rye Mutt committed
			mEngines[c] = kdu_synthesis(res,&mAllocator,mPushPullParams,use_shorts);
	mAllocator.finalize(*codestreamp); // Actually creates buffering resources
	{
		mLines[c].create(); // Grabs resources from the allocator.
	}
}

LLKDUDecodeState::~LLKDUDecodeState()
{
	// Cleanup
	for (S32 c = 0; c < mNumComponents; c++)
	{
		mEngines[c].destroy(); // engines are interfaces; no default destructors
	}
	mTile.close();
}

bool LLKDUDecodeState::processTileDecode(F32 decode_time, bool limit_time)
/* Decompresses a tile, writing the data into the supplied byte buffer.
The buffer contains interleaved image components, if there are any.
Although you may think of the buffer as belonging entirely to this tile,
the `buf' pointer may actually point into a larger buffer representing
multiple tiles.  For this reason, `row_gap' is needed to identify the
separation between consecutive rows in the real buffer. */
{
	S32 c;
	// Now walk through the lines of the buffer, recovering them from the
	// relevant tile-component processing engines.

	LLTimer decode_timer;
	while (mDims.size.y--)
	{
			mEngines[c].pull(mLines[c]);
		}
		if ((mNumComponents >= 3) && mUseYCC)
		{
			kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
		}
		{
			transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
		}
		mBuf += mRowGap;
		if (mDims.size.y % 10)
		{
			if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
			{
kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_codestream codestream)
	int n;
	
	this->codestream = codestream;
	codestream.get_valid_tiles(valid_tile_indices);
	tile_idx = valid_tile_indices.pos;
	tile = codestream.open_tile(tile_idx,NULL);
	
	// Set up the individual components
	num_components = codestream.get_num_components(true);
	components = new kdc_component_flow_control[num_components];
	count_delta = 0;
	kdc_component_flow_control *comp = components;
	for (n = 0; n < num_components; n++, comp++)
	{
		comp->line = NULL;
		comp->reader = img_in;
		kdu_coords subsampling;  
		codestream.get_subsampling(n,subsampling,true);
		kdu_dims dims;  
		codestream.get_tile_dims(tile_idx,n,dims,true);
		comp->vert_subsampling = subsampling.y;
		if ((n == 0) || (comp->vert_subsampling < count_delta))
		{
			count_delta = comp->vert_subsampling;
		}
		comp->ratio_counter = 0;
		comp->remaining_lines = comp->initial_lines = dims.size.y;
	}
	assert(num_components >= 0);
	
	tile.set_components_of_interest(num_components);
	max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
}

kdc_flow_control::~kdc_flow_control()
{
	if (components != NULL)
	{
		delete[] components;
	}
	if (engine.exists())
	{
		engine.destroy();
	}
}

bool kdc_flow_control::advance_components()
{
	bool found_line = false;
	while (!found_line)
	{
		bool all_done = true;
		kdc_component_flow_control *comp = components;
		for (int n = 0; n < num_components; n++, comp++)
		{
			assert(comp->ratio_counter >= 0);
			if (comp->remaining_lines > 0)
			{
				all_done = false;
				comp->ratio_counter -= count_delta;
				if (comp->ratio_counter < 0)
				{
					found_line = true;
					comp->line = engine.exchange_line(n,NULL,NULL);
					assert(comp->line != NULL);
					if (comp->line->get_width())
					{
						comp->reader->get(n,*(comp->line),0);
					}
}

void kdc_flow_control::process_components()
{
	kdc_component_flow_control *comp = components;
	for (int n = 0; n < num_components; n++, comp++)
	{
		if (comp->ratio_counter < 0)
		{
			comp->ratio_counter += comp->vert_subsampling;
			assert(comp->ratio_counter >= 0);
			assert(comp->remaining_lines > 0);
			comp->remaining_lines--;
			assert(comp->line != NULL);
			engine.exchange_line(n,comp->line,NULL);
			comp->line = NULL;
		}
	}