Newer
Older
Merov Linden
committed
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;
Merov Linden
committed
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
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;
}
|*==========================================================================*/
Merov Linden
committed
Merov Linden
committed
void set_default_colour_weights(kdu_params *siz)
{
kdu_params *cod = siz->access_cluster(COD_params);
assert(cod != NULL);
bool can_use_ycc = true;
Merov Linden
committed
bool rev0 = false;
int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
for (int c = 0; c < 3; c++)
Merov Linden
committed
{
Merov Linden
committed
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);
Merov Linden
committed
kdu_params *coc = cod->access_relation(-1,c);
Merov Linden
committed
bool rev = false; coc->get(Creversible,0,0,rev);
Merov Linden
committed
if (c == 0)
Merov Linden
committed
{
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))
{
Merov Linden
committed
can_use_ycc = false;
Merov Linden
committed
}
Merov Linden
committed
}
if (!can_use_ycc)
Merov Linden
committed
{
Merov Linden
committed
return;
Merov Linden
committed
}
Merov Linden
committed
bool use_ycc;
if (!cod->get(Cycc,0,0,use_ycc))
Merov Linden
committed
{
Merov Linden
committed
cod->set(Cycc,0,0,use_ycc=true);
Merov Linden
committed
}
Merov Linden
committed
if (!use_ycc)
Merov Linden
committed
{
Merov Linden
committed
return;
Merov Linden
committed
}
cod = siz->access_cluster(ENC_params);
assert(cod != NULL);
Merov Linden
committed
float weight;
Merov Linden
committed
if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
{
// Weights already specified explicitly -> nothing to do
return;
}
Merov Linden
committed
Merov Linden
committed
// 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.
Merov Linden
committed
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
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;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 255);
Merov Linden
committed
}
*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;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 255);
Merov Linden
committed
}
*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;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 255);
Merov Linden
committed
}
*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;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 256 - (1<<upshift));
Merov Linden
committed
}
*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;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 255);
Merov Linden
committed
}
*dest = (kdu_byte) val;
}
}
else
{
kdu_int16 upshift = 8-precision;
for (; width > 0; width--, sp++, dest+=gap)
{
val = sp->ival;
val <<= upshift;
val += 128;
Merov Linden
committed
{
Merov Linden
committed
val = (val < 0 ? 0 : 256 - (1<<upshift));
Merov Linden
committed
}
*dest = (kdu_byte) val;
}
}
}
}
}
LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
kdu_codestream* codestreamp)
Merov Linden
committed
{
S32 c;
mTile = tile;
mBuf = buf;
mRowGap = row_gap;
mNumComponents = tile.get_num_components();
Merov Linden
committed
llassert(mNumComponents <= 4);
Merov Linden
committed
mUseYCC = tile.get_ycc();
Merov Linden
committed
for (c = 0; c < 4; ++c)
Merov Linden
committed
{
mReversible[c] = false;
mBitDepths[c] = 0;
}
// Open tile-components and create processing engines and resources
Merov Linden
committed
for (c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
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);
Merov Linden
committed
if (res.which() == 0) // No DWT levels used
{
mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,mPushPullParams,use_shorts);
Merov Linden
committed
}
else
{
mEngines[c] = kdu_synthesis(res,&mAllocator,mPushPullParams,use_shorts);
Merov Linden
committed
}
}
mAllocator.finalize(*codestreamp); // Actually creates buffering resources
Merov Linden
committed
for (c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
mLines[c].create(); // Grabs resources from the allocator.
}
}
LLKDUDecodeState::~LLKDUDecodeState()
{
// Cleanup
Merov Linden
committed
for (S32 c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
mEngines[c].destroy(); // engines are interfaces; no default destructors
}
mTile.close();
}
bool LLKDUDecodeState::processTileDecode(F32 decode_time, bool limit_time)
Merov Linden
committed
/* 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--)
{
Merov Linden
committed
for (c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
mEngines[c].pull(mLines[c]);
Merov Linden
committed
}
if ((mNumComponents >= 3) && mUseYCC)
{
kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
}
Merov Linden
committed
for (c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
}
mBuf += mRowGap;
if (mDims.size.y % 10)
{
if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
{
return false;
Merov Linden
committed
}
}
}
return true;
Merov Linden
committed
}
// kdc_flow_control
kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_codestream codestream)
Merov Linden
committed
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
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()
{
Merov Linden
committed
if (components != NULL)
{
delete[] components;
}
if (engine.exists())
{
engine.destroy();
}
}
bool kdc_flow_control::advance_components()
{
Merov Linden
committed
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);
}
Merov Linden
committed
}
}
}
if (all_done)
{
return false;
}
}
return true;
}
void kdc_flow_control::process_components()
{
Merov Linden
committed
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;
}
}