📄 tcq_quant.c
字号:
/*****************************************************************************/
/* Copyright 1999 Science Applications International Corporation (SAIC). */
/* Copyright 1995 University of Arizona, Arizona Board of Regents. */
/* All rights reserved */
/* File: "tcq_quant.c" */
/* Description: Trellis coded quantization */
/* Author: Joe Triscari/Tom Flohr */
/* Affiliation: SAIC */
/* Version: VM9.0 */
/* Last Revised: 20 April, 2001 */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to support arbitrary reference points for the */
/* transform and the various regular partitions, so as to facilitate */
/* cropping and geometric transformations in the compressed domain and to */
/* enable full support for CRF's single-sample overlap Wavelet transform, */
/* as originally documented in Seoul. Changes are too numerous to flag */
/* individually within the code. Changes copyrighted by HP with all rights */
/* reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to support interface modifications, arbitrary */
/* changes in coding parameters from component to component and from tile */
/* to tile, to support the full generality of PART-1 of the JPEG2000 */
/* standard, and to support most anticipated generality of PART-2. Changes */
/* are too numerous to flag individually within the code, which in some */
/* places has been completely rewritten. All changes copyrighted by HP with */
/* all rights reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified for general wavelet decompositions. */
/* Copyright 2000 Science Applications International Corporation (SAIC). */
/* Copyright 1995 University of Arizona, Arizona Board of Regents. */
/* All Rights Reserved for modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified for general offset and scalar quantization. */
/* Copyright 2000 The MITRE Corporation. */
/* All Rights Reserved for modified parts. */
/*****************************************************************************/
#include <local_services.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include <ifc.h>
#include <markers.h>
#include "tcq_quant_local.h"
#ifndef MAX
#define MAX(A,B) ((A)>(B)?(A):(B))
#endif
#ifndef MIN
#define MIN(A,B) ((A)<(B)?(A):(B))
#endif
extern void ftcq(float *class_coef, std_int *quant_code_words, std_int n1,
float ql_step, int * scan_order);
/* ========================================================================= */
/* ---------------------------- Internal Functions ------------------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC is_power_of_2 */
/*****************************************************************************/
static int
is_power_of_2(int val)
{
if (val == 0)
return(0);
while (!(val & 1))
val>>=1;
return(val == 1);
}
/*****************************************************************************/
/* STATIC AllocateBlockBuffer */
/*****************************************************************************/
static float **
AllocateBlockBuffer(int width, int height)
{
float **retval;
int i;
retval = (float **)local_malloc(TCQ_MEM_KEY,
sizeof(float*)*height);
retval[0] = (float *)local_malloc(TCQ_MEM_KEY,
sizeof(float)*width*height);
for (i = 1; i < height; i++)
retval[i] = retval[i-1] + width;
return (retval);
}
/*****************************************************************************/
/* STATIC DeleteBlockBuffer */
/*****************************************************************************/
static void
DeleteBlockBuffer(float **buffer)
{
if (buffer == NULL) return;
local_free(buffer[0]);
local_free(buffer);
}
/*****************************************************************************/
/* STATIC ConvertTCQStates */
/*****************************************************************************/
static void
ConvertTCQStates(std_int *cast_buf, int width, int extra_lsbs)
{
int i, signbit;
int extra_lsbs_neg = 0;
if (extra_lsbs < 0) {
extra_lsbs_neg = 1;
extra_lsbs *= -1;
}
signbit = 1<<31;
if (extra_lsbs_neg == 0) {
for (i = 0; i < width; i++) {
if (cast_buf[i] < 0) cast_buf[i] = ((-cast_buf[i])<<extra_lsbs)|signbit;
else cast_buf[i] <<= extra_lsbs;
}
}
else {
for (i = 0; i < width; i++) {
if (cast_buf[i] < 0) cast_buf[i] = ((-cast_buf[i])>>extra_lsbs)|signbit;
else cast_buf[i] >>= extra_lsbs;
}
}
}
/*****************************************************************************/
/* STATIC get_scan_order */
/*****************************************************************************/
int *get_scan_order(int block_height, int block_width)
{
int *scan_order;
int upper_limit;
int i, j, k, l = 0;
scan_order = (int *) local_malloc(TCQ_MEM_KEY, sizeof(int)*block_height*block_width);
for (i=0; i<block_height; i+=4) {
upper_limit = MIN(i+4, block_height);
for (j=0; j<block_width; j++) {
for (k=i; k<upper_limit; k++) {
scan_order[l++] = k*block_width + j;
}
}
}
return(scan_order);
}
/*****************************************************************************/
/* STATIC TCQBlock */
/*****************************************************************************/
static void
TCQBlock(float **block, int block_width, int block_height,
int block_offset, float scale, int extra_lsbs,
tcq_quantizer_ref self)
/* Quantize one block of the indicated dimensions from the `block' buffer.
The first entry in each row of the buffer is found by adding `block_offset'
to the corresponding entry in the `block' array. Returns with the
contents of the relevant portion of the `block' buffer overwritten with
32 bit integers representing the quantized sample values to be sent
on to the encoder. The caller must pass these to the encoder, after
aggregating all horizontally adjacent blocks in the tile and correcting
for any mismatch between the size of "ifc_int" and "std_int" data
types. */
{
int j, tcq_len;
static float *data = NULL; /* It would be a good idea to get rid */
static std_int *states = NULL; /* of these static variables later; */
static int max_height, max_width; /* they make the code non-reentrant. */
int *scan_order;
if (block == NULL) {
if (data) local_free(data);
if (states) local_free(states);
data = NULL;
states = NULL;
return;
}
if (data == NULL) {
data = (float *)local_malloc(TCQ_MEM_KEY,
sizeof(float)*block_width*block_height);
states = (std_int *)local_malloc(TCQ_MEM_KEY,
sizeof(std_int)*block_width*block_height);
max_height = block_height;
max_width = block_width;
}
else if ((block_height*block_width) > (max_height*max_width)) {
local_free(data);
local_free(states);
data = (float *)local_malloc(TCQ_MEM_KEY,
sizeof(float)*block_width*block_height);
states = (std_int *)local_malloc(TCQ_MEM_KEY,
sizeof(std_int)*block_width*block_height);
max_height = block_height;
max_width = block_width;
}
tcq_len = 0;
for (j=0; j < block_height; j++)
{
memcpy(data+tcq_len,block[j]+block_offset,sizeof(float)*block_width);
tcq_len += block_width;
}
scan_order = get_scan_order(block_height, block_width);
ftcq(data, states, tcq_len, scale, scan_order);
local_free(scan_order);
ConvertTCQStates(states, tcq_len, extra_lsbs);
tcq_len = 0;
for (j=0; j < block_height; j++)
{
memcpy(block[j]+block_offset,states+tcq_len,sizeof(float)*block_width);
tcq_len += block_width;
}
}
/*****************************************************************************/
/* STATIC destroy_component_structures */
/*****************************************************************************/
static void
destroy_component_structures(tcq_component_info_ptr comp)
{
tcq_level_info_ptr lev;
tcq_band_info_ptr band;
int n, b;
/* Bug fix added by TJF */
if (comp->levels == NULL)
return;
for (n=0; n <= comp->num_levels; n++)
{
lev = comp->levels + n;
if (lev->bands != NULL)
{
for (b = lev->min_band; b <= lev->max_band; b++)
{
band = lev->bands + b;
if (!band->valid_band)
continue;
assert(band->num_lines == 0);
DeleteBlockBuffer(band->line_buffer);
}
local_free(lev->bands);
}
}
local_free(comp->levels);
}
/*****************************************************************************/
/* STATIC start_tile */
/*****************************************************************************/
static void
start_tile(tcq_quantizer_ref self)
{
forward_info_ref info = self->info;
encoder_ref encoder = self->encoder;
int num_components = self->num_components;
tcq_component_info_ptr comp;
tcq_level_info_ptr lev;
tcq_band_info_ptr band;
int reversible, c, n, b;
for (c=0; c < num_components; c++)
{
comp = self->components + c;
destroy_component_structures(comp);
comp->num_levels =
info->get_var_tile_info(info,c,NULL,NULL,&reversible,NULL,NULL);
if (reversible)
local_error("Cannot use TCQ with reversible decompositions!");
comp->levels = (tcq_level_info_ptr)
local_malloc(TCQ_MEM_KEY,sizeof(tcq_level_info)*(comp->num_levels+1));
for (n=0; n <= comp->num_levels; n++)
{
int max_hp_descent;
float step_size;
int exponent, extra_lsbs;
lev = comp->levels + n;
if (n == 0)
lev->min_band = lev->max_band = LL_BAND;
else
{
info->get_level_info(info,c,n,NULL,&max_hp_descent,NULL,NULL);
if (max_hp_descent == 0)
{
lev->min_band = 0;
lev->max_band = -1;
continue;
}
else
{
lev->min_band = 1 << (max_hp_descent+max_hp_descent-2);
lev->max_band = (1<<(max_hp_descent+max_hp_descent)) - 1;
}
}
lev->bands = (tcq_band_info_ptr)
local_malloc(TCQ_MEM_KEY,
sizeof(tcq_band_info)*(lev->max_band+1));
for (b=lev->min_band; b <= lev->max_band; b++)
{
band = lev->bands + b;
info->get_band_info(info,c,n,b,NULL,NULL,NULL,NULL,NULL,NULL,&(band->valid_band));
if (!band->valid_band)
continue;
info->get_quant_info(info,c,n,b,&step_size,&exponent,NULL,
&extra_lsbs, NULL, NULL);
band->extra_lsbs = extra_lsbs;
band->line_buffer = NULL;
band->num_lines = 0;
band->scale = step_size;
band->scale /= 2.0F;
}
}
}
/* Now set up the block structure. */
for (c=0; c < self->num_components; c++)
{
comp = self->components + c;
for (n=0; n <= comp->num_levels; n++)
{
canvas_dims dims;
frame_info frame;
lev = comp->levels + n;
for (b=lev->min_band; b <= lev->max_band; b++)
{
int block_height, block_width;
band = lev->bands + b;
if (!band->valid_band)
continue;
info->get_band_info(info,c,n,b,&dims,&frame,NULL,NULL,NULL,NULL,NULL);
encoder->get_block_ht_wd(encoder,c,n,b,
&block_height,&block_width);
assert(is_power_of_2(block_width) &&
is_power_of_2(block_height));
band->first_block_width = block_width -
((dims.left_col - frame.dims.left_col) & (block_width - 1));
band->first_block_height = block_height -
((dims.top_row - frame.dims.top_row) & (block_height - 1));
if (band->first_block_height > dims.rows)
band->first_block_height = dims.rows;
if (band->first_block_width > dims.cols)
band->first_block_width = dims.cols;
band->block_width = block_width;
band->block_height = block_height;
band->num_lines = 0;
band->remaining_tile_height = dims.rows;
band->current_block_height = band->first_block_height;
}
}
}
}
/* ========================================================================= */
/* ------------------------- Interface Implementation ---------------------- */
/* ========================================================================= */
/*****************************************************************************/
/* STATIC __initialize */
/*****************************************************************************/
static void
__initialize(quantizer_ref base, int num_components,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -