📄 wavelet.c
字号:
for (i = 0; i <= bl->max_quant; i++)
{
t_wv_quantised_block* ebl = &bl->quant[i];
if (bits_left - ebl->compressed_size >= need_left)
{ // fit
float lmse;
unsigned char wd;
if (went_down)
*went_down = 1;
lmse = recursive_selector_bits(cc, block_idx + 1, bits_left - ebl->compressed_size, mse + ebl->mse, &wd);
if (lmse < bl->best_mse)
{
if (!wd)
{ // we didn't fit another block, so set their quant to max
int j;
for (j = block_idx + 1; j < cc->num_blocks; j++)
cc->blocks[j].best_quant = cc->blocks[j].max_quant;
}
bl->best_quant = i;
bl->best_mse = best_lmse = lmse;
}
}
}
return best_lmse;
}
static int recursive_selector_mse(t_wv_cchannel* cc, const int block_idx, const int total_bits, const float mse, unsigned char *went_down)
{
int i;
t_wv_cblock* bl;
int best_bits;
float min_mse, max_mse;
if (went_down)
*went_down = 0;
min_mse = max_mse = mse;
for (i = block_idx; i < cc->num_blocks; i++)
{
min_mse += cc->blocks[i].quant[0].mse;
max_mse += cc->blocks[i].quant[cc->blocks[i].max_quant].mse;
}
if (max_mse <= cc->max_mse)
{
cc->final_mse = max_mse;
return total_bits;
}
if ((total_bits != 0 && cc->max_bits - total_bits < RICE_MIN_SPACE) || block_idx >= cc->num_blocks)
return cc->max_bits + 1; // didn't meet the requirements
if (min_mse > cc->max_mse)
return cc->max_bits + 1; // only try this if it can possibly be better (with infite bits)
best_bits = cc->max_bits + 1;
bl = &cc->blocks[block_idx];
for (i = 0; i <= bl->max_quant; i++)
{
t_wv_quantised_block* ebl = &bl->quant[i];
if (total_bits + ebl->compressed_size <= cc->max_bits)
{ // fit
int lbits;
unsigned char wd;
if (went_down)
*went_down = 1;
lbits = recursive_selector_mse(cc, block_idx + 1, total_bits + ebl->compressed_size, mse + ebl->mse, &wd);
if (lbits <= cc->max_bits && lbits < bl->best_bits)
{
if (!wd)
{ // we didn't fit another block, so set their quant to max
int j;
for (j = block_idx + 1; j < cc->num_blocks; j++)
{
cc->blocks[j].best_quant = cc->blocks[j].max_quant;
cc->blocks[j].best_bits = lbits;
}
}
bl->best_quant = i;
bl->best_bits = best_bits = lbits;
}
}
}
return best_bits;
}
//----------------------------------------------------------------------------
// wv_init_channel_settings initialises compression settings for a single
// channel, stores it to the userdefined pointer and
// returns the number of bits used (0 on failure)
// CC handle to the channel (gotten from wv_init_channel)
// MaxBits (maximum) bits to be used for the channel (0 ^= quality-based)
// MaxMSE maximum mean square error to be incurred by the compression
// 0.0f => lossless, 65536.0f => don't care
// Settings pointer where the channel-setting handle is stored on success
//----------------------------------------------------------------------------
WAVELET_DLL_API int WAVELET_DLL_CC wv_init_channel_settings(t_wv_cchannel* CC, const int MaxBits, const float MaxMSE, t_wv_csettings** Settings)
{
int bits = 0;
if (CC && Settings)
{
int i, size;
for (i = 0; i < CC->num_blocks; i++)
{
CC->blocks[i].best_bits = 1 << 30;
CC->blocks[i].best_mse = 65536.0f;
CC->blocks[i].best_quant = CC->blocks[i].max_quant;
}
CC->max_bits = size = max(0, MaxBits);
CC->max_mse = min(65536.0f, max(0.0f, MaxMSE));
if (CC->max_mse < 65536.0f)
{
if (CC->max_bits == 0)
CC->max_bits = 1 << 30;
size = recursive_selector_mse(CC, 0, 0, 0.0f, NULL);
}
else
{
CC->final_mse = recursive_selector_bits(CC, 0, CC->max_bits, 0.0f, NULL); // only bit-constraint
size = 0;
for (i = 0; i < CC->num_blocks; i++)
size += CC->blocks[i].quant[CC->blocks[i].best_quant].compressed_size;
}
if (CC->max_bits == 0 || size <= CC->max_bits)
{
t_wv_csettings* set = malloc(sizeof *set);
set->cchannel = CC;
set->size_min_block = CC->size_min_block;
set->emse = 0.0f;
set->num_bits = 0;
set->num_blocks = CC->num_blocks;
set->blocks = malloc(CC->num_blocks * sizeof *set);
for (i = 0; i < CC->num_blocks; i++)
{
set->blocks[i].max_bpp = CC->blocks[i].max_bpp;
set->blocks[i].quant = CC->blocks[i].best_quant;
set->blocks[i].num_bits = CC->blocks[i].quant[CC->blocks[i].best_quant].compressed_size;
set->num_bits += set->blocks[i].num_bits;
set->emse += CC->blocks[i].quant[CC->blocks[i].best_quant].mse;
// printf("%i ", set->blocks[i].num_bits);
}
// printf("\n");
bits = set->num_bits;
*Settings = set;
}
else
*Settings = NULL;
}
return bits;
}
//----------------------------------------------------------------------------
// wv_done_channel_settings frees the channels settings
// Settings channel-settings handle to be freed
//----------------------------------------------------------------------------
WAVELET_DLL_API void WAVELET_DLL_CC wv_done_channel_settings(t_wv_csettings* Settings)
{
if (Settings)
{
free(Settings->blocks);
free(Settings);
}
}
//----------------------------------------------------------------------------
// wv_encode_channels encodes a number of channels progressively
// interleaved into a given bit_file. it includes a small header
// containing # channels, power of 2 width & height
// returns the number of bits written
// NumChannels # of channels to be encoded
// ChannelSettings array of channel-settings handles to be used for encoding.
// all channels / settings need to have the same width, height
// and number of blocks to be encoded into the same file
// BF bit-file handle to be written to (opened in WRITE-mode)
//----------------------------------------------------------------------------
WAVELET_DLL_API int WAVELET_DLL_CC wv_encode_channels(const int NumChannels, t_wv_csettings** ChannelSettings, t_bit_file* BF)
{
int bits = 0;
if (NumChannels > 0 && NumChannels <= wv_MAX_CHANNELS && ChannelSettings && BF)
{
int i;
// check that the channels are the same size & # of blocks
for (i = 1; i < NumChannels; i++)
{
if (ChannelSettings[0]->num_blocks != ChannelSettings[i]->num_blocks)
break;
if (ChannelSettings[0]->cchannel->width != ChannelSettings[i]->cchannel->width)
break;
if (ChannelSettings[0]->cchannel->height != ChannelSettings[i]->cchannel->height)
break;
if (ChannelSettings[0]->cchannel->size_min_block != ChannelSettings[i]->cchannel->size_min_block)
break;
}
if (i == NumChannels)
{ // they all match
static const unsigned int magic = 0x5b765d;
int j;
bits += bit_write(magic, 24, BF);
bits += bit_write(wv_CUR_HEADER_VERSION, 4, BF);
bits += bit_write(wv_CUR_BITSTREAM_VERSION, 4, BF);
bits += bit_write(ChannelSettings[0]->cchannel->width != ChannelSettings[0]->cchannel->owidth ||
ChannelSettings[0]->cchannel->height != ChannelSettings[0]->cchannel->oheight, 1, BF); // write dimension flag
if (ChannelSettings[0]->cchannel->width != ChannelSettings[0]->cchannel->owidth ||
ChannelSettings[0]->cchannel->height != ChannelSettings[0]->cchannel->oheight)
{
bits += bit_write(ChannelSettings[0]->cchannel->owidth - 1, 16, BF);
bits += bit_write(ChannelSettings[0]->cchannel->oheight - 1, 16, BF);
}
bits += bit_write(NumChannels - 1, 4, BF);
bits += bit_write(wv_log2i(ChannelSettings[0]->cchannel->width) - 1, 4, BF);
bits += bit_write(wv_log2i(ChannelSettings[0]->cchannel->height) - 1, 4, BF);
bits += bit_write(ChannelSettings[0]->num_blocks - 1, 4, BF);
bits += bit_write(wv_log2i(ChannelSettings[0]->size_min_block), 5, BF);
for (i = 0; i < ChannelSettings[0]->num_blocks; i++)
for (j = 0; j < NumChannels; j++)
bits += rice_encode_block(ChannelSettings[j]->cchannel->reordered_channel + ChannelSettings[j]->cchannel->blocks[i].offset, ChannelSettings[j]->cchannel->blocks[i].size, ChannelSettings[j]->blocks[i].quant, 0, ChannelSettings[j]->cchannel->blocks[i].max_value, BF); // write channel-blocks interleaved
}
}
return bits;
}
//----------------------------------------------------------------------------
// wv_init_decode_channels decodes a number of channels from a bit-file
// written to by wv_encode_channels.
// returns Header if header read successfully, NULL otherwise
// Header Place to store the information (only valid if != NULL was returned)
// BF bit-file handle to be read from (opened in READ-mode)
//----------------------------------------------------------------------------
WAVELET_DLL_API t_wv_header* WAVELET_DLL_CC wv_read_header(t_wv_header* Header, t_bit_file* BF)
{
static const unsigned int magic = 0x5b765d;
int header_version, bitstream_version;
if (!Header)
return NULL;
Header->num_channels = 0;
Header->width = Header->height = 0;
Header->owidth = Header->oheight = 0;
Header->header_version = bitstream_version = 0;
if (!BF)
return NULL;
if (bit_read(24, BF) != magic)
return NULL;
header_version= bit_read(4, BF);
if (header_version < wv_MIN_HEADER_VERSION || header_version > wv_CUR_HEADER_VERSION)
return NULL;
bitstream_version = bit_read(4, BF);
if (bitstream_version < wv_MIN_BITSTREAM_VERSION || bitstream_version > wv_CUR_BITSTREAM_VERSION)
return NULL;
Header->header_version = header_version;
Header->bitstream_version = bitstream_version;
if (bit_read_single(BF))
{ // read original dimensions
Header->owidth = bit_read(16, BF) + 1;
Header->oheight = bit_read(16, BF) + 1;
}
Header->num_channels = bit_read(4, BF) + 1;
Header->width = 1 << bit_read(4, BF);
Header->height = 1 << bit_read(4, BF);
if (Header->owidth == 0)
{ // they were equal
Header->owidth = Header->width;
Header->oheight = Header->height;
}
Header->num_blocks = bit_read(4, BF) + 1;
Header->size_min_block = bit_read(5, BF);
Header->size_min_block = Header->size_min_block ? (1 << (Header->size_min_block - 1)) : 0;
if (Header->width >= 1 && Header->height >= 1 && Header->size_min_block > 0)
return Header;
return NULL;
}
//----------------------------------------------------------------------------
// wv_init_decode_channels decodes a number of channels from a bit-file
// written to by wv_encode_channels.
// returns a structure containing all the channels (NULL on fail)
// BF has to be aligned to the header
// Reduction Indicates how often to halve the dimensions of the stored channels (minimum is 4x4)
// BF bit-file handle to be read from (opened in READ-mode)
//----------------------------------------------------------------------------
WAVELET_DLL_API t_wv_dchannels* WAVELET_DLL_CC wv_init_decode_channels(int Reduction, t_bit_file* BF)
{
t_wv_header hdr;
if (wv_read_header(&hdr, BF) != NULL)
{
t_wv_dchannels* dc = NULL;
int max_levels = max(0, wv_log2i(min(hdr.width, hdr.height)) - 2);
int** reorder_table;
wv_pel* tmp;
int i, j;
Reduction = max(0, min(Reduction, min(max_levels - 1, hdr.num_blocks - 1)));
reorder_table = init_reorder_tables(hdr.width, hdr.owidth, hdr.height, hdr.oheight, max_levels - Reduction, Reduction);
hdr.width >>= Reduction;
hdr.height >>= Reduction;
hdr.owidth >>= Reduction;
hdr.oheight >>= Reduction;
hdr.num_blocks -= Reduction;
max_levels -= Reduction;
dc = malloc(sizeof *dc);
dc->channels = malloc(hdr.num_channels * sizeof *dc->channels);
for (i = 0; i < hdr.num_channels; i++)
dc->channels[i] = malloc(hdr.width * hdr.height * sizeof *dc->channels[i]);
for (i = 0; i < hdr.num_blocks; i++)
{
int ofs = (i == 0) ? 0 : (hdr.size_min_block << (2 * (i - 1)));
// int size = (i == 0) ? size_min_block : ((size_min_block << (2 * i)) - ofs); // original
int size = (i == 0) ? hdr.size_min_block : 3 * reorder_table[i - 1][0]; // do not read zeroes
for (j = 0; j < hdr.num_channels; j++)
rice_decode_block(dc->channels[j] + ofs, size, 0, BF);
}
tmp = malloc(hdr.width * hdr.height * sizeof *tmp);
for (i = 0; i < hdr.num_channels; i++)
{
unreorder(tmp, dc->channels[i], reorder_table, hdr.width, hdr.height, max_levels);
inverse_wavelet_transform(tmp, hdr.width, hdr.height, max_levels);
memcpy(dc->channels[i], tmp, hdr.width * hdr.height * sizeof *dc->channels[i]);
}
free(tmp);
free_reorder_tables(reorder_table, max_levels);
dc->hdr = hdr;
return dc;
}
return NULL;
}
//----------------------------------------------------------------------------
// wv_done_decode_channels frees the structure allocated
// by wv_init_decode_channels.
// dc decompressed channel structure to be freed
//----------------------------------------------------------------------------
WAVELET_DLL_API void WAVELET_DLL_CC wv_done_decode_channels(t_wv_dchannels* dc)
{
if (dc)
{
int i;
for (i = 0; i < dc->hdr.num_channels; i++)
free(dc->channels[i]);
free(dc->channels);
free(dc);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -