271 lines
6.9 KiB
C++
271 lines
6.9 KiB
C++
/**
|
|
* @file llblockdecoder.cpp
|
|
* @brief Image block decompression
|
|
*
|
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "llblockdecoder.h"
|
|
|
|
// KDU core header files
|
|
#include "kdu_elementary.h"
|
|
#include "kdu_messaging.h"
|
|
#include "kdu_params.h"
|
|
#include "kdu_compressed.h"
|
|
#include "kdu_sample_processing.h"
|
|
|
|
#include "llkdumem.h"
|
|
|
|
#include "llblockdata.h"
|
|
#include "llerror.h"
|
|
|
|
|
|
BOOL LLBlockDecoder::decodeU32(LLBlockDataU32 &block_data, U8 *source_data, const U32 source_size) const
|
|
{
|
|
U32 width, height;
|
|
|
|
llassert(source_data);
|
|
|
|
LLKDUMemSource source(source_data, source_size);
|
|
|
|
source.reset();
|
|
|
|
kdu_codestream codestream;
|
|
|
|
codestream.create(&source);
|
|
codestream.set_fast();
|
|
|
|
kdu_dims dims;
|
|
codestream.get_dims(0,dims);
|
|
llassert(codestream.get_num_components() == 1);
|
|
|
|
width = dims.size.x;
|
|
height = dims.size.y;
|
|
|
|
// Assumes U32 data.
|
|
U8 *output = block_data.getData();
|
|
|
|
kdu_dims tile_indices;
|
|
codestream.get_valid_tiles(tile_indices);
|
|
|
|
kdu_coords tpos;
|
|
tpos.x = 0;
|
|
tpos.y = 0;
|
|
|
|
// Now we are ready to walk through the tiles processing them one-by-one.
|
|
while (tpos.y < tile_indices.size.y)
|
|
{
|
|
while (tpos.x < tile_indices.size.x)
|
|
{
|
|
kdu_tile tile = codestream.open_tile(tpos+tile_indices.pos);
|
|
|
|
kdu_resolution res = tile.access_component(0).access_resolution();
|
|
kdu_dims tile_dims;
|
|
res.get_dims(tile_dims);
|
|
kdu_coords offset = tile_dims.pos - dims.pos;
|
|
int row_gap = block_data.getRowStride(); // inter-row separation
|
|
kdu_byte *buf = output + offset.y*row_gap + offset.x*4;
|
|
|
|
kdu_tile_comp tile_comp = tile.access_component(0);
|
|
bool reversible = tile_comp.get_reversible();
|
|
U32 precision = tile_comp.get_bit_depth();
|
|
U32 precision_scale = 1 << precision;
|
|
llassert(precision >= 8); // Else would have used 16 bit representation
|
|
|
|
kdu_resolution comp_res = tile_comp.access_resolution(); // Get top resolution
|
|
kdu_dims comp_dims;
|
|
comp_res.get_dims(comp_dims);
|
|
|
|
bool use_shorts = (tile_comp.get_bit_depth(true) <= 16);
|
|
|
|
kdu_line_buf line;
|
|
kdu_sample_allocator allocator;
|
|
kdu_pull_ifc engine;
|
|
|
|
line.pre_create(&allocator, comp_dims.size.x, reversible, use_shorts);
|
|
if (res.which() == 0) // No DWT levels used
|
|
{
|
|
engine = kdu_decoder(res.access_subband(LL_BAND), &allocator, use_shorts);
|
|
}
|
|
else
|
|
{
|
|
engine = kdu_synthesis(res, &allocator, use_shorts);
|
|
}
|
|
allocator.finalize(); // Actually creates buffering resources
|
|
|
|
line.create(); // Grabs resources from the allocator.
|
|
|
|
// Do the actual processing
|
|
while (tile_dims.size.y--)
|
|
{
|
|
engine.pull(line, true);
|
|
int width = line.get_width();
|
|
|
|
llassert(line.get_buf32());
|
|
llassert(!line.is_absolute());
|
|
// Decompressed samples have a 32-bit representation (integer or float)
|
|
kdu_sample32 *sp = line.get_buf32();
|
|
// Transferring normalized floating point data.
|
|
U32 *dest_u32 = (U32 *)buf;
|
|
for (; width > 0; width--, sp++, dest_u32++)
|
|
{
|
|
if (sp->fval < -0.5f)
|
|
{
|
|
*dest_u32 = 0;
|
|
}
|
|
else
|
|
{
|
|
*dest_u32 = (U32)((sp->fval + 0.5f)*precision_scale);
|
|
}
|
|
}
|
|
buf += row_gap;
|
|
}
|
|
engine.destroy();
|
|
tile.close();
|
|
tpos.x++;
|
|
}
|
|
tpos.y++;
|
|
tpos.x = 0;
|
|
}
|
|
codestream.destroy();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLBlockDecoder::decodeF32(LLBlockDataF32 &block_data, U8 *source_data, const U32 source_size, const F32 min, const F32 max) const
|
|
{
|
|
U32 width, height;
|
|
F32 range, range_inv, float_offset;
|
|
bool use_shorts = false;
|
|
|
|
range = max - min;
|
|
range_inv = 1.f / range;
|
|
float_offset = 0.5f*(max + min);
|
|
|
|
llassert(source_data);
|
|
|
|
LLKDUMemSource source(source_data, source_size);
|
|
|
|
source.reset();
|
|
|
|
kdu_codestream codestream;
|
|
|
|
codestream.create(&source);
|
|
codestream.set_fast();
|
|
|
|
kdu_dims dims;
|
|
codestream.get_dims(0,dims);
|
|
llassert(codestream.get_num_components() == 1);
|
|
|
|
width = dims.size.x;
|
|
height = dims.size.y;
|
|
|
|
// Assumes F32 data.
|
|
U8 *output = block_data.getData();
|
|
|
|
kdu_dims tile_indices;
|
|
codestream.get_valid_tiles(tile_indices);
|
|
|
|
kdu_coords tpos;
|
|
tpos.x = 0;
|
|
tpos.y = 0;
|
|
|
|
// Now we are ready to walk through the tiles processing them one-by-one.
|
|
while (tpos.y < tile_indices.size.y)
|
|
{
|
|
while (tpos.x < tile_indices.size.x)
|
|
{
|
|
kdu_tile tile = codestream.open_tile(tpos+tile_indices.pos);
|
|
|
|
kdu_resolution res = tile.access_component(0).access_resolution();
|
|
kdu_dims tile_dims;
|
|
res.get_dims(tile_dims);
|
|
kdu_coords offset = tile_dims.pos - dims.pos;
|
|
int row_gap = block_data.getRowStride(); // inter-row separation
|
|
kdu_byte *buf = output + offset.y*row_gap + offset.x*4;
|
|
|
|
kdu_tile_comp tile_comp = tile.access_component(0);
|
|
bool reversible = tile_comp.get_reversible();
|
|
|
|
kdu_resolution comp_res = tile_comp.access_resolution(); // Get top resolution
|
|
kdu_dims comp_dims;
|
|
comp_res.get_dims(comp_dims);
|
|
|
|
kdu_line_buf line;
|
|
kdu_sample_allocator allocator;
|
|
kdu_pull_ifc engine;
|
|
|
|
line.pre_create(&allocator, comp_dims.size.x, reversible, use_shorts);
|
|
if (res.which() == 0) // No DWT levels used
|
|
{
|
|
engine = kdu_decoder(res.access_subband(LL_BAND), &allocator, use_shorts);
|
|
}
|
|
else
|
|
{
|
|
engine = kdu_synthesis(res, &allocator, use_shorts);
|
|
}
|
|
allocator.finalize(); // Actually creates buffering resources
|
|
|
|
line.create(); // Grabs resources from the allocator.
|
|
|
|
// Do the actual processing
|
|
while (tile_dims.size.y--)
|
|
{
|
|
engine.pull(line, true);
|
|
int width = line.get_width();
|
|
|
|
llassert(line.get_buf32());
|
|
llassert(!line.is_absolute());
|
|
// Decompressed samples have a 32-bit representation (integer or float)
|
|
kdu_sample32 *sp = line.get_buf32();
|
|
// Transferring normalized floating point data.
|
|
F32 *dest_f32 = (F32 *)buf;
|
|
for (; width > 0; width--, sp++, dest_f32++)
|
|
{
|
|
if (sp->fval < -0.5f)
|
|
{
|
|
*dest_f32 = min;
|
|
}
|
|
else if (sp->fval > 0.5f)
|
|
{
|
|
*dest_f32 = max;
|
|
}
|
|
else
|
|
{
|
|
*dest_f32 = (sp->fval) * range + float_offset;
|
|
}
|
|
}
|
|
buf += row_gap;
|
|
}
|
|
engine.destroy();
|
|
tile.close();
|
|
tpos.x++;
|
|
}
|
|
tpos.y++;
|
|
tpos.x = 0;
|
|
}
|
|
codestream.destroy();
|
|
return TRUE;
|
|
}
|