1764 lines
48 KiB
C
1764 lines
48 KiB
C
/*
|
|
* Copyright (c) 2001-2003, David Janssens
|
|
* Copyright (c) 2002-2003, Yannick Verschueren
|
|
* Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe
|
|
* Copyright (c) 2005, Hervé Drolon, FreeImage Team
|
|
* Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium
|
|
* Copyright (c) 2005-2006, Dept. of Electronic and Information Engineering, Universita' degli Studi di Perugia, Italy
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef USE_JPWL
|
|
|
|
#include "../libopenjpeg/opj_includes.h"
|
|
#include <limits.h>
|
|
|
|
/** Minimum and maximum values for the double->pfp conversion */
|
|
#define MIN_V1 0.0
|
|
#define MAX_V1 17293822569102704640.0
|
|
#define MIN_V2 0.000030517578125
|
|
#define MAX_V2 131040.0
|
|
|
|
/** conversion between a double precision floating point
|
|
number and the corresponding pseudo-floating point used
|
|
to represent sensitivity values
|
|
@param V the double precision value
|
|
@param bytes the number of bytes of the representation
|
|
@return the pseudo-floating point value (cast accordingly)
|
|
*/
|
|
unsigned short int jpwl_double_to_pfp(double V, int bytes);
|
|
|
|
/** conversion between a pseudo-floating point used
|
|
to represent sensitivity values and the corresponding
|
|
double precision floating point number
|
|
@param em the pseudo-floating point value (cast accordingly)
|
|
@param bytes the number of bytes of the representation
|
|
@return the double precision value
|
|
*/
|
|
double jpwl_pfp_to_double(unsigned short int em, int bytes);
|
|
|
|
/*-------------------------------------------------------------*/
|
|
|
|
int jpwl_markcomp(const void *arg1, const void *arg2)
|
|
{
|
|
/* Compare the two markers' positions */
|
|
double diff = (((jpwl_marker_t *) arg1)->dpos - ((jpwl_marker_t *) arg2)->dpos);
|
|
|
|
if (diff == 0.0)
|
|
return (0);
|
|
else if (diff < 0)
|
|
return (-1);
|
|
else
|
|
return (+1);
|
|
}
|
|
|
|
int jpwl_epbs_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num,
|
|
bool latest, bool packed, bool insideMH, int *idx, int hprot,
|
|
double place_pos, int tileno,
|
|
unsigned long int pre_len, unsigned long int post_len) {
|
|
|
|
jpwl_epb_ms_t *epb_mark = NULL;
|
|
|
|
int k_pre, k_post, n_pre, n_post;
|
|
|
|
unsigned long int L1, L2, dL4, max_postlen, epbs_len = 0;
|
|
|
|
/* We find RS(n,k) for EPB parms and pre-data, if any */
|
|
if (insideMH && (*idx == 0)) {
|
|
/* First EPB in MH */
|
|
k_pre = 64;
|
|
n_pre = 160;
|
|
} else if (!insideMH && (*idx == 0)) {
|
|
/* First EPB in TH */
|
|
k_pre = 25;
|
|
n_pre = 80;
|
|
} else {
|
|
/* Following EPBs in MH or TH */
|
|
k_pre = 13;
|
|
n_pre = 40;
|
|
};
|
|
|
|
/* Find lengths, Figs. B3 and B4 */
|
|
/* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */
|
|
L1 = pre_len + 13;
|
|
|
|
/* size of pre-data redundancy */
|
|
/* (redundancy per codeword) * (number of codewords, rounded up) */
|
|
L2 = (n_pre - k_pre) * (unsigned long int) ceil((double) L1 / (double) k_pre);
|
|
|
|
/* Find protection type for post data and its associated redundancy field length*/
|
|
if ((hprot == 16) || (hprot == 32)) {
|
|
/* there is a CRC for post-data */
|
|
k_post = post_len;
|
|
n_post = post_len + (hprot >> 3);
|
|
/*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */
|
|
|
|
} else if ((hprot >= 37) && (hprot <= 128)) {
|
|
/* there is a RS for post-data */
|
|
k_post = 32;
|
|
n_post = hprot;
|
|
|
|
} else {
|
|
/* Use predefined codes */
|
|
n_post = n_pre;
|
|
k_post = k_pre;
|
|
};
|
|
|
|
/* Create the EPB(s) */
|
|
while (post_len > 0) {
|
|
|
|
/* maximum postlen in order to respect EPB size
|
|
(we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms)*/
|
|
/* (message word size) * (number of containable parity words) */
|
|
max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post));
|
|
|
|
/* maximum postlen in order to respect EPB size */
|
|
if (*idx == 0)
|
|
/* (we use (JPWL_MAXIMUM_EPB_ROOM - L2) instead of 65535 for keeping room for EPB parms + pre-data) */
|
|
/* (message word size) * (number of containable parity words) */
|
|
max_postlen = k_post * (unsigned long int) floor((double) (JPWL_MAXIMUM_EPB_ROOM - L2) / (double) (n_post - k_post));
|
|
|
|
else
|
|
/* (we use JPWL_MAXIMUM_EPB_ROOM instead of 65535 for keeping room for EPB parms) */
|
|
/* (message word size) * (number of containable parity words) */
|
|
max_postlen = k_post * (unsigned long int) floor((double) JPWL_MAXIMUM_EPB_ROOM / (double) (n_post - k_post));
|
|
|
|
/* null protection case */
|
|
/* the max post length can be as large as the LDPepb field can host */
|
|
if (hprot == 0)
|
|
max_postlen = INT_MAX;
|
|
|
|
/* length to use */
|
|
dL4 = min(max_postlen, post_len);
|
|
|
|
if (epb_mark = jpwl_epb_create(
|
|
j2k, /* this encoder handle */
|
|
latest ? (dL4 < max_postlen) : false, /* is it the latest? */
|
|
packed, /* is it packed? */
|
|
tileno, /* we are in TPH */
|
|
*idx, /* its index */
|
|
hprot, /* protection type parameters of following data */
|
|
0, /* pre-data: nothing for now */
|
|
dL4 /* post-data: the stub computed previously */
|
|
)) {
|
|
|
|
/* Add this marker to the 'insertanda' list */
|
|
if (*jwmarker_num < JPWL_MAX_NO_MARKERS) {
|
|
jwmarker[*jwmarker_num].id = J2K_MS_EPB; /* its type */
|
|
jwmarker[*jwmarker_num].epbmark = epb_mark; /* the EPB */
|
|
jwmarker[*jwmarker_num].pos = (int) place_pos; /* after SOT */
|
|
jwmarker[*jwmarker_num].dpos = place_pos + 0.0000001 * (double)(*idx); /* not very first! */
|
|
jwmarker[*jwmarker_num].len = epb_mark->Lepb; /* its length */
|
|
jwmarker[*jwmarker_num].len_ready = true; /* ready */
|
|
jwmarker[*jwmarker_num].pos_ready = true; /* ready */
|
|
jwmarker[*jwmarker_num].parms_ready = true; /* ready */
|
|
jwmarker[*jwmarker_num].data_ready = false; /* not ready */
|
|
(*jwmarker_num)++;
|
|
}
|
|
|
|
/* increment epb index */
|
|
(*idx)++;
|
|
|
|
/* decrease postlen */
|
|
post_len -= dL4;
|
|
|
|
/* increase the total length of EPBs */
|
|
epbs_len += epb_mark->Lepb + 2;
|
|
|
|
} else {
|
|
/* ooops, problems */
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not create TPH EPB for UEP in tile %d\n", tileno);
|
|
};
|
|
}
|
|
|
|
return epbs_len;
|
|
}
|
|
|
|
|
|
jpwl_epb_ms_t *jpwl_epb_create(opj_j2k_t *j2k, bool latest, bool packed, int tileno, int idx, int hprot,
|
|
unsigned long int pre_len, unsigned long int post_len) {
|
|
|
|
jpwl_epb_ms_t *epb = NULL;
|
|
unsigned short int data_len = 0;
|
|
unsigned short int L2, L3;
|
|
unsigned long int L1, L4;
|
|
unsigned char *predata_in = NULL;
|
|
|
|
bool insideMH = (tileno == -1);
|
|
|
|
/* Alloc space */
|
|
if (!(epb = (jpwl_epb_ms_t *) opj_malloc((size_t) 1 * sizeof (jpwl_epb_ms_t)))) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for one EPB MS\n");
|
|
return NULL;
|
|
};
|
|
|
|
/* We set RS(n,k) for EPB parms and pre-data, if any */
|
|
if (insideMH && (idx == 0)) {
|
|
/* First EPB in MH */
|
|
epb->k_pre = 64;
|
|
epb->n_pre = 160;
|
|
} else if (!insideMH && (idx == 0)) {
|
|
/* First EPB in TH */
|
|
epb->k_pre = 25;
|
|
epb->n_pre = 80;
|
|
} else {
|
|
/* Following EPBs in MH or TH */
|
|
epb->k_pre = 13;
|
|
epb->n_pre = 40;
|
|
};
|
|
|
|
/* Find lengths, Figs. B3 and B4 */
|
|
/* size of pre data: pre_buf(pre_len) + EPB(2) + Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) */
|
|
L1 = pre_len + 13;
|
|
epb->pre_len = pre_len;
|
|
|
|
/* size of pre-data redundancy */
|
|
/* (redundancy per codeword) * (number of codewords, rounded up) */
|
|
L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre);
|
|
|
|
/* length of post-data */
|
|
L4 = post_len;
|
|
epb->post_len = post_len;
|
|
|
|
/* Find protection type for post data and its associated redundancy field length*/
|
|
if ((hprot == 16) || (hprot == 32)) {
|
|
/* there is a CRC for post-data */
|
|
epb->Pepb = 0x10000000 | ((unsigned long int) hprot >> 5); /* 0=CRC-16, 1=CRC-32 */
|
|
epb->k_post = post_len;
|
|
epb->n_post = post_len + (hprot >> 3);
|
|
/*L3 = hprot >> 3;*/ /* 2 (CRC-16) or 4 (CRC-32) bytes */
|
|
|
|
} else if ((hprot >= 37) && (hprot <= 128)) {
|
|
/* there is a RS for post-data */
|
|
epb->Pepb = 0x20000020 | (((unsigned long int) hprot & 0x000000FF) << 8);
|
|
epb->k_post = 32;
|
|
epb->n_post = hprot;
|
|
|
|
} else if (hprot == 1) {
|
|
/* Use predefined codes */
|
|
epb->Pepb = (unsigned long int) 0x00000000;
|
|
epb->n_post = epb->n_pre;
|
|
epb->k_post = epb->k_pre;
|
|
|
|
} else if (hprot == 0) {
|
|
/* Placeholder EPB: only protects its parameters, no protection method */
|
|
epb->Pepb = (unsigned long int) 0xFFFFFFFF;
|
|
epb->n_post = 1;
|
|
epb->k_post = 1;
|
|
|
|
} else {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Invalid protection value for EPB h = %d\n", hprot);
|
|
return NULL;
|
|
}
|
|
|
|
epb->hprot = hprot;
|
|
|
|
/* (redundancy per codeword) * (number of codewords, rounded up) */
|
|
L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post);
|
|
|
|
/* private fields */
|
|
epb->tileno = tileno;
|
|
|
|
/* Fill some fields of the EPB */
|
|
|
|
/* total length of the EPB MS (less the EPB marker itself): */
|
|
/* Lepb(2) + Depb(1) + LDPepb(4) + Pepb(4) + pre_redundancy + post-redundancy */
|
|
epb->Lepb = 11 + L2 + L3;
|
|
|
|
/* EPB style */
|
|
epb->Depb = ((packed & 0x0001) << 7) | ((latest & 0x0001) << 6) | (idx & 0x003F);
|
|
|
|
/* length of data protected by EPB: */
|
|
epb->LDPepb = L1 + L4;
|
|
|
|
return epb;
|
|
}
|
|
|
|
void jpwl_epb_write(jpwl_epb_ms_t *epb, unsigned char *buf) {
|
|
|
|
/* Marker */
|
|
*(buf++) = (unsigned char) (J2K_MS_EPB >> 8);
|
|
*(buf++) = (unsigned char) (J2K_MS_EPB >> 0);
|
|
|
|
/* Lepb */
|
|
*(buf++) = (unsigned char) (epb->Lepb >> 8);
|
|
*(buf++) = (unsigned char) (epb->Lepb >> 0);
|
|
|
|
/* Depb */
|
|
*(buf++) = (unsigned char) (epb->Depb >> 0);
|
|
|
|
/* LDPepb */
|
|
*(buf++) = (unsigned char) (epb->LDPepb >> 24);
|
|
*(buf++) = (unsigned char) (epb->LDPepb >> 16);
|
|
*(buf++) = (unsigned char) (epb->LDPepb >> 8);
|
|
*(buf++) = (unsigned char) (epb->LDPepb >> 0);
|
|
|
|
/* Pepb */
|
|
*(buf++) = (unsigned char) (epb->Pepb >> 24);
|
|
*(buf++) = (unsigned char) (epb->Pepb >> 16);
|
|
*(buf++) = (unsigned char) (epb->Pepb >> 8);
|
|
*(buf++) = (unsigned char) (epb->Pepb >> 0);
|
|
|
|
/* Data */
|
|
/*memcpy(buf, epb->data, (size_t) epb->Lepb - 11);*/
|
|
memset(buf, 0, (size_t) epb->Lepb - 11);
|
|
};
|
|
|
|
|
|
jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, bool esd_on, bool red_on, bool epb_on, bool info_on) {
|
|
|
|
jpwl_epc_ms_t *epc = NULL;
|
|
|
|
/* Alloc space */
|
|
if (!(epc = (jpwl_epc_ms_t *) malloc((size_t) 1 * sizeof (jpwl_epc_ms_t)))) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for EPC MS\n");
|
|
return NULL;
|
|
};
|
|
|
|
/* Set the EPC parameters */
|
|
epc->esd_on = esd_on;
|
|
epc->epb_on = epb_on;
|
|
epc->red_on = red_on;
|
|
epc->info_on = info_on;
|
|
|
|
/* Fill the EPC fields with default values */
|
|
epc->Lepc = 9;
|
|
epc->Pcrc = 0x0000;
|
|
epc->DL = 0x00000000;
|
|
epc->Pepc = ((j2k->cp->esd_on & 0x0001) << 4) | ((j2k->cp->red_on & 0x0001) << 5) |
|
|
((j2k->cp->epb_on & 0x0001) << 6) | ((j2k->cp->info_on & 0x0001) << 7);
|
|
|
|
return (epc);
|
|
}
|
|
|
|
bool jpwl_epb_fill(opj_j2k_t *j2k, jpwl_epb_ms_t *epb, unsigned char *buf, unsigned char *post_buf) {
|
|
|
|
unsigned long int L1, L2, L3, L4;
|
|
int remaining;
|
|
unsigned long int P, NN_P;
|
|
|
|
/* Operating buffer */
|
|
static unsigned char codeword[NN], *parityword;
|
|
|
|
unsigned char *L1_buf, *L2_buf;
|
|
/* these ones are static, since we need to keep memory of
|
|
the exact place from one call to the other */
|
|
static unsigned char *L3_buf, *L4_buf;
|
|
|
|
/* some consistency check */
|
|
if (!buf) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs\n");
|
|
return false;
|
|
}
|
|
|
|
if (!post_buf && !L4_buf) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs data\n");
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Compute parity bytes on pre-data, ALWAYS present (at least only for EPB parms)
|
|
*/
|
|
|
|
/* Initialize RS structures */
|
|
P = epb->n_pre - epb->k_pre;
|
|
NN_P = NN - P;
|
|
memset(codeword, 0, NN);
|
|
parityword = codeword + NN_P;
|
|
init_rs(NN_P);
|
|
|
|
/* pre-data begins pre_len bytes before of EPB buf */
|
|
L1_buf = buf - epb->pre_len;
|
|
L1 = epb->pre_len + 13;
|
|
|
|
/* redundancy for pre-data begins immediately after EPB parms */
|
|
L2_buf = buf + 13;
|
|
L2 = (epb->n_pre - epb->k_pre) * (unsigned short int) ceil((double) L1 / (double) epb->k_pre);
|
|
|
|
/* post-data
|
|
the position of L4 buffer can be:
|
|
1) passed as a parameter: in that case use it
|
|
2) null: in that case use the previous (static) one
|
|
*/
|
|
if (post_buf)
|
|
L4_buf = post_buf;
|
|
L4 = epb->post_len;
|
|
|
|
/* post-data redundancy begins immediately after pre-data redundancy */
|
|
L3_buf = L2_buf + L2;
|
|
L3 = (epb->n_post - epb->k_post) * (unsigned short int) ceil((double) L4 / (double) epb->k_post);
|
|
|
|
/* let's check whether EPB length is sufficient to contain all these data */
|
|
if (epb->Lepb < (11 + L2 + L3))
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no room in EPB data field for writing redundancy data\n");
|
|
/*printf("Env. %d, nec. %d (%d + %d)\n", epb->Lepb - 11, L2 + L3, L2, L3);*/
|
|
|
|
/* Compute redundancy of pre-data message words */
|
|
remaining = L1;
|
|
while (remaining) {
|
|
|
|
/* copy message data into codeword buffer */
|
|
if (remaining < epb->k_pre) {
|
|
/* the last message word is zero-padded */
|
|
memset(codeword, 0, NN);
|
|
memcpy(codeword, L1_buf, remaining);
|
|
L1_buf += remaining;
|
|
remaining = 0;
|
|
|
|
} else {
|
|
memcpy(codeword, L1_buf, epb->k_pre);
|
|
L1_buf += epb->k_pre;
|
|
remaining -= epb->k_pre;
|
|
|
|
}
|
|
|
|
/* Encode the buffer and obtain parity bytes */
|
|
if (encode_rs(codeword, parityword))
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING,
|
|
"Possible encoding error in codeword @ position #%d\n", (L1_buf - buf) / epb->k_pre);
|
|
|
|
/* copy parity bytes only in redundancy buffer */
|
|
memcpy(L2_buf, parityword, P);
|
|
|
|
/* advance parity buffer */
|
|
L2_buf += P;
|
|
}
|
|
|
|
/*
|
|
* Compute parity bytes on post-data, may be absent if there are no data
|
|
*/
|
|
/*printf("Hprot is %d (tileno=%d, k_pre=%d, n_pre=%d, k_post=%d, n_post=%d, pre_len=%d, post_len=%d)\n",
|
|
epb->hprot, epb->tileno, epb->k_pre, epb->n_pre, epb->k_post, epb->n_post, epb->pre_len,
|
|
epb->post_len);*/
|
|
if (epb->hprot < 0) {
|
|
|
|
/* there should be no EPB */
|
|
|
|
} else if (epb->hprot == 0) {
|
|
|
|
/* no protection for the data */
|
|
/* advance anyway */
|
|
L4_buf += epb->post_len;
|
|
|
|
} else if (epb->hprot == 16) {
|
|
|
|
/* CRC-16 */
|
|
unsigned short int mycrc = 0x0000;
|
|
|
|
/* compute the CRC field (excluding itself) */
|
|
remaining = L4;
|
|
while (remaining--)
|
|
jpwl_updateCRC16(&mycrc, *(L4_buf++));
|
|
|
|
/* write the CRC field */
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 8);
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 0);
|
|
|
|
} else if (epb->hprot == 32) {
|
|
|
|
/* CRC-32 */
|
|
unsigned long int mycrc = 0x00000000;
|
|
|
|
/* compute the CRC field (excluding itself) */
|
|
remaining = L4;
|
|
while (remaining--)
|
|
jpwl_updateCRC32(&mycrc, *(L4_buf++));
|
|
|
|
/* write the CRC field */
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 24);
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 16);
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 8);
|
|
*(L3_buf++) = (unsigned char) (mycrc >> 0);
|
|
|
|
} else {
|
|
|
|
/* RS */
|
|
|
|
/* Initialize RS structures */
|
|
P = epb->n_post - epb->k_post;
|
|
NN_P = NN - P;
|
|
memset(codeword, 0, NN);
|
|
parityword = codeword + NN_P;
|
|
init_rs(NN_P);
|
|
|
|
/* Compute redundancy of post-data message words */
|
|
remaining = L4;
|
|
while (remaining) {
|
|
|
|
/* copy message data into codeword buffer */
|
|
if (remaining < epb->k_post) {
|
|
/* the last message word is zero-padded */
|
|
memset(codeword, 0, NN);
|
|
memcpy(codeword, L4_buf, remaining);
|
|
L4_buf += remaining;
|
|
remaining = 0;
|
|
|
|
} else {
|
|
memcpy(codeword, L4_buf, epb->k_post);
|
|
L4_buf += epb->k_post;
|
|
remaining -= epb->k_post;
|
|
|
|
}
|
|
|
|
/* Encode the buffer and obtain parity bytes */
|
|
if (encode_rs(codeword, parityword))
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING,
|
|
"Possible encoding error in codeword @ position #%d\n", (L4_buf - buf) / epb->k_post);
|
|
|
|
/* copy parity bytes only in redundancy buffer */
|
|
memcpy(L3_buf, parityword, P);
|
|
|
|
/* advance parity buffer */
|
|
L3_buf += P;
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool jpwl_correct(opj_j2k_t *j2k) {
|
|
|
|
opj_cio_t *cio = j2k->cio;
|
|
bool status;
|
|
static bool mh_done = false;
|
|
int mark_pos, id, len, skips, sot_pos;
|
|
unsigned long int Psot = 0;
|
|
|
|
/* go back to marker position */
|
|
mark_pos = cio_tell(cio) - 2;
|
|
cio_seek(cio, mark_pos);
|
|
|
|
if ((j2k->state == J2K_STATE_MHSOC) && !mh_done) {
|
|
|
|
int mark_val = 0, skipnum = 0;
|
|
|
|
/*
|
|
COLOR IMAGE
|
|
first thing to do, if we are here, is to look whether
|
|
51 (skipnum) positions ahead there is an EPB, in case of MH
|
|
*/
|
|
/*
|
|
B/W IMAGE
|
|
first thing to do, if we are here, is to look whether
|
|
45 (skipnum) positions ahead there is an EPB, in case of MH
|
|
*/
|
|
/* SIZ SIZ_FIELDS SIZ_COMPS FOLLOWING_MARKER */
|
|
skipnum = 2 + 38 + 3 * j2k->cp->exp_comps + 2;
|
|
if ((cio->bp + skipnum) < cio->end) {
|
|
|
|
cio_skip(cio, skipnum);
|
|
|
|
/* check that you are not going beyond the end of codestream */
|
|
|
|
/* call EPB corrector */
|
|
status = jpwl_epb_correct(j2k, /* J2K decompressor handle */
|
|
cio->bp, /* pointer to EPB in codestream buffer */
|
|
0, /* EPB type: MH */
|
|
skipnum, /* length of pre-data */
|
|
-1, /* length of post-data: -1 means auto */
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
/* read the marker value */
|
|
mark_val = (*(cio->bp) << 8) | *(cio->bp + 1);
|
|
|
|
if (status && (mark_val == J2K_MS_EPB)) {
|
|
/* we found it! */
|
|
mh_done = true;
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (true /*(j2k->state == J2K_STATE_TPHSOT) || (j2k->state == J2K_STATE_TPH)*/) {
|
|
/* else, look if 12 positions ahead there is an EPB, in case of TPH */
|
|
cio_seek(cio, mark_pos);
|
|
if ((cio->bp + 12) < cio->end) {
|
|
|
|
cio_skip(cio, 12);
|
|
|
|
/* call EPB corrector */
|
|
status = jpwl_epb_correct(j2k, /* J2K decompressor handle */
|
|
cio->bp, /* pointer to EPB in codestream buffer */
|
|
1, /* EPB type: TPH */
|
|
12, /* length of pre-data */
|
|
-1, /* length of post-data: -1 means auto */
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (status)
|
|
/* we found it! */
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
/* for now, don't use this code */
|
|
|
|
/* else, look if here is an EPB, in case of other */
|
|
if (mark_pos > 64) {
|
|
/* it cannot stay before the first MH EPB */
|
|
cio_seek(cio, mark_pos);
|
|
cio_skip(cio, 0);
|
|
|
|
/* call EPB corrector */
|
|
status = jpwl_epb_correct(j2k, /* J2K decompressor handle */
|
|
cio->bp, /* pointer to EPB in codestream buffer */
|
|
2, /* EPB type: TPH */
|
|
0, /* length of pre-data */
|
|
-1, /* length of post-data: -1 means auto */
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (status)
|
|
/* we found it! */
|
|
return true;
|
|
}
|
|
|
|
/* nope, no EPBs probably, or they are so damaged that we can give up */
|
|
return false;
|
|
|
|
return true;
|
|
|
|
/* AN ATTEMPT OF PARSER */
|
|
/* NOT USED ACTUALLY */
|
|
|
|
/* go to the beginning of the file */
|
|
cio_seek(cio, 0);
|
|
|
|
/* let's begin */
|
|
j2k->state = J2K_STATE_MHSOC;
|
|
|
|
/* cycle all over the markers */
|
|
while ((unsigned int) cio_tell(cio) < cio->length) {
|
|
|
|
/* read the marker */
|
|
mark_pos = cio_tell(cio);
|
|
id = cio_read(cio, 2);
|
|
|
|
/* details */
|
|
printf("Marker@%d: %X\n", cio_tell(cio) - 2, id);
|
|
|
|
/* do an action in response to the read marker */
|
|
switch (id) {
|
|
|
|
/* short markers */
|
|
|
|
/* SOC */
|
|
case J2K_MS_SOC:
|
|
j2k->state = J2K_STATE_MHSIZ;
|
|
len = 0;
|
|
skips = 0;
|
|
break;
|
|
|
|
/* EOC */
|
|
case J2K_MS_EOC:
|
|
j2k->state = J2K_STATE_MT;
|
|
len = 0;
|
|
skips = 0;
|
|
break;
|
|
|
|
/* particular case of SOD */
|
|
case J2K_MS_SOD:
|
|
len = Psot - (mark_pos - sot_pos) - 2;
|
|
skips = len;
|
|
break;
|
|
|
|
/* long markers */
|
|
|
|
/* SOT */
|
|
case J2K_MS_SOT:
|
|
j2k->state = J2K_STATE_TPH;
|
|
sot_pos = mark_pos; /* position of SOT */
|
|
len = cio_read(cio, 2); /* read the length field */
|
|
cio_skip(cio, 2); /* this field is unnecessary */
|
|
Psot = cio_read(cio, 4); /* tile length */
|
|
skips = len - 8;
|
|
break;
|
|
|
|
/* remaining */
|
|
case J2K_MS_SIZ:
|
|
j2k->state = J2K_STATE_MH;
|
|
/* read the length field */
|
|
len = cio_read(cio, 2);
|
|
skips = len - 2;
|
|
break;
|
|
|
|
/* remaining */
|
|
default:
|
|
/* read the length field */
|
|
len = cio_read(cio, 2);
|
|
skips = len - 2;
|
|
break;
|
|
|
|
}
|
|
|
|
/* skip to marker's end */
|
|
cio_skip(cio, skips);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
bool jpwl_epb_correct(opj_j2k_t *j2k, unsigned char *buffer, int type, int pre_len, int post_len, int *conn,
|
|
unsigned char **L4_bufp) {
|
|
|
|
/* Operating buffer */
|
|
unsigned char codeword[NN], *parityword;
|
|
|
|
unsigned long int P, NN_P;
|
|
unsigned long int L1, L4;
|
|
int remaining, n_pre, k_pre, n_post, k_post;
|
|
|
|
int status, tt;
|
|
|
|
int orig_pos = cio_tell(j2k->cio);
|
|
|
|
unsigned char *L1_buf, *L2_buf;
|
|
unsigned char *L3_buf, *L4_buf;
|
|
|
|
unsigned long int LDPepb, Pepb;
|
|
unsigned short int Lepb;
|
|
unsigned char Depb;
|
|
char str1[25] = "";
|
|
int myconn, errnum = 0;
|
|
bool errflag = false;
|
|
|
|
opj_cio_t *cio = j2k->cio;
|
|
|
|
/* check for common errors */
|
|
if (!buffer) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "The EPB pointer is a NULL buffer\n");
|
|
return false;
|
|
}
|
|
|
|
/* set bignesses */
|
|
L1 = pre_len + 13;
|
|
|
|
/* pre-data correction */
|
|
switch (type) {
|
|
|
|
case 0:
|
|
/* MH EPB */
|
|
k_pre = 64;
|
|
n_pre = 160;
|
|
break;
|
|
|
|
case 1:
|
|
/* TPH EPB */
|
|
k_pre = 25;
|
|
n_pre = 80;
|
|
break;
|
|
|
|
case 2:
|
|
/* other EPBs */
|
|
k_pre = 13;
|
|
n_pre = 40;
|
|
break;
|
|
|
|
case 3:
|
|
/* automatic setup */
|
|
break;
|
|
|
|
default:
|
|
/* unknown type */
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Unknown expected EPB type\n");
|
|
return false;
|
|
break;
|
|
|
|
}
|
|
|
|
/* Initialize RS structures */
|
|
P = n_pre - k_pre;
|
|
NN_P = NN - P;
|
|
tt = (int) floor((float) P / 2.0F); /* correction capability of the code */
|
|
memset(codeword, 0, NN);
|
|
parityword = codeword + NN_P;
|
|
init_rs(NN_P);
|
|
|
|
/* Correct pre-data message words */
|
|
L1_buf = buffer - pre_len;
|
|
L2_buf = buffer + 13;
|
|
remaining = L1;
|
|
while (remaining) {
|
|
|
|
/* always zero-pad codewords */
|
|
/* (this is required, since after decoding the zeros in the long codeword
|
|
could change, and keep unchanged in subsequent calls) */
|
|
memset(codeword, 0, NN);
|
|
|
|
/* copy codeword buffer into message bytes */
|
|
if (remaining < k_pre)
|
|
memcpy(codeword, L1_buf, remaining);
|
|
else
|
|
memcpy(codeword, L1_buf, k_pre);
|
|
|
|
/* copy redundancy buffer in parity bytes */
|
|
memcpy(parityword, L2_buf, P);
|
|
|
|
/* Decode the buffer and possibly obtain corrected bytes */
|
|
status = eras_dec_rs(codeword, NULL, 0);
|
|
if (status == -1) {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING,
|
|
"Possible decoding error in codeword @ position #%d\n", (L1_buf - buffer) / k_pre);*/
|
|
errflag = true;
|
|
/* we can try to safely get out from the function:
|
|
if we are here, either this is not an EPB or the first codeword
|
|
is too damaged to be helpful */
|
|
/*return false;*/
|
|
|
|
} else if (status == 0) {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/
|
|
|
|
} else if (status <= tt) {
|
|
/* it has corrected 0 <= errs <= tt */
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/
|
|
errnum += status;
|
|
|
|
} else {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n");
|
|
return false;*/
|
|
errflag = true;
|
|
}
|
|
|
|
|
|
/* advance parity buffer */
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected parity only if all is OK */
|
|
memcpy(L2_buf, parityword, P);
|
|
L2_buf += P;
|
|
|
|
/* advance message buffer */
|
|
if (remaining < k_pre) {
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected data only if all is OK */
|
|
memcpy(L1_buf, codeword, remaining);
|
|
L1_buf += remaining;
|
|
remaining = 0;
|
|
|
|
} else {
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected data only if all is OK */
|
|
memcpy(L1_buf, codeword, k_pre);
|
|
L1_buf += k_pre;
|
|
remaining -= k_pre;
|
|
|
|
}
|
|
}
|
|
|
|
/* print summary */
|
|
if (!conn) {
|
|
|
|
/*if (errnum)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "+ %d symbol errors corrected (Ps=%.1e)\n", errnum,
|
|
(float) errnum / ((float) n_pre * (float) L1 / (float) k_pre));*/
|
|
if (errflag) {
|
|
/*opj_event_msg(j2k->cinfo, EVT_INFO, "+ there were unrecoverable errors\n");*/
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
/* presumably, now, EPB parameters are correct */
|
|
/* let's get them */
|
|
|
|
/* Simply read the EPB parameters */
|
|
if (conn)
|
|
cio->bp = buffer;
|
|
cio_skip(cio, 2); /* the marker */
|
|
Lepb = cio_read(cio, 2);
|
|
Depb = cio_read(cio, 1);
|
|
LDPepb = cio_read(cio, 4);
|
|
Pepb = cio_read(cio, 4);
|
|
|
|
/* What does Pepb tells us about the protection method? */
|
|
if (((Pepb & 0xF0000000) >> 28) == 0)
|
|
sprintf(str1, "pred"); /* predefined */
|
|
else if (((Pepb & 0xF0000000) >> 28) == 1)
|
|
sprintf(str1, "crc-%d", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */
|
|
else if (((Pepb & 0xF0000000) >> 28) == 2)
|
|
sprintf(str1, "rs(%d,32)", (Pepb & 0x0000FF00) >> 8); /* RS mode */
|
|
else if (Pepb == 0xFFFFFFFF)
|
|
sprintf(str1, "nometh"); /* RS mode */
|
|
else
|
|
sprintf(str1, "unknown"); /* unknown */
|
|
|
|
/* Now we write them to screen */
|
|
if (!conn && post_len)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO,
|
|
"EPB(%d): (%sl, %sp, %u), %lu, %s\n",
|
|
cio_tell(cio) - 13,
|
|
(Depb & 0x40) ? "" : "n", /* latest EPB or not? */
|
|
(Depb & 0x80) ? "" : "n", /* packed or unpacked EPB? */
|
|
(Depb & 0x3F), /* EPB index value */
|
|
LDPepb, /*length of the data protected by the EPB */
|
|
str1); /* protection method */
|
|
|
|
|
|
/* well, we need to investigate how long is the connected length of packed EPBs */
|
|
myconn = Lepb + 2;
|
|
if ((Depb & 0x40) == 0) /* not latest in header */
|
|
jpwl_epb_correct(j2k, /* J2K decompressor handle */
|
|
buffer + Lepb + 2, /* pointer to next EPB in codestream buffer */
|
|
2, /* EPB type: should be of other type */
|
|
0, /* only EPB fields */
|
|
0, /* do not look after */
|
|
&myconn,
|
|
NULL
|
|
);
|
|
if (conn)
|
|
*conn += myconn;
|
|
|
|
/*if (!conn)
|
|
printf("connected = %d\n", myconn);*/
|
|
|
|
/*cio_seek(j2k->cio, orig_pos);
|
|
return true;*/
|
|
|
|
/* post-data
|
|
the position of L4 buffer is at the end of currently connected EPBs
|
|
*/
|
|
if (!(L4_bufp))
|
|
L4_buf = buffer + myconn;
|
|
else if (!(*L4_bufp))
|
|
L4_buf = buffer + myconn;
|
|
else
|
|
L4_buf = *L4_bufp;
|
|
if (post_len == -1)
|
|
L4 = LDPepb - pre_len - 13;
|
|
else if (post_len == 0)
|
|
L4 = 0;
|
|
else
|
|
L4 = post_len;
|
|
|
|
L3_buf = L2_buf;
|
|
|
|
/* Do a further check here on the read parameters */
|
|
if (L4 > (unsigned long) cio_numbytesleft(j2k->cio))
|
|
/* overflow */
|
|
return false;
|
|
|
|
/* we are ready for decoding the remaining data */
|
|
if (((Pepb & 0xF0000000) >> 28) == 1) {
|
|
/* CRC here */
|
|
if ((16 * ((Pepb & 0x00000001) + 1)) == 16) {
|
|
|
|
/* CRC-16 */
|
|
unsigned short int mycrc = 0x0000, filecrc = 0x0000;
|
|
|
|
/* compute the CRC field */
|
|
remaining = L4;
|
|
while (remaining--)
|
|
jpwl_updateCRC16(&mycrc, *(L4_buf++));
|
|
|
|
/* read the CRC field */
|
|
filecrc = *(L3_buf++) << 8;
|
|
filecrc |= *(L3_buf++);
|
|
|
|
/* check the CRC field */
|
|
if (mycrc == filecrc) {
|
|
if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n");
|
|
} else {
|
|
if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc);
|
|
errflag = true;
|
|
}
|
|
}
|
|
|
|
if ((16 * ((Pepb & 0x00000001) + 1)) == 32) {
|
|
|
|
/* CRC-32 */
|
|
unsigned long int mycrc = 0x00000000, filecrc = 0x00000000;
|
|
|
|
/* compute the CRC field */
|
|
remaining = L4;
|
|
while (remaining--)
|
|
jpwl_updateCRC32(&mycrc, *(L4_buf++));
|
|
|
|
/* read the CRC field */
|
|
filecrc = *(L3_buf++) << 24;
|
|
filecrc |= *(L3_buf++) << 16;
|
|
filecrc |= *(L3_buf++) << 8;
|
|
filecrc |= *(L3_buf++);
|
|
|
|
/* check the CRC field */
|
|
if (mycrc == filecrc) {
|
|
if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "- CRC is OK\n");
|
|
} else {
|
|
if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "- CRC is KO (r=%d, c=%d)\n", filecrc, mycrc);
|
|
errflag = true;
|
|
}
|
|
}
|
|
|
|
} else if (Pepb == 0xFFFFFFFF) {
|
|
/* no method */
|
|
|
|
/* advance without doing anything */
|
|
remaining = L4;
|
|
while (remaining--)
|
|
L4_buf++;
|
|
|
|
} else if ((((Pepb & 0xF0000000) >> 28) == 2) || (((Pepb & 0xF0000000) >> 28) == 0)) {
|
|
/* RS coding here */
|
|
|
|
if (((Pepb & 0xF0000000) >> 28) == 0) {
|
|
|
|
k_post = k_pre;
|
|
n_post = n_pre;
|
|
|
|
} else {
|
|
|
|
k_post = 32;
|
|
n_post = (Pepb & 0x0000FF00) >> 8;
|
|
}
|
|
|
|
/* Initialize RS structures */
|
|
P = n_post - k_post;
|
|
NN_P = NN - P;
|
|
tt = (int) floor((float) P / 2.0F); /* again, correction capability */
|
|
memset(codeword, 0, NN);
|
|
parityword = codeword + NN_P;
|
|
init_rs(NN_P);
|
|
|
|
/* Correct post-data message words */
|
|
/*L4_buf = buffer + Lepb + 2;*/
|
|
L3_buf = L2_buf;
|
|
remaining = L4;
|
|
while (remaining) {
|
|
|
|
/* always zero-pad codewords */
|
|
/* (this is required, since after decoding the zeros in the long codeword
|
|
could change, and keep unchanged in subsequent calls) */
|
|
memset(codeword, 0, NN);
|
|
|
|
/* copy codeword buffer into message bytes */
|
|
if (remaining < k_post)
|
|
memcpy(codeword, L4_buf, remaining);
|
|
else
|
|
memcpy(codeword, L4_buf, k_post);
|
|
|
|
/* copy redundancy buffer in parity bytes */
|
|
memcpy(parityword, L3_buf, P);
|
|
|
|
/* Decode the buffer and possibly obtain corrected bytes */
|
|
status = eras_dec_rs(codeword, NULL, 0);
|
|
if (status == -1) {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING,
|
|
"Possible decoding error in codeword @ position #%d\n", (L4_buf - (buffer + Lepb + 2)) / k_post);*/
|
|
errflag = true;
|
|
|
|
} else if (status == 0) {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "codeword is correctly decoded\n");*/
|
|
|
|
} else if (status <= tt) {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "%d errors corrected in codeword\n", status);*/
|
|
errnum += status;
|
|
|
|
} else {
|
|
/*if (conn == NULL)
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "EPB correction capability exceeded\n");
|
|
return false;*/
|
|
errflag = true;
|
|
}
|
|
|
|
|
|
/* advance parity buffer */
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected data only if all is OK */
|
|
memcpy(L3_buf, parityword, P);
|
|
L3_buf += P;
|
|
|
|
/* advance message buffer */
|
|
if (remaining < k_post) {
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected data only if all is OK */
|
|
memcpy(L4_buf, codeword, remaining);
|
|
L4_buf += remaining;
|
|
remaining = 0;
|
|
|
|
} else {
|
|
if ((status >= 0) && (status <= tt))
|
|
/* copy back corrected data only if all is OK */
|
|
memcpy(L4_buf, codeword, k_post);
|
|
L4_buf += k_post;
|
|
remaining -= k_post;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/* give back the L4_buf address */
|
|
if (L4_bufp)
|
|
*L4_bufp = L4_buf;
|
|
|
|
/* print summary */
|
|
if (!conn) {
|
|
|
|
if (errnum)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "- %d symbol errors corrected (Ps=%.1e)\n", errnum,
|
|
(float) errnum / (float) LDPepb);
|
|
if (errflag)
|
|
opj_event_msg(j2k->cinfo, EVT_INFO, "- there were unrecoverable errors\n");
|
|
|
|
}
|
|
|
|
cio_seek(j2k->cio, orig_pos);
|
|
|
|
return true;
|
|
}
|
|
|
|
void jpwl_epc_write(jpwl_epc_ms_t *epc, unsigned char *buf) {
|
|
|
|
/* Marker */
|
|
*(buf++) = (unsigned char) (J2K_MS_EPC >> 8);
|
|
*(buf++) = (unsigned char) (J2K_MS_EPC >> 0);
|
|
|
|
/* Lepc */
|
|
*(buf++) = (unsigned char) (epc->Lepc >> 8);
|
|
*(buf++) = (unsigned char) (epc->Lepc >> 0);
|
|
|
|
/* Pcrc */
|
|
*(buf++) = (unsigned char) (epc->Pcrc >> 8);
|
|
*(buf++) = (unsigned char) (epc->Pcrc >> 0);
|
|
|
|
/* DL */
|
|
*(buf++) = (unsigned char) (epc->DL >> 24);
|
|
*(buf++) = (unsigned char) (epc->DL >> 16);
|
|
*(buf++) = (unsigned char) (epc->DL >> 8);
|
|
*(buf++) = (unsigned char) (epc->DL >> 0);
|
|
|
|
/* Pepc */
|
|
*(buf++) = (unsigned char) (epc->Pepc >> 0);
|
|
|
|
/* Data */
|
|
/*memcpy(buf, epc->data, (size_t) epc->Lepc - 9);*/
|
|
memset(buf, 0, (size_t) epc->Lepc - 9);
|
|
};
|
|
|
|
int jpwl_esds_add(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int *jwmarker_num,
|
|
int comps, unsigned char addrm, unsigned char ad_size,
|
|
unsigned char senst, unsigned char se_size,
|
|
double place_pos, int tileno) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
jpwl_esd_ms_t *jpwl_esd_create(opj_j2k_t *j2k, int comp, unsigned char addrm, unsigned char ad_size,
|
|
unsigned char senst, unsigned char se_size, int tileno,
|
|
unsigned long int svalnum, void *sensval) {
|
|
|
|
jpwl_esd_ms_t *esd = NULL;
|
|
|
|
/* Alloc space */
|
|
if (!(esd = (jpwl_esd_ms_t *) malloc((size_t) 1 * sizeof (jpwl_esd_ms_t)))) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not allocate room for ESD MS\n");
|
|
return NULL;
|
|
};
|
|
|
|
/* if relative sensitivity, activate byte range mode */
|
|
if (senst == 0)
|
|
addrm = 1;
|
|
|
|
/* size of sensval's ... */
|
|
if ((ad_size != 0) && (ad_size != 2) && (ad_size != 4)) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Address size %d for ESD MS is forbidden\n", ad_size);
|
|
return NULL;
|
|
}
|
|
if ((se_size != 1) && (se_size != 2)) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Sensitivity size %d for ESD MS is forbidden\n", se_size);
|
|
return NULL;
|
|
}
|
|
|
|
/* ... depends on the addressing mode */
|
|
switch (addrm) {
|
|
|
|
/* packet mode */
|
|
case (0):
|
|
ad_size = 0; /* as per the standard */
|
|
esd->sensval_size = se_size;
|
|
break;
|
|
|
|
/* byte range */
|
|
case (1):
|
|
/* auto sense address size */
|
|
if (ad_size == 0)
|
|
/* if there are more than 66% of (2^16 - 1) bytes, switch to 4 bytes
|
|
(we keep space for possible EPBs being inserted) */
|
|
ad_size = (j2k->cstr_info->codestream_size > (1 * 65535 / 3)) ? 4 : 2;
|
|
esd->sensval_size = ad_size + ad_size + se_size;
|
|
break;
|
|
|
|
/* packet range */
|
|
case (2):
|
|
/* auto sense address size */
|
|
if (ad_size == 0)
|
|
/* if there are more than 2^16 - 1 packets, switch to 4 bytes */
|
|
ad_size = (j2k->cstr_info->packno > 65535) ? 4 : 2;
|
|
esd->sensval_size = ad_size + ad_size + se_size;
|
|
break;
|
|
|
|
case (3):
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is unimplemented\n", addrm);
|
|
return NULL;
|
|
|
|
default:
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "Address mode %d for ESD MS is forbidden\n", addrm);
|
|
return NULL;
|
|
}
|
|
|
|
/* set or unset sensitivity values */
|
|
if (svalnum <= 0) {
|
|
|
|
switch (senst) {
|
|
|
|
/* just based on the portions of a codestream */
|
|
case (0):
|
|
/* MH + no. of THs + no. of packets */
|
|
svalnum = 1 + (j2k->cstr_info->tw * j2k->cstr_info->th) * (1 + j2k->cstr_info->packno);
|
|
break;
|
|
|
|
/* all the ones that are based on the packets */
|
|
default:
|
|
if (tileno < 0)
|
|
/* MH: all the packets and all the tiles info is written */
|
|
svalnum = j2k->cstr_info->tw * j2k->cstr_info->th * j2k->cstr_info->packno;
|
|
else
|
|
/* TPH: only that tile info is written */
|
|
svalnum = j2k->cstr_info->packno;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
/* fill private fields */
|
|
esd->senst = senst;
|
|
esd->ad_size = ad_size;
|
|
esd->se_size = se_size;
|
|
esd->addrm = addrm;
|
|
esd->svalnum = svalnum;
|
|
esd->numcomps = j2k->image->numcomps;
|
|
esd->tileno = tileno;
|
|
|
|
/* Set the ESD parameters */
|
|
/* length, excluding data field */
|
|
if (esd->numcomps < 257)
|
|
esd->Lesd = 4 + (unsigned short int) (esd->svalnum * esd->sensval_size);
|
|
else
|
|
esd->Lesd = 5 + (unsigned short int) (esd->svalnum * esd->sensval_size);
|
|
|
|
/* component data field */
|
|
if (comp >= 0)
|
|
esd->Cesd = comp;
|
|
else
|
|
/* we are averaging */
|
|
esd->Cesd = 0;
|
|
|
|
/* Pesd field */
|
|
esd->Pesd = 0x00;
|
|
esd->Pesd |= (esd->addrm & 0x03) << 6; /* addressing mode */
|
|
esd->Pesd |= (esd->senst & 0x07) << 3; /* sensitivity type */
|
|
esd->Pesd |= ((esd->se_size >> 1) & 0x01) << 2; /* sensitivity size */
|
|
esd->Pesd |= ((esd->ad_size >> 2) & 0x01) << 1; /* addressing size */
|
|
esd->Pesd |= (comp < 0) ? 0x01 : 0x00; /* averaging components */
|
|
|
|
/* if pointer to sensval is NULL, we can fill data field by ourselves */
|
|
if (!sensval) {
|
|
|
|
/* old code moved to jpwl_esd_fill() */
|
|
esd->data = NULL;
|
|
|
|
} else {
|
|
/* we set the data field as the sensitivity values poinnter passed to the function */
|
|
esd->data = (unsigned char *) sensval;
|
|
}
|
|
|
|
return (esd);
|
|
}
|
|
|
|
bool jpwl_esd_fill(opj_j2k_t *j2k, jpwl_esd_ms_t *esd, unsigned char *buf) {
|
|
|
|
int i;
|
|
unsigned long int vv;
|
|
unsigned long int addr1, addr2;
|
|
double dvalue, Omax2, tmp, TSE, MSE, oldMSE, PSNR, oldPSNR;
|
|
unsigned short int pfpvalue;
|
|
unsigned long int addrmask = 0x00000000;
|
|
bool doneMH = false, doneTPH = false;
|
|
|
|
/* sensitivity values in image info are as follows:
|
|
- for each tile, distotile is the starting distortion for that tile, sum of all components
|
|
- for each packet in a tile, disto is the distortion reduction caused by that packet to that tile
|
|
- the TSE for a single tile should be given by distotile - sum(disto) , for all components
|
|
- the MSE for a single tile is given by TSE / nbpix , for all components
|
|
- the PSNR for a single tile is given by 10*log10( Omax^2 / MSE) , for all components
|
|
(Omax is given by 2^bpp - 1 for unsigned images and by 2^(bpp - 1) - 1 for signed images
|
|
*/
|
|
|
|
/* browse all components and find Omax */
|
|
Omax2 = 0.0;
|
|
for (i = 0; i < j2k->image->numcomps; i++) {
|
|
tmp = pow(2.0, (double) (j2k->image->comps[i].sgnd ?
|
|
(j2k->image->comps[i].bpp - 1) : (j2k->image->comps[i].bpp))) - 1;
|
|
if (tmp > Omax2)
|
|
Omax2 = tmp;
|
|
}
|
|
Omax2 = Omax2 * Omax2;
|
|
|
|
/* if pointer of esd->data is not null, simply write down all the values byte by byte */
|
|
if (esd->data) {
|
|
for (i = 0; i < (int) esd->svalnum; i++)
|
|
*(buf++) = esd->data[i];
|
|
return true;
|
|
}
|
|
|
|
/* addressing mask */
|
|
if (esd->ad_size == 2)
|
|
addrmask = 0x0000FFFF; /* two bytes */
|
|
else
|
|
addrmask = 0xFFFFFFFF; /* four bytes */
|
|
|
|
/* set on precise point where sensitivity starts */
|
|
if (esd->numcomps < 257)
|
|
buf += 6;
|
|
else
|
|
buf += 7;
|
|
|
|
/* let's fill the data fields */
|
|
for (vv = (esd->tileno < 0) ? 0 : (j2k->cstr_info->packno * esd->tileno); vv < esd->svalnum; vv++) {
|
|
|
|
int thistile = vv / j2k->cstr_info->packno, thispacket = vv % j2k->cstr_info->packno;
|
|
|
|
/* skip for the hack some lines below */
|
|
if (thistile == j2k->cstr_info->tw * j2k->cstr_info->th)
|
|
break;
|
|
|
|
/* starting tile distortion */
|
|
if (thispacket == 0) {
|
|
TSE = j2k->cstr_info->tile[thistile].distotile;
|
|
oldMSE = TSE / j2k->cstr_info->tile[thistile].numpix;
|
|
oldPSNR = 10.0 * log10(Omax2 / oldMSE);
|
|
}
|
|
|
|
/* TSE */
|
|
TSE -= j2k->cstr_info->tile[thistile].packet[thispacket].disto;
|
|
|
|
/* MSE */
|
|
MSE = TSE / j2k->cstr_info->tile[thistile].numpix;
|
|
|
|
/* PSNR */
|
|
PSNR = 10.0 * log10(Omax2 / MSE);
|
|
|
|
/* fill the address range */
|
|
switch (esd->addrm) {
|
|
|
|
/* packet mode */
|
|
case (0):
|
|
/* nothing, there is none */
|
|
break;
|
|
|
|
/* byte range */
|
|
case (1):
|
|
/* start address of packet */
|
|
addr1 = (j2k->cstr_info->tile[thistile].packet[thispacket].start_pos) & addrmask;
|
|
/* end address of packet */
|
|
addr2 = (j2k->cstr_info->tile[thistile].packet[thispacket].end_pos) & addrmask;
|
|
break;
|
|
|
|
/* packet range */
|
|
case (2):
|
|
/* not implemented here */
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "Addressing mode packet_range is not implemented\n");
|
|
break;
|
|
|
|
/* unknown addressing method */
|
|
default:
|
|
/* not implemented here */
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "Unknown addressing mode\n");
|
|
break;
|
|
|
|
}
|
|
|
|
/* hack for writing relative sensitivity of MH and TPHs */
|
|
if ((esd->senst == 0) && (thispacket == 0)) {
|
|
|
|
/* possible MH */
|
|
if ((thistile == 0) && !doneMH) {
|
|
/* we have to manage MH addresses */
|
|
addr1 = 0; /* start of MH */
|
|
addr2 = j2k->cstr_info->main_head_end; /* end of MH */
|
|
/* set special dvalue for this MH */
|
|
dvalue = -10.0;
|
|
doneMH = true; /* don't come here anymore */
|
|
vv--; /* wrap back loop counter */
|
|
|
|
} else if (!doneTPH) {
|
|
/* we have to manage TPH addresses */
|
|
addr1 = j2k->cstr_info->tile[thistile].start_pos;
|
|
addr2 = j2k->cstr_info->tile[thistile].end_header;
|
|
/* set special dvalue for this TPH */
|
|
dvalue = -1.0;
|
|
doneTPH = true; /* don't come here till the next tile */
|
|
vv--; /* wrap back loop counter */
|
|
}
|
|
|
|
} else
|
|
doneTPH = false; /* reset TPH counter */
|
|
|
|
/* write the addresses to the buffer */
|
|
switch (esd->ad_size) {
|
|
|
|
case (0):
|
|
/* do nothing */
|
|
break;
|
|
|
|
case (2):
|
|
/* two bytes */
|
|
*(buf++) = (unsigned char) (addr1 >> 8);
|
|
*(buf++) = (unsigned char) (addr1 >> 0);
|
|
*(buf++) = (unsigned char) (addr2 >> 8);
|
|
*(buf++) = (unsigned char) (addr2 >> 0);
|
|
break;
|
|
|
|
case (4):
|
|
/* four bytes */
|
|
*(buf++) = (unsigned char) (addr1 >> 24);
|
|
*(buf++) = (unsigned char) (addr1 >> 16);
|
|
*(buf++) = (unsigned char) (addr1 >> 8);
|
|
*(buf++) = (unsigned char) (addr1 >> 0);
|
|
*(buf++) = (unsigned char) (addr2 >> 24);
|
|
*(buf++) = (unsigned char) (addr2 >> 16);
|
|
*(buf++) = (unsigned char) (addr2 >> 8);
|
|
*(buf++) = (unsigned char) (addr2 >> 0);
|
|
break;
|
|
|
|
default:
|
|
/* do nothing */
|
|
break;
|
|
}
|
|
|
|
|
|
/* let's fill the value field */
|
|
switch (esd->senst) {
|
|
|
|
/* relative sensitivity */
|
|
case (0):
|
|
/* we just write down the packet ordering */
|
|
if (dvalue == -10)
|
|
/* MH */
|
|
dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */
|
|
else if (dvalue == -1)
|
|
/* TPH */
|
|
dvalue = MAX_V1 + 1000.0; /* this will cause pfpvalue set to 0xFFFF */
|
|
else
|
|
/* packet: first is most important, and then in decreasing order
|
|
down to the last, which counts for 1 */
|
|
dvalue = jpwl_pfp_to_double((unsigned short) (j2k->cstr_info->packno - thispacket), esd->se_size);
|
|
break;
|
|
|
|
/* MSE */
|
|
case (1):
|
|
/* !!! WRONG: let's put here disto field of packets !!! */
|
|
dvalue = MSE;
|
|
break;
|
|
|
|
/* MSE reduction */
|
|
case (2):
|
|
dvalue = oldMSE - MSE;
|
|
oldMSE = MSE;
|
|
break;
|
|
|
|
/* PSNR */
|
|
case (3):
|
|
dvalue = PSNR;
|
|
break;
|
|
|
|
/* PSNR increase */
|
|
case (4):
|
|
dvalue = PSNR - oldPSNR;
|
|
oldPSNR = PSNR;
|
|
break;
|
|
|
|
/* MAXERR */
|
|
case (5):
|
|
dvalue = 0.0;
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "MAXERR sensitivity mode is not implemented\n");
|
|
break;
|
|
|
|
/* TSE */
|
|
case (6):
|
|
dvalue = TSE;
|
|
break;
|
|
|
|
/* reserved */
|
|
case (7):
|
|
dvalue = 0.0;
|
|
opj_event_msg(j2k->cinfo, EVT_WARNING, "Reserved sensitivity mode is not implemented\n");
|
|
break;
|
|
|
|
default:
|
|
dvalue = 0.0;
|
|
break;
|
|
}
|
|
|
|
/* compute the pseudo-floating point value */
|
|
pfpvalue = jpwl_double_to_pfp(dvalue, esd->se_size);
|
|
|
|
/* write the pfp value to the buffer */
|
|
switch (esd->se_size) {
|
|
|
|
case (1):
|
|
/* one byte */
|
|
*(buf++) = (unsigned char) (pfpvalue >> 0);
|
|
break;
|
|
|
|
case (2):
|
|
/* two bytes */
|
|
*(buf++) = (unsigned char) (pfpvalue >> 8);
|
|
*(buf++) = (unsigned char) (pfpvalue >> 0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void jpwl_esd_write(jpwl_esd_ms_t *esd, unsigned char *buf) {
|
|
|
|
/* Marker */
|
|
*(buf++) = (unsigned char) (J2K_MS_ESD >> 8);
|
|
*(buf++) = (unsigned char) (J2K_MS_ESD >> 0);
|
|
|
|
/* Lesd */
|
|
*(buf++) = (unsigned char) (esd->Lesd >> 8);
|
|
*(buf++) = (unsigned char) (esd->Lesd >> 0);
|
|
|
|
/* Cesd */
|
|
if (esd->numcomps >= 257)
|
|
*(buf++) = (unsigned char) (esd->Cesd >> 8);
|
|
*(buf++) = (unsigned char) (esd->Cesd >> 0);
|
|
|
|
/* Pesd */
|
|
*(buf++) = (unsigned char) (esd->Pesd >> 0);
|
|
|
|
/* Data */
|
|
if (esd->numcomps < 257)
|
|
memset(buf, 0xAA, (size_t) esd->Lesd - 4);
|
|
/*memcpy(buf, esd->data, (size_t) esd->Lesd - 4);*/
|
|
else
|
|
memset(buf, 0xAA, (size_t) esd->Lesd - 5);
|
|
/*memcpy(buf, esd->data, (size_t) esd->Lesd - 5);*/
|
|
}
|
|
|
|
unsigned short int jpwl_double_to_pfp(double V, int bytes) {
|
|
|
|
unsigned short int em, e, m;
|
|
|
|
switch (bytes) {
|
|
|
|
case (1):
|
|
|
|
if (V < MIN_V1) {
|
|
e = 0x0000;
|
|
m = 0x0000;
|
|
} else if (V > MAX_V1) {
|
|
e = 0x000F;
|
|
m = 0x000F;
|
|
} else {
|
|
e = (unsigned short int) (floor(log(V) * 1.44269504088896) / 4.0);
|
|
m = (unsigned short int) (0.5 + (V / (pow(2.0, (double) (4 * e)))));
|
|
}
|
|
em = ((e & 0x000F) << 4) + (m & 0x000F);
|
|
break;
|
|
|
|
case (2):
|
|
|
|
if (V < MIN_V2) {
|
|
e = 0x0000;
|
|
m = 0x0000;
|
|
} else if (V > MAX_V2) {
|
|
e = 0x001F;
|
|
m = 0x07FF;
|
|
} else {
|
|
e = (unsigned short int) floor(log(V) * 1.44269504088896) + 15;
|
|
m = (unsigned short int) (0.5 + 2048.0 * ((V / (pow(2.0, (double) e - 15.0))) - 1.0));
|
|
}
|
|
em = ((e & 0x001F) << 11) + (m & 0x07FF);
|
|
break;
|
|
|
|
default:
|
|
|
|
em = 0x0000;
|
|
break;
|
|
};
|
|
|
|
return em;
|
|
}
|
|
|
|
double jpwl_pfp_to_double(unsigned short int em, int bytes) {
|
|
|
|
double V;
|
|
|
|
switch (bytes) {
|
|
|
|
case 1:
|
|
V = (double) (em & 0x0F) * pow(2.0, (double) (em & 0xF0));
|
|
break;
|
|
|
|
case 2:
|
|
|
|
V = pow(2.0, (double) ((em & 0xF800) >> 11) - 15.0) * (1.0 + (double) (em & 0x07FF) / 2048.0);
|
|
break;
|
|
|
|
default:
|
|
V = 0.0;
|
|
break;
|
|
|
|
}
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
bool jpwl_update_info(opj_j2k_t *j2k, jpwl_marker_t *jwmarker, int jwmarker_num) {
|
|
|
|
int mm;
|
|
unsigned long int addlen;
|
|
|
|
opj_codestream_info_t *info = j2k->cstr_info;
|
|
int tileno, tpno, packno, numtiles = info->th * info->tw, numpacks = info->packno;
|
|
|
|
if (!j2k || !jwmarker ) {
|
|
opj_event_msg(j2k->cinfo, EVT_ERROR, "J2K handle or JPWL markers list badly allocated\n");
|
|
return false;
|
|
}
|
|
|
|
/* main_head_end: how many markers are there before? */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->main_head_end)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->main_head_end += addlen;
|
|
|
|
/* codestream_size: always increment with all markers */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->codestream_size += addlen;
|
|
|
|
/* navigate through all the tiles */
|
|
for (tileno = 0; tileno < numtiles; tileno++) {
|
|
|
|
/* start_pos: increment with markers before SOT */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].start_pos)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->tile[tileno].start_pos += addlen;
|
|
|
|
/* end_header: increment with markers before of it */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_header)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->tile[tileno].end_header += addlen;
|
|
|
|
/* end_pos: increment with markers before the end of this tile */
|
|
/* code is disabled, since according to JPWL no markers can be beyond TPH */
|
|
/*addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].end_pos)
|
|
addlen += jwmarker[mm].len + 2;*/
|
|
info->tile[tileno].end_pos += addlen;
|
|
|
|
/* navigate through all the tile parts */
|
|
for (tpno = 0; tpno < info->tile[tileno].num_tps; tpno++) {
|
|
|
|
/* start_pos: increment with markers before SOT */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_start_pos)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->tile[tileno].tp[tpno].tp_start_pos += addlen;
|
|
|
|
/* end_header: increment with markers before of it */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_header)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->tile[tileno].tp[tpno].tp_end_header += addlen;
|
|
|
|
/* end_pos: increment with markers before the end of this tile part */
|
|
addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].tp[tpno].tp_end_pos)
|
|
addlen += jwmarker[mm].len + 2;
|
|
info->tile[tileno].tp[tpno].tp_end_pos += addlen;
|
|
|
|
}
|
|
|
|
/* navigate through all the packets in this tile */
|
|
for (packno = 0; packno < numpacks; packno++) {
|
|
|
|
/* start_pos: increment with markers before the packet */
|
|
/* disabled for the same reason as before */
|
|
/*addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].start_pos)
|
|
addlen += jwmarker[mm].len + 2;*/
|
|
info->tile[tileno].packet[packno].start_pos += addlen;
|
|
|
|
/* end_pos: increment if marker is before the end of packet */
|
|
/* disabled for the same reason as before */
|
|
/*addlen = 0;
|
|
for (mm = 0; mm < jwmarker_num; mm++)
|
|
if (jwmarker[mm].pos < (unsigned long int) info->tile[tileno].packet[packno].end_pos)
|
|
addlen += jwmarker[mm].len + 2;*/
|
|
info->tile[tileno].packet[packno].end_pos += addlen;
|
|
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif /* USE_JPWL */
|