/* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2001-2003, David Janssens * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe * Copyright (c) 2005, Herve 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 "opj_includes.h" #include /** 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, opj_bool latest, opj_bool packed, opj_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) : OPJ_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].m.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 = OPJ_TRUE; /* ready */ jwmarker[*jwmarker_num].pos_ready = OPJ_TRUE; /* ready */ jwmarker[*jwmarker_num].parms_ready = OPJ_TRUE; /* ready */ jwmarker[*jwmarker_num].data_ready = OPJ_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, opj_bool latest, opj_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;*/ opj_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(opj_j2k_t *j2k, 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); /* update markers struct */ j2k_add_marker(j2k->cstr_info, J2K_MS_EPB, -1, epb->Lepb + 2); } jpwl_epc_ms_t *jpwl_epc_create(opj_j2k_t *j2k, opj_bool esd_on, opj_bool red_on, opj_bool epb_on, opj_bool info_on) { jpwl_epc_ms_t *epc = NULL; /* Alloc space */ if (!(epc = (jpwl_epc_ms_t *) opj_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); } opj_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 OPJ_FALSE; } if (!post_buf && !L4_buf) { opj_event_msg(j2k->cinfo, EVT_ERROR, "There is no operating buffer for EPBs data\n"); return OPJ_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 OPJ_TRUE; } opj_bool jpwl_correct(opj_j2k_t *j2k) { opj_cio_t *cio = j2k->cio; opj_bool status; static opj_bool mh_done = OPJ_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 = OPJ_TRUE; return OPJ_TRUE; } /* Disable correction in case of missing or bad head EPB */ /* We can't do better! */ /* PATCHED: 2008-01-25 */ /* MOVED UP: 2008-02-01 */ if (!status) { j2k->cp->correct = OPJ_FALSE; opj_event_msg(j2k->cinfo, EVT_WARNING, "Couldn't find the MH EPB: disabling JPWL\n"); } } } if (OPJ_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 OPJ_TRUE; } } } return OPJ_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 OPJ_TRUE; } } /* nope, no EPBs probably, or they are so damaged that we can give up */ return OPJ_FALSE; return OPJ_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 (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); } } opj_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; opj_bool errflag = OPJ_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 OPJ_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 */ opj_event_msg(j2k->cinfo, EVT_ERROR, "Auto. setup not yet implemented\n"); return OPJ_FALSE; break; default: /* unknown type */ opj_event_msg(j2k->cinfo, EVT_ERROR, "Unknown expected EPB type\n"); return OPJ_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 = OPJ_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 OPJ_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 OPJ_FALSE;*/ errflag = OPJ_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 OPJ_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-%lu", 16 * ((Pepb & 0x00000001) + 1)); /* CRC mode */ } else if (((Pepb & 0xF0000000) >> 28) == 2) { sprintf(str1, "rs(%lu,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 OPJ_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 OPJ_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 = OPJ_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 = OPJ_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 = OPJ_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 OPJ_FALSE;*/ errflag = OPJ_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 OPJ_TRUE; } void jpwl_epc_write(opj_j2k_t *j2k, 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); /* update markers struct */ j2k_add_marker(j2k->cstr_info, J2K_MS_EPC, -1, epc->Lepc + 2); } 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, int se_size, int tileno, unsigned long int svalnum, void *sensval) { jpwl_esd_ms_t *esd = NULL; /* Alloc space */ if (!(esd = (jpwl_esd_ms_t *) opj_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 = (unsigned int)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 pointer passed to the function */ esd->data = (unsigned char *) sensval; } return (esd); } opj_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 = 0L, addr2 = 0L; double dvalue = 0.0, Omax2, tmp, TSE = 0.0, MSE, oldMSE = 0.0, PSNR, oldPSNR = 0.0; unsigned short int pfpvalue; unsigned long int addrmask = 0x00000000; opj_bool doneMH = OPJ_FALSE, doneTPH = OPJ_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 OPJ_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 = OPJ_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 = OPJ_TRUE; /* don't come here till the next tile */ vv--; /* wrap back loop counter */ } } else { doneTPH = OPJ_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 OPJ_TRUE; } opj_bool jpwl_esd_write(opj_j2k_t *j2k, 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);*/ /* update markers struct */ j2k_add_marker(j2k->cstr_info, J2K_MS_ESD, -1, esd->Lesd + 2); return OPJ_TRUE; } 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; } opj_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 OPJ_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_ph_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].end_ph_pos) addlen += jwmarker[mm].len + 2;*/ info->tile[tileno].packet[packno].end_ph_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; } } /* reorder the markers list */ return OPJ_TRUE; } #endif /* USE_JPWL */