Cleanup code related to quality layer allocation, and add a few safety checks

This commit is contained in:
Even Rouault 2022-08-11 18:06:21 +02:00
parent 3d9bcd3753
commit c06632c6f6
No known key found for this signature in database
GPG Key ID: 33EBBFC47B3DD87D
7 changed files with 94 additions and 59 deletions

View File

@ -846,7 +846,7 @@ static int parse_cmdline_encoder(int argc, char **argv,
/* ----------------------------------------------------- */
case 'q': { /* add fixed_quality */
case 'q': { /* layer allocation by distortion ratio (PSNR) */
char *s = opj_optarg;
while (sscanf(s, "%f", &parameters->tcp_distoratio[parameters->tcp_numlayers])
== 1) {
@ -866,7 +866,7 @@ static int parse_cmdline_encoder(int argc, char **argv,
/* dda */
/* ----------------------------------------------------- */
case 'f': { /* mod fixed_quality (before : -q) */
case 'f': { /* layer allocation by fixed layer */
int *row = NULL, *col = NULL;
OPJ_UINT32 numlayers = 0, numresolution = 0, matrix_width = 0;
@ -1812,7 +1812,7 @@ static int parse_cmdline_encoder(int argc, char **argv,
parameters->cp_fixed_quality))) {
fprintf(stderr, "[ERROR] options -r -q and -f cannot be used together !!\n");
return 1;
} /* mod fixed_quality */
}
/* if no rate entered, lossless by default */

View File

@ -7666,6 +7666,27 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
return OPJ_FALSE;
}
if (parameters->cp_fixed_alloc) {
if (parameters->cp_matrice == NULL) {
opj_event_msg(p_manager, EVT_ERROR,
"cp_fixed_alloc set, but cp_matrice missing\n");
return OPJ_FALSE;
}
if (parameters->tcp_numlayers > J2K_TCD_MATRIX_MAX_LAYER_COUNT) {
opj_event_msg(p_manager, EVT_ERROR,
"tcp_numlayers when cp_fixed_alloc set should not exceed %d\n",
J2K_TCD_MATRIX_MAX_LAYER_COUNT);
return OPJ_FALSE;
}
if (parameters->numresolution > J2K_TCD_MATRIX_MAX_RESOLUTION_COUNT) {
opj_event_msg(p_manager, EVT_ERROR,
"numresolution when cp_fixed_alloc set should not exceed %d\n",
J2K_TCD_MATRIX_MAX_RESOLUTION_COUNT);
return OPJ_FALSE;
}
}
p_j2k->m_specific_param.m_encoder.m_nb_comps = image->numcomps;
/* keep a link to cp so that we can destroy it later in j2k_destroy_compress */
@ -7885,15 +7906,17 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
cp->m_specific_param.m_enc.m_max_comp_size = (OPJ_UINT32)
parameters->max_comp_size;
cp->rsiz = parameters->rsiz;
cp->m_specific_param.m_enc.m_disto_alloc = (OPJ_UINT32)
parameters->cp_disto_alloc & 1u;
cp->m_specific_param.m_enc.m_fixed_alloc = (OPJ_UINT32)
parameters->cp_fixed_alloc & 1u;
cp->m_specific_param.m_enc.m_fixed_quality = (OPJ_UINT32)
parameters->cp_fixed_quality & 1u;
if (parameters->cp_fixed_alloc) {
cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy = FIXED_LAYER;
} else if (parameters->cp_fixed_quality) {
cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy =
FIXED_DISTORTION_RATIO;
} else {
cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy =
RATE_DISTORTION_RATIO;
}
/* mod fixed_quality */
if (parameters->cp_fixed_alloc && parameters->cp_matrice) {
if (parameters->cp_fixed_alloc) {
size_t array_size = (size_t)parameters->tcp_numlayers *
(size_t)parameters->numresolution * 3 * sizeof(OPJ_INT32);
cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size);
@ -8051,22 +8074,25 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
opj_tcp_t *tcp = &cp->tcps[tileno];
const OPJ_BOOL fixed_distoratio =
cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
FIXED_DISTORTION_RATIO;
tcp->numlayers = (OPJ_UINT32)parameters->tcp_numlayers;
for (j = 0; j < tcp->numlayers; j++) {
if (OPJ_IS_CINEMA(cp->rsiz) || OPJ_IS_IMF(cp->rsiz)) {
if (cp->m_specific_param.m_enc.m_fixed_quality) {
if (fixed_distoratio) {
tcp->distoratio[j] = parameters->tcp_distoratio[j];
}
tcp->rates[j] = parameters->tcp_rates[j];
} else {
if (cp->m_specific_param.m_enc.m_fixed_quality) { /* add fixed_quality */
if (fixed_distoratio) {
tcp->distoratio[j] = parameters->tcp_distoratio[j];
} else {
tcp->rates[j] = parameters->tcp_rates[j];
}
}
if (!cp->m_specific_param.m_enc.m_fixed_quality &&
if (!fixed_distoratio &&
tcp->rates[j] <= 1.0) {
tcp->rates[j] = 0.0; /* force lossless */
}

View File

@ -113,6 +113,9 @@ The functions in J2K.C have for goal to read/write the several parts of the code
#define J2K_MAX_POCS 32 /**< Maximum number of POCs */
#define J2K_TCD_MATRIX_MAX_LAYER_COUNT 10
#define J2K_TCD_MATRIX_MAX_RESOLUTION_COUNT 10
/* ----------------------------------------------------------------------- */
/**
@ -272,7 +275,7 @@ typedef struct opj_tcp {
OPJ_UINT32 ppt_data_size;
/** size of ppt_data*/
OPJ_UINT32 ppt_len;
/** add fixed_quality */
/** PSNR values */
OPJ_FLOAT32 distoratio[100];
/** tile-component coding parameters */
opj_tccp_t *tccps;
@ -314,6 +317,14 @@ typedef struct opj_tcp {
} opj_tcp_t;
/**
Rate allocation strategy
*/
typedef enum {
RATE_DISTORTION_RATIO = 0, /** allocation by rate/distortion */
FIXED_DISTORTION_RATIO = 1, /** allocation by fixed distortion ratio (PSNR) (fixed quality) */
FIXED_LAYER = 2, /** allocation by fixed layer (number of passes per layer / resolution / subband) */
} J2K_QUALITY_LAYER_ALLOCATION_STRATEGY;
typedef struct opj_encoding_param {
@ -325,12 +336,8 @@ typedef struct opj_encoding_param {
OPJ_INT32 *m_matrice;
/** Flag determining tile part generation*/
OPJ_BYTE m_tp_flag;
/** allocation by rate/distortion */
OPJ_BITFIELD m_disto_alloc : 1;
/** allocation by fixed layer */
OPJ_BITFIELD m_fixed_alloc : 1;
/** add fixed_quality */
OPJ_BITFIELD m_fixed_quality : 1;
/** Quality layer allocation strategy */
J2K_QUALITY_LAYER_ALLOCATION_STRATEGY m_quality_layer_alloc_strategy;
/** Enabling Tile part generation*/
OPJ_BITFIELD m_tp_on : 1;
}

View File

@ -405,7 +405,7 @@ typedef struct opj_cparameters {
int cp_disto_alloc;
/** allocation by fixed layer */
int cp_fixed_alloc;
/** add fixed_quality */
/** allocation by fixed quality (PSNR) */
int cp_fixed_quality;
/** fixed layer */
int *cp_matrice;
@ -829,9 +829,9 @@ typedef struct opj_tile_info {
int pdy[33];
/** information concerning packets inside tile */
opj_packet_info_t *packet;
/** add fixed_quality */
/** number of pixels of the tile */
int numpix;
/** add fixed_quality */
/** distortion of the tile */
double distotile;
/** number of markers */
int marknum;

View File

@ -1410,7 +1410,6 @@ static void opj_t1_dec_clnpass(
}
/** mod fixed_quality */
static OPJ_FLOAT64 opj_t1_getwmsedec(
OPJ_INT32 nmsedec,
OPJ_UINT32 compno,
@ -2313,7 +2312,7 @@ OPJ_BOOL opj_t1_encode_cblks(opj_tcd_t* tcd,
OPJ_UINT32 compno, resno, bandno, precno, cblkno;
opj_mutex_t* mutex = opj_mutex_create();
tile->distotile = 0; /* fixed_quality */
tile->distotile = 0;
for (compno = 0; compno < tile->numcomps; ++compno) {
opj_tcd_tilecomp_t* tilec = &tile->comps[compno];
@ -2401,7 +2400,6 @@ static int opj_t1_enc_is_term_pass(opj_tcd_cblk_enc_t* cblk,
}
/** mod fixed_quality */
static OPJ_FLOAT64 opj_t1_encode_cblk(opj_t1_t *t1,
opj_tcd_cblk_enc_t* cblk,
OPJ_UINT32 orient,
@ -2505,7 +2503,6 @@ static OPJ_FLOAT64 opj_t1_encode_cblk(opj_t1_t *t1,
break;
}
/* fixed_quality */
tempwmsedec = opj_t1_getwmsedec(nmsedec, compno, level, orient, bpno, qmfbid,
stepsize, numcomps, mct_norms, mct_numcomps) ;
cumwmsedec += tempwmsedec;

View File

@ -256,7 +256,7 @@ OPJ_BOOL opj_tcd_makelayer(opj_tcd_t *tcd,
opj_tcd_tile_t *tcd_tile = tcd->tcd_image->tiles;
OPJ_BOOL layer_allocation_is_same = OPJ_TRUE;
tcd_tile->distolayer[layno] = 0; /* fixed_quality */
tcd_tile->distolayer[layno] = 0;
for (compno = 0; compno < tcd_tile->numcomps; compno++) {
opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno];
@ -338,7 +338,7 @@ OPJ_BOOL opj_tcd_makelayer(opj_tcd_t *tcd,
cblk->passes[cblk->numpassesinlayers - 1].distortiondec;
}
tcd_tile->distolayer[layno] += layer->disto; /* fixed_quality */
tcd_tile->distolayer[layno] += layer->disto;
if (final) {
cblk->numpassesinlayers = n;
@ -351,13 +351,14 @@ OPJ_BOOL opj_tcd_makelayer(opj_tcd_t *tcd,
return layer_allocation_is_same;
}
/** For m_quality_layer_alloc_strategy == FIXED_LAYER */
static
void opj_tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno,
OPJ_UINT32 final)
{
OPJ_UINT32 compno, resno, bandno, precno, cblkno;
OPJ_INT32 value; /*, matrice[tcd_tcp->numlayers][tcd_tile->comps[0].numresolutions][3]; */
OPJ_INT32 matrice[10][10][3];
OPJ_INT32 matrice[J2K_TCD_MATRIX_MAX_LAYER_COUNT][J2K_TCD_MATRIX_MAX_RESOLUTION_COUNT][3];
OPJ_UINT32 i, j, k;
opj_cp_t *cp = tcd->cp;
@ -458,8 +459,8 @@ void opj_tcd_makelayer_fixed(opj_tcd_t *tcd, OPJ_UINT32 layno,
}
/** Rate allocation for the following methods:
* - allocation by rate/distortio (m_disto_alloc == 1)
* - allocation by fixed quality (m_fixed_quality == 1)
* - allocation by rate/distortio (m_quality_layer_alloc_strategy == RATE_DISTORTION_RATIO)
* - allocation by fixed quality (m_quality_layer_alloc_strategy == FIXED_DISTORTION_RATIO)
*/
static
OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
@ -472,8 +473,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
OPJ_UINT32 compno, resno, bandno, precno, cblkno, layno;
OPJ_UINT32 passno;
OPJ_FLOAT64 min, max;
OPJ_FLOAT64 cumdisto[100]; /* fixed_quality */
const OPJ_FLOAT64 K = 1; /* 1.1; fixed_quality */
OPJ_FLOAT64 cumdisto[100];
const OPJ_FLOAT64 K = 1;
OPJ_FLOAT64 maxSE = 0;
opj_cp_t *cp = tcd->cp;
@ -483,7 +484,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
min = DBL_MAX;
max = 0;
tcd_tile->numpix = 0; /* fixed_quality */
tcd_tile->numpix = 0;
for (compno = 0; compno < tcd_tile->numcomps; compno++) {
opj_tcd_tilecomp_t *tilec = &tcd_tile->comps[compno];
@ -533,9 +534,12 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
}
} /* passno */
/* fixed_quality */
tcd_tile->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0));
tilec->numpix += ((cblk->x1 - cblk->x0) * (cblk->y1 - cblk->y0));
{
const OPJ_SIZE_T cblk_pix_count = (OPJ_SIZE_T)((cblk->x1 - cblk->x0) *
(cblk->y1 - cblk->y0));
tcd_tile->numpix += cblk_pix_count;
tilec->numpix += cblk_pix_count;
}
} /* cbklno */
} /* precno */
} /* bandno */
@ -549,8 +553,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
/* index file */
if (cstr_info) {
opj_tile_info_t *tile_info = &cstr_info->tile[tcd->tcd_tileno];
tile_info->numpix = tcd_tile->numpix;
tile_info->distotile = tcd_tile->distotile;
tile_info->numpix = (int)tcd_tile->numpix;
tile_info->distotile = (int)tcd_tile->distotile;
tile_info->thresh = (OPJ_FLOAT64 *) opj_malloc(tcd_tcp->numlayers * sizeof(
OPJ_FLOAT64));
if (!tile_info->thresh) {
@ -567,19 +571,20 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
OPJ_FLOAT64 goodthresh = 0;
OPJ_FLOAT64 stable_thresh = 0;
OPJ_UINT32 i;
OPJ_FLOAT64 distotarget; /* fixed_quality */
OPJ_FLOAT64 distotarget;
/* fixed_quality */
distotarget = tcd_tile->distotile - ((K * maxSE) / pow((OPJ_FLOAT32)10,
tcd_tcp->distoratio[layno] / 10));
/* Don't try to find an optimal threshold but rather take everything not included yet, if
-r xx,yy,zz,0 (disto_alloc == 1 and rates == 0)
-q xx,yy,zz,0 (fixed_quality == 1 and distoratio == 0)
-r xx,yy,zz,0 (m_quality_layer_alloc_strategy == RATE_DISTORTION_RATIO and rates == NULL)
-q xx,yy,zz,0 (m_quality_layer_alloc_strategy == FIXED_DISTORTION_RATIO and distoratio == NULL)
==> possible to have some lossy layers and the last layer for sure lossless */
if (((cp->m_specific_param.m_enc.m_disto_alloc == 1) &&
if (((cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
RATE_DISTORTION_RATIO) &&
(tcd_tcp->rates[layno] > 0.0f)) ||
((cp->m_specific_param.m_enc.m_fixed_quality == 1) &&
((cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
FIXED_DISTORTION_RATIO) &&
(tcd_tcp->distoratio[layno] > 0.0))) {
opj_t2_t*t2 = opj_t2_create(tcd->image, cp);
OPJ_FLOAT64 thresh = 0;
@ -590,7 +595,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
}
for (i = 0; i < 128; ++i) {
OPJ_FLOAT64 distoachieved = 0; /* fixed_quality */
OPJ_FLOAT64 distoachieved = 0;
OPJ_BOOL layer_allocation_is_same;
OPJ_FLOAT64 new_thresh = (lo + hi) / 2;
@ -612,7 +617,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
opj_event_msg(p_manager, EVT_INFO, "--> layer_allocation_is_same = %d",
layer_allocation_is_same);
#endif
if (cp->m_specific_param.m_enc.m_fixed_quality) { /* fixed_quality */
if (cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
FIXED_DISTORTION_RATIO) {
if (OPJ_IS_CINEMA(cp->rsiz) || OPJ_IS_IMF(cp->rsiz)) {
if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest,
p_data_written, maxlen, cstr_info, NULL, tcd->cur_tp_num, tcd->tp_pos,
@ -698,7 +704,6 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd,
opj_tcd_makelayer(tcd, layno, goodthresh, 1);
/* fixed_quality */
cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] :
(cumdisto[layno - 1] + tcd_tile->distolayer[layno]);
}
@ -2662,10 +2667,10 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd,
p_cstr_info->index_write = 0;
}
if (l_cp->m_specific_param.m_enc.m_disto_alloc ||
l_cp->m_specific_param.m_enc.m_fixed_quality) {
/* fixed_quality */
/* Normal Rate/distortion allocation */
if (l_cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
RATE_DISTORTION_RATIO ||
l_cp->m_specific_param.m_enc.m_quality_layer_alloc_strategy ==
FIXED_DISTORTION_RATIO) {
if (! opj_tcd_rateallocate(p_tcd, p_dest_data, &l_nb_written, p_max_dest_size,
p_cstr_info, p_manager)) {
return OPJ_FALSE;

View File

@ -222,8 +222,8 @@ typedef struct opj_tcd_tilecomp {
OPJ_UINT32 win_x1;
OPJ_UINT32 win_y1;
/* add fixed_quality */
OPJ_INT32 numpix;
/* number of pixels */
OPJ_SIZE_T numpix;
} opj_tcd_tilecomp_t;
@ -235,9 +235,9 @@ typedef struct opj_tcd_tile {
OPJ_INT32 x0, y0, x1, y1;
OPJ_UINT32 numcomps; /* number of components in tile */
opj_tcd_tilecomp_t *comps; /* Components information */
OPJ_INT32 numpix; /* add fixed_quality */
OPJ_FLOAT64 distotile; /* add fixed_quality */
OPJ_FLOAT64 distolayer[100]; /* add fixed_quality */
OPJ_SIZE_T numpix; /* number of pixels */
OPJ_FLOAT64 distotile; /* distortion of the tile */
OPJ_FLOAT64 distolayer[100]; /* distortion per layer */
OPJ_UINT32 packno; /* packet number */
} opj_tcd_tile_t;