Newer
Older
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
1005
1006
1007
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
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 & ((-1)<<8))
{
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;
if (val & ((-1)<<8))
{
Merov Linden
committed
val = (val < 0 ? 0 : 255);
Merov Linden
committed
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
}
*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 & ((-1)<<8))
{
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;
if (val & ((-1)<<8))
{
Merov Linden
committed
val = (val < 0 ? 0 : 256 - (1<<upshift));
Merov Linden
committed
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
}
*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 & ((-1)<<8))
{
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;
if (val & ((-1)<<8))
{
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)
{
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
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
{
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);
if (res.which() == 0) // No DWT levels used
{
mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
}
else
{
mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
}
}
mAllocator.finalize(); // 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
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
{
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--)
{
Merov Linden
committed
for (c = 0; c < mNumComponents; c++)
Merov Linden
committed
{
mEngines[c].pull(mLines[c],true);
}
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;
}
}
}
return TRUE;
}
// kdc_flow_control
kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream codestream)
{
Merov Linden
committed
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
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;
}
}