/*@{*/
/**
- * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures.
+ * Sets up the procedures to do on reading header. Developers wanting to extend the library can add their own reading procedures.
*/
static OPJ_BOOL opj_j2k_setup_header_reading(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager);
opj_event_mgr_t * p_manager);
/**
- * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters
- * are valid. Developpers wanting to extend the library can add their own validation procedures.
+ * Sets up the validation ,i.e. adds the procedures to launch to make sure the codec parameters
+ * are valid. Developers wanting to extend the library can add their own validation procedures.
*/
static OPJ_BOOL opj_j2k_setup_encoding_validation(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager);
/**
- * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters
- * are valid. Developpers wanting to extend the library can add their own validation procedures.
+ * Sets up the validation ,i.e. adds the procedures to launch to make sure the codec parameters
+ * are valid. Developers wanting to extend the library can add their own validation procedures.
*/
static OPJ_BOOL opj_j2k_setup_decoding_validation(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager);
/**
- * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters
- * are valid. Developpers wanting to extend the library can add their own validation procedures.
+ * Sets up the validation ,i.e. adds the procedures to launch to make sure the codec parameters
+ * are valid. Developers wanting to extend the library can add their own validation procedures.
*/
static OPJ_BOOL opj_j2k_setup_end_compress(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager);
opj_event_mgr_t * p_manager);
/**
- * Excutes the given procedures on the given codec.
+ * Executes the given procedures on the given codec.
*
* @param p_procedure_list the list of procedures to execute
* @param p_j2k the jpeg2000 codec to execute the procedures on.
static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
opj_stream_private_t *p_stream,
struct opj_event_mgr * p_manager);
static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
opj_stream_private_t *p_stream,
struct opj_event_mgr * p_manager);
opj_event_mgr_t * p_manager);
/**
- * Reads a COD marker (Coding Styke defaults)
+ * Reads a COD marker (Coding style defaults)
* @param p_header_data the data contained in the COD box.
* @param p_j2k the jpeg2000 codec.
* @param p_header_size the size of the data contained in the COD marker.
*
* @param p_j2k J2K codec.
* @param p_data Output buffer
- * @param p_total_data_size Output buffer size
+ * @param total_data_size Output buffer size
* @param p_data_written Number of bytes written into stream
* @param p_stream the stream to write data to.
* @param p_manager the user event manager.
*/
static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
OPJ_UINT32 * p_data_written,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager);
/**
* Writes the SOD marker (Start of data)
*
+ * This also writes optional PLT markers (before SOD)
+ *
* @param p_j2k J2K codec.
* @param p_tile_coder FIXME DOC
* @param p_data FIXME DOC
* @param p_data_written FIXME DOC
- * @param p_total_data_size FIXME DOC
+ * @param total_data_size FIXME DOC
* @param p_stream the stream to write data to.
* @param p_manager the user event manager.
*/
opj_tcd_t * p_tile_coder,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager);
static void opj_j2k_update_tlm(opj_j2k_t * p_j2k, OPJ_UINT32 p_tile_part_size)
{
- opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,
- p_j2k->m_current_tile_number, 1); /* PSOT */
- ++p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current;
+ if (p_j2k->m_specific_param.m_encoder.m_Ttlmi_is_byte) {
+ opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,
+ p_j2k->m_current_tile_number, 1);
+ p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 1;
+ } else {
+ opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,
+ p_j2k->m_current_tile_number, 2);
+ p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current += 2;
+ }
opj_write_bytes(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current,
p_tile_part_size, 4); /* PSOT */
OPJ_UINT32 p_header_size,
opj_event_mgr_t * p_manager);
+/**
+ * Reads a CAP marker (extended capabilities definition). Empty implementation.
+ * Found in HTJ2K files
+ *
+ * @param p_header_data the data contained in the CAP box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the CAP marker.
+ * @param p_manager the user event manager.
+*/
+static OPJ_BOOL opj_j2k_read_cap(opj_j2k_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ opj_event_mgr_t * p_manager);
+
+/**
+ * Reads a CPF marker (corresponding profile). Empty implementation. Found in HTJ2K files
+ * @param p_header_data the data contained in the CPF box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the CPF marker.
+ * @param p_manager the user event manager.
+*/
+static OPJ_BOOL opj_j2k_read_cpf(opj_j2k_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ opj_event_mgr_t * p_manager);
+
/**
* Writes COC marker for each component.
* A nice message is outputted at errors.
*
* @param p_pocs the progression order changes.
+ * @param tileno the tile number of interest
* @param p_nb_pocs the number of progression order changes.
* @param p_nb_resolutions the number of resolutions.
* @param numcomps the number of components
* @return true if the pocs are valid.
*/
static OPJ_BOOL opj_j2k_check_poc_val(const opj_poc_t *p_pocs,
+ OPJ_UINT32 tileno,
OPJ_UINT32 p_nb_pocs,
OPJ_UINT32 p_nb_resolutions,
OPJ_UINT32 numcomps,
static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz,
opj_event_mgr_t *p_manager);
+static void opj_j2k_set_imf_parameters(opj_cparameters_t *parameters,
+ opj_image_t *image, opj_event_mgr_t *p_manager);
+
+static OPJ_BOOL opj_j2k_is_imf_compliant(opj_cparameters_t *parameters,
+ opj_image_t *image,
+ opj_event_mgr_t *p_manager);
+
/**
* Checks for invalid number of tile-parts in SOT marker (TPsot==TNsot). See issue 254.
*
{J2K_MS_COM, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_com},
{J2K_MS_MCT, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_mct},
{J2K_MS_CBD, J2K_STATE_MH, opj_j2k_read_cbd},
+ {J2K_MS_CAP, J2K_STATE_MH, opj_j2k_read_cap},
+ {J2K_MS_CPF, J2K_STATE_MH, opj_j2k_read_cpf},
{J2K_MS_MCC, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_mcc},
{J2K_MS_MCO, J2K_STATE_MH | J2K_STATE_TPH, opj_j2k_read_mco},
#ifdef USE_JPWL
-#ifdef TODO_MS /* remove these functions which are not commpatible with the v2 API */
+#ifdef TODO_MS /* remove these functions which are not compatible with the v2 API */
{J2K_MS_EPC, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epc},
{J2K_MS_EPB, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_epb},
{J2K_MS_ESD, J2K_STATE_MH | J2K_STATE_TPH, j2k_read_esd},
}
static OPJ_BOOL opj_j2k_check_poc_val(const opj_poc_t *p_pocs,
+ OPJ_UINT32 tileno,
OPJ_UINT32 p_nb_pocs,
OPJ_UINT32 p_nb_resolutions,
OPJ_UINT32 p_num_comps,
OPJ_UINT32 step_r = p_num_comps * step_c;
OPJ_UINT32 step_l = p_nb_resolutions * step_r;
OPJ_BOOL loss = OPJ_FALSE;
- OPJ_UINT32 layno0 = 0;
+
+ assert(p_nb_pocs > 0);
packet_array = (OPJ_UINT32*) opj_calloc(step_l * p_num_layers,
sizeof(OPJ_UINT32));
return OPJ_FALSE;
}
- if (p_nb_pocs == 0) {
- opj_free(packet_array);
- return OPJ_TRUE;
- }
-
- index = step_r * p_pocs->resno0;
- /* take each resolution for each poc */
- for (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) {
- OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c;
-
- /* take each comp of each resolution for each poc */
- for (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) {
- OPJ_UINT32 comp_index = res_index + layno0 * step_l;
-
- /* and finally take each layer of each res of ... */
- for (layno = layno0; layno < p_pocs->layno1 ; ++layno) {
- /*index = step_r * resno + step_c * compno + step_l * layno;*/
- packet_array[comp_index] = 1;
- comp_index += step_l;
- }
-
- res_index += step_c;
- }
-
- index += step_r;
- }
- ++p_pocs;
-
- /* iterate through all the pocs */
- for (i = 1; i < p_nb_pocs ; ++i) {
- OPJ_UINT32 l_last_layno1 = (p_pocs - 1)->layno1 ;
+ /* iterate through all the pocs that match our tile of interest. */
+ for (i = 0; i < p_nb_pocs; ++i) {
+ const opj_poc_t *poc = &p_pocs[i];
+ if (tileno + 1 == poc->tile) {
+ index = step_r * poc->resno0;
- layno0 = (p_pocs->layno1 > l_last_layno1) ? l_last_layno1 : 0;
- index = step_r * p_pocs->resno0;
+ /* take each resolution for each poc */
+ for (resno = poc->resno0 ;
+ resno < opj_uint_min(poc->resno1, p_nb_resolutions); ++resno) {
+ OPJ_UINT32 res_index = index + poc->compno0 * step_c;
- /* take each resolution for each poc */
- for (resno = p_pocs->resno0 ; resno < p_pocs->resno1 ; ++resno) {
- OPJ_UINT32 res_index = index + p_pocs->compno0 * step_c;
+ /* take each comp of each resolution for each poc */
+ for (compno = poc->compno0 ;
+ compno < opj_uint_min(poc->compno1, p_num_comps); ++compno) {
+ /* The layer index always starts at zero for every progression. */
+ const OPJ_UINT32 layno0 = 0;
+ OPJ_UINT32 comp_index = res_index + layno0 * step_l;
- /* take each comp of each resolution for each poc */
- for (compno = p_pocs->compno0 ; compno < p_pocs->compno1 ; ++compno) {
- OPJ_UINT32 comp_index = res_index + layno0 * step_l;
+ /* and finally take each layer of each res of ... */
+ for (layno = layno0; layno < opj_uint_min(poc->layno1, p_num_layers);
+ ++layno) {
+ packet_array[comp_index] = 1;
+ comp_index += step_l;
+ }
- /* and finally take each layer of each res of ... */
- for (layno = layno0; layno < p_pocs->layno1 ; ++layno) {
- /*index = step_r * resno + step_c * compno + step_l * layno;*/
- packet_array[comp_index] = 1;
- comp_index += step_l;
+ res_index += step_c;
}
- res_index += step_c;
+ index += step_r;
}
-
- index += step_r;
}
-
- ++p_pocs;
}
index = 0;
for (resno = 0; resno < p_nb_resolutions; ++resno) {
for (compno = 0; compno < p_num_comps; ++compno) {
loss |= (packet_array[index] != 1);
- /*index = step_r * resno + step_c * compno + step_l * layno;*/
+#ifdef DEBUG_VERBOSE
+ if (packet_array[index] != 1) {
+ fprintf(stderr,
+ "Missing packet in POC: layno=%d resno=%d compno=%d\n",
+ layno, resno, compno);
+ }
+#endif
index += step_c;
}
}
tpnum *= l_current_poc->layE;
break;
}
- /* whould we split here ? */
+ /* would we split here ? */
if (cp->m_specific_param.m_enc.m_tp_flag == prog[i]) {
cp->m_specific_param.m_enc.m_tp_pos = i;
break;
/* FIXME move it in a index structure included in p_j2k*/
p_j2k->cstr_index->main_head_start = opj_stream_tell(p_stream) - 2;
- opj_event_msg(p_manager, EVT_INFO, "Start to read j2k main header (%d).\n",
+ opj_event_msg(p_manager, EVT_INFO,
+ "Start to read j2k main header (%" PRId64 ").\n",
p_j2k->cstr_index->main_head_start);
/* Add the marker to the codestream index*/
}
/**
- * Reads a COD marker (Coding Styke defaults)
+ * Reads a COD marker (Coding style defaults)
* @param p_header_data the data contained in the COD box.
* @param p_j2k the jpeg2000 codec.
* @param p_header_size the size of the data contained in the COD marker.
&l_cp->tcps[p_j2k->m_current_tile_number] :
p_j2k->m_specific_param.m_decoder.m_default_tcp;
+#if 0
+ /* This check was added per https://github.com/uclouvain/openjpeg/commit/daed8cc9195555e101ab708a501af2dfe6d5e001 */
+ /* but this is no longer necessary to handle issue476.jp2 */
+ /* and this actually cause issues on legit files. See https://github.com/uclouvain/openjpeg/issues/1043 */
/* Only one COD per tile */
if (l_tcp->cod) {
opj_event_msg(p_manager, EVT_ERROR,
"COD marker already read. No more than one COD marker per tile.\n");
return OPJ_FALSE;
}
+#endif
l_tcp->cod = 1;
/* Make sure room is sufficient */
opj_read_bytes(p_header_data, &l_tcp->mct, 1); /* SGcod (C) */
++p_header_data;
+ if (l_tcp->mct > 1) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid multiple component transformation\n");
+ return OPJ_FALSE;
+ }
+
p_header_size -= 5;
for (i = 0; i < l_image->numcomps; ++i) {
l_tcp->tccps[i].csty = l_tcp->csty & J2K_CCP_CSTY_PRT;
l_nb_bytes += opj_j2k_get_max_poc_size(p_j2k);
+ if (p_j2k->m_specific_param.m_encoder.m_PLT) {
+ /* Reserve space for PLT markers */
+
+ OPJ_UINT32 i;
+ const opj_cp_t * l_cp = &(p_j2k->m_cp);
+ OPJ_UINT32 l_max_packet_count = 0;
+ for (i = 0; i < l_cp->th * l_cp->tw; ++i) {
+ l_max_packet_count = opj_uint_max(l_max_packet_count,
+ opj_get_encoding_packet_count(p_j2k->m_private_image, l_cp, i));
+ }
+ /* Minimum 6 bytes per PLT marker, and at a minimum (taking a pessimistic */
+ /* estimate of 4 bytes for a packet size), one can write */
+ /* (65536-6) / 4 = 16382 paquet sizes per PLT marker */
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT =
+ 6 * opj_uint_ceildiv(l_max_packet_count, 16382);
+ /* Maximum 5 bytes per packet to encode a full UINT32 */
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT +=
+ l_nb_bytes += 5 * l_max_packet_count;
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT += 1;
+ l_nb_bytes += p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT;
+ }
+
/*** DEVELOPER CORNER, Add room for your headers ***/
return l_nb_bytes;
l_old_poc_nb = l_tcp->POC ? l_tcp->numpocs + 1 : 0;
l_current_poc_nb += l_old_poc_nb;
- if (l_current_poc_nb >= 32) {
+ if (l_current_poc_nb >= J2K_MAX_POCS) {
opj_event_msg(p_manager, EVT_ERROR, "Too many POCs %d\n", l_current_poc_nb);
return OPJ_FALSE;
}
- assert(l_current_poc_nb < 32);
/* now poc is in use.*/
l_tcp->POC = 1;
/* preconditions */
assert(p_tcp != 00);
assert(p_manager != 00);
- assert(p_tcp->ppt_buffer == NULL);
+
+ if (p_tcp->ppt_buffer != NULL) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "opj_j2k_merge_ppt() has already been called\n");
+ return OPJ_FALSE;
+ }
if (p_tcp->ppt == 0U) {
return OPJ_TRUE;
{
OPJ_BYTE * l_current_data = 00;
OPJ_UINT32 l_tlm_size;
+ OPJ_UINT32 size_per_tile_part;
/* preconditions */
assert(p_j2k != 00);
assert(p_manager != 00);
assert(p_stream != 00);
- l_tlm_size = 6 + (5 * p_j2k->m_specific_param.m_encoder.m_total_tile_parts);
+ /* 10921 = (65535 - header_size) / size_per_tile_part where */
+ /* header_size = 4 and size_per_tile_part = 6 */
+ if (p_j2k->m_specific_param.m_encoder.m_total_tile_parts > 10921) {
+ /* We could do more but it would require writing several TLM markers */
+ opj_event_msg(p_manager, EVT_ERROR,
+ "A maximum of 10921 tile-parts are supported currently "
+ "when writing TLM marker\n");
+ return OPJ_FALSE;
+ }
+
+ if (p_j2k->m_specific_param.m_encoder.m_total_tile_parts <= 255) {
+ size_per_tile_part = 5;
+ p_j2k->m_specific_param.m_encoder.m_Ttlmi_is_byte = OPJ_TRUE;
+ } else {
+ size_per_tile_part = 6;
+ p_j2k->m_specific_param.m_encoder.m_Ttlmi_is_byte = OPJ_FALSE;
+ }
+
+ l_tlm_size = 2 + 4 + (size_per_tile_part *
+ p_j2k->m_specific_param.m_encoder.m_total_tile_parts);
if (l_tlm_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) {
OPJ_BYTE *new_header_tile_data = (OPJ_BYTE *) opj_realloc(
p_j2k->m_specific_param.m_encoder.m_header_tile_data = new_header_tile_data;
p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = l_tlm_size;
}
+ memset(p_j2k->m_specific_param.m_encoder.m_header_tile_data, 0, l_tlm_size);
l_current_data = p_j2k->m_specific_param.m_encoder.m_header_tile_data;
1); /* Ztlm=0*/
++l_current_data;
- opj_write_bytes(l_current_data, 0x50,
- 1); /* Stlm ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */
+ /* Stlm 0x50= ST=1(8bits-255 tiles max),SP=1(Ptlm=32bits) */
+ /* Stlm 0x60= ST=2(16bits-65535 tiles max),SP=1(Ptlm=32bits) */
+ opj_write_bytes(l_current_data,
+ size_per_tile_part == 5 ? 0x50 : 0x60,
+ 1);
++l_current_data;
- /* do nothing on the 5 * l_j2k->m_specific_param.m_encoder.m_total_tile_parts remaining data */
+ /* do nothing on the size_per_tile_part * l_j2k->m_specific_param.m_encoder.m_total_tile_parts remaining data */
if (opj_stream_write_data(p_stream,
p_j2k->m_specific_param.m_encoder.m_header_tile_data, l_tlm_size,
p_manager) != l_tlm_size) {
static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
OPJ_UINT32 * p_data_written,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager
OPJ_UNUSED(p_stream);
- if (p_total_data_size < 12) {
+ if (total_data_size < 12) {
opj_event_msg(p_manager, EVT_ERROR,
"Not enough bytes in output buffer to write SOT marker\n");
return OPJ_FALSE;
opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n");
return OPJ_FALSE;
}
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "SOT %d %d %d %d\n",
+ p_j2k->m_current_tile_number, l_tot_len, l_current_part, l_num_parts);
+#endif
l_cp = &(p_j2k->m_cp);
l_tile_x = p_j2k->m_current_tile_number % l_cp->tw;
l_tile_y = p_j2k->m_current_tile_number / l_cp->tw;
- /* Fixes issue with id_000020,sig_06,src_001958,op_flip4,pos_149 */
- /* of https://github.com/uclouvain/openjpeg/issues/939 */
- /* We must avoid reading twice the same tile part number for a given tile */
- /* so as to avoid various issues, like opj_j2k_merge_ppt being called */
- /* several times. */
- /* ISO 15444-1 A.4.2 Start of tile-part (SOT) mandates that tile parts */
- /* should appear in increasing order. */
- if (l_tcp->m_current_tile_part_number + 1 != (OPJ_INT32)l_current_part) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid tile part index for tile number %d. "
- "Got %d, expected %d\n",
- p_j2k->m_current_tile_number,
- l_current_part,
- l_tcp->m_current_tile_part_number + 1);
- return OPJ_FALSE;
+ if (p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec < 0 ||
+ p_j2k->m_current_tile_number == (OPJ_UINT32)
+ p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec) {
+ /* Do only this check if we decode all tile part headers, or if */
+ /* we decode one precise tile. Otherwise the m_current_tile_part_number */
+ /* might not be valid */
+ /* Fixes issue with id_000020,sig_06,src_001958,op_flip4,pos_149 */
+ /* of https://github.com/uclouvain/openjpeg/issues/939 */
+ /* We must avoid reading twice the same tile part number for a given tile */
+ /* so as to avoid various issues, like opj_j2k_merge_ppt being called */
+ /* several times. */
+ /* ISO 15444-1 A.4.2 Start of tile-part (SOT) mandates that tile parts */
+ /* should appear in increasing order. */
+ if (l_tcp->m_current_tile_part_number + 1 != (OPJ_INT32)l_current_part) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid tile part index for tile number %d. "
+ "Got %d, expected %d\n",
+ p_j2k->m_current_tile_number,
+ l_current_part,
+ l_tcp->m_current_tile_part_number + 1);
+ return OPJ_FALSE;
+ }
}
- ++ l_tcp->m_current_tile_part_number;
+
+ l_tcp->m_current_tile_part_number = (OPJ_INT32) l_current_part;
#ifdef USE_JPWL
if (l_cp->correct) {
return OPJ_TRUE;
}
+/**
+ * Write one or more PLT markers in the provided buffer
+ */
+static OPJ_BOOL opj_j2k_write_plt_in_memory(opj_j2k_t *p_j2k,
+ opj_tcd_marker_info_t* marker_info,
+ OPJ_BYTE * p_data,
+ OPJ_UINT32 * p_data_written,
+ opj_event_mgr_t * p_manager)
+{
+ OPJ_BYTE Zplt = 0;
+ OPJ_UINT16 Lplt;
+ OPJ_BYTE* p_data_start = p_data;
+ OPJ_BYTE* p_data_Lplt = p_data + 2;
+ OPJ_UINT32 i;
+
+ OPJ_UNUSED(p_j2k);
+
+ opj_write_bytes(p_data, J2K_MS_PLT, 2);
+ p_data += 2;
+
+ /* Reserve space for Lplt */
+ p_data += 2;
+
+ opj_write_bytes(p_data, Zplt, 1);
+ p_data += 1;
+
+ Lplt = 3;
+
+ for (i = 0; i < marker_info->packet_count; i++) {
+ OPJ_BYTE var_bytes[5];
+ OPJ_UINT8 var_bytes_size = 0;
+ OPJ_UINT32 packet_size = marker_info->p_packet_size[i];
+
+ /* Packet size written in variable-length way, starting with LSB */
+ var_bytes[var_bytes_size] = (OPJ_BYTE)(packet_size & 0x7f);
+ var_bytes_size ++;
+ packet_size >>= 7;
+ while (packet_size > 0) {
+ var_bytes[var_bytes_size] = (OPJ_BYTE)((packet_size & 0x7f) | 0x80);
+ var_bytes_size ++;
+ packet_size >>= 7;
+ }
+
+ /* Check if that can fit in the current PLT marker. If not, finish */
+ /* current one, and start a new one */
+ if (Lplt + var_bytes_size > 65535) {
+ if (Zplt == 255) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "More than 255 PLT markers would be needed for current tile-part !\n");
+ return OPJ_FALSE;
+ }
+
+ /* Patch Lplt */
+ opj_write_bytes(p_data_Lplt, Lplt, 2);
+
+ /* Start new segment */
+ opj_write_bytes(p_data, J2K_MS_PLT, 2);
+ p_data += 2;
+
+ /* Reserve space for Lplt */
+ p_data_Lplt = p_data;
+ p_data += 2;
+
+ Zplt ++;
+ opj_write_bytes(p_data, Zplt, 1);
+ p_data += 1;
+
+ Lplt = 3;
+ }
+
+ Lplt = (OPJ_UINT16)(Lplt + var_bytes_size);
+
+ /* Serialize variable-length packet size, starting with MSB */
+ for (; var_bytes_size > 0; --var_bytes_size) {
+ opj_write_bytes(p_data, var_bytes[var_bytes_size - 1], 1);
+ p_data += 1;
+ }
+ }
+
+ *p_data_written = (OPJ_UINT32)(p_data - p_data_start);
+
+ /* Patch Lplt */
+ opj_write_bytes(p_data_Lplt, Lplt, 2);
+
+ return OPJ_TRUE;
+}
+
static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k,
opj_tcd_t * p_tile_coder,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager
)
{
opj_codestream_info_t *l_cstr_info = 00;
OPJ_UINT32 l_remaining_data;
+ opj_tcd_marker_info_t* marker_info = NULL;
/* preconditions */
assert(p_j2k != 00);
OPJ_UNUSED(p_stream);
- if (p_total_data_size < 4) {
+ if (total_data_size < 4) {
opj_event_msg(p_manager, EVT_ERROR,
"Not enough bytes in output buffer to write SOD marker\n");
return OPJ_FALSE;
opj_write_bytes(p_data, J2K_MS_SOD,
2); /* SOD */
- p_data += 2;
/* make room for the EOF marker */
- l_remaining_data = p_total_data_size - 4;
+ l_remaining_data = total_data_size - 4;
/* update tile coder */
p_tile_coder->tp_num =
if (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) {
p_tile_coder->tcd_image->tiles->packno = 0;
+#ifdef deadcode
if (l_cstr_info) {
l_cstr_info->packno = 0;
}
+#endif
}
*p_data_written = 0;
- if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data,
+ if (p_j2k->m_specific_param.m_encoder.m_PLT) {
+ marker_info = opj_tcd_marker_info_create(
+ p_j2k->m_specific_param.m_encoder.m_PLT);
+ if (marker_info == NULL) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Cannot encode tile: opj_tcd_marker_info_create() failed\n");
+ return OPJ_FALSE;
+ }
+ }
+
+ if (l_remaining_data <
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Not enough bytes in output buffer to write SOD marker\n");
+ opj_tcd_marker_info_destroy(marker_info);
+ return OPJ_FALSE;
+ }
+ l_remaining_data -= p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT;
+
+ if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number,
+ p_data + 2,
p_data_written, l_remaining_data, l_cstr_info,
+ marker_info,
p_manager)) {
opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n");
+ opj_tcd_marker_info_destroy(marker_info);
return OPJ_FALSE;
}
+ /* For SOD */
*p_data_written += 2;
+ if (p_j2k->m_specific_param.m_encoder.m_PLT) {
+ OPJ_UINT32 l_data_written_PLT = 0;
+ OPJ_BYTE* p_PLT_buffer = (OPJ_BYTE*)opj_malloc(
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT);
+ if (!p_PLT_buffer) {
+ opj_event_msg(p_manager, EVT_ERROR, "Cannot allocate memory\n");
+ opj_tcd_marker_info_destroy(marker_info);
+ return OPJ_FALSE;
+ }
+ if (!opj_j2k_write_plt_in_memory(p_j2k,
+ marker_info,
+ p_PLT_buffer,
+ &l_data_written_PLT,
+ p_manager)) {
+ opj_tcd_marker_info_destroy(marker_info);
+ opj_free(p_PLT_buffer);
+ return OPJ_FALSE;
+ }
+
+ assert(l_data_written_PLT <=
+ p_j2k->m_specific_param.m_encoder.m_reserved_bytes_for_PLT);
+
+ /* Move PLT marker(s) before SOD */
+ memmove(p_data + l_data_written_PLT, p_data, *p_data_written);
+ memcpy(p_data, p_PLT_buffer, l_data_written_PLT);
+ opj_free(p_PLT_buffer);
+ *p_data_written += l_data_written_PLT;
+ }
+
+ opj_tcd_marker_info_destroy(marker_info);
+
return OPJ_TRUE;
}
OPJ_FLOAT32 * l_rates = 0;
OPJ_FLOAT32 l_sot_remove;
OPJ_UINT32 l_bits_empty, l_size_pixel;
- OPJ_UINT32 l_tile_size = 0;
+ OPJ_UINT64 l_tile_size = 0;
OPJ_UINT32 l_last_res;
OPJ_FLOAT32(* l_tp_stride_func)(opj_tcp_t *) = 00;
l_rates = l_tcp->rates;
/* Modification of the RATE >> */
- if (*l_rates > 0.0f) {
- *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
- (OPJ_UINT32)(l_y1 - l_y0)))
- /
- ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
- )
- -
- l_offset;
- }
-
- ++l_rates;
-
- for (k = 1; k < l_tcp->numlayers; ++k) {
+ for (k = 0; k < l_tcp->numlayers; ++k) {
if (*l_rates > 0.0f) {
- *l_rates = (((OPJ_FLOAT32)(l_size_pixel * (OPJ_UINT32)(l_x1 - l_x0) *
- (OPJ_UINT32)(l_y1 - l_y0)))
- /
- ((*l_rates) * (OPJ_FLOAT32)l_bits_empty)
- )
+ *l_rates = (OPJ_FLOAT32)(((OPJ_FLOAT64)l_size_pixel * (OPJ_UINT32)(
+ l_x1 - l_x0) *
+ (OPJ_UINT32)(l_y1 - l_y0))
+ / ((*l_rates) * (OPJ_FLOAT32)l_bits_empty))
-
l_offset;
}
l_tile_size = 0;
for (i = 0; i < l_image->numcomps; ++i) {
- l_tile_size += (opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
- *
- opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
- *
- l_img_comp->prec
- );
+ l_tile_size += (OPJ_UINT64)opj_uint_ceildiv(l_cp->tdx, l_img_comp->dx)
+ *
+ opj_uint_ceildiv(l_cp->tdy, l_img_comp->dy)
+ *
+ l_img_comp->prec;
++l_img_comp;
}
/* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
/* TODO revise this to take into account the overhead linked to the */
/* number of packets and number of code blocks in packets */
- l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
+ l_tile_size = (OPJ_UINT64)((double)l_tile_size * 1.4 / 8);
/* Arbitrary amount to make the following work: */
/* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */
l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
- p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = l_tile_size;
+ if (l_tile_size > UINT_MAX) {
+ l_tile_size = UINT_MAX;
+ }
+
+ p_j2k->m_specific_param.m_encoder.m_encoded_tile_size = (OPJ_UINT32)l_tile_size;
p_j2k->m_specific_param.m_encoder.m_encoded_tile_data =
(OPJ_BYTE *) opj_malloc(p_j2k->m_specific_param.m_encoder.m_encoded_tile_size);
if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data == 00) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Not enough memory to allocate m_encoded_tile_data. %u MB required\n",
+ (OPJ_UINT32)(l_tile_size / 1024 / 1024));
return OPJ_FALSE;
}
- if (OPJ_IS_CINEMA(l_cp->rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer =
- (OPJ_BYTE *) opj_malloc(5 *
+ (OPJ_BYTE *) opj_malloc(6 *
p_j2k->m_specific_param.m_encoder.m_total_tile_parts);
if (! p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) {
return OPJ_FALSE;
return OPJ_TRUE;
}
+/**
+ * Reads a CAP marker (extended capabilities definition). Empty implementation.
+ * Found in HTJ2K files.
+ *
+ * @param p_header_data the data contained in the CAP box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the CAP marker.
+ * @param p_manager the user event manager.
+*/
+static OPJ_BOOL opj_j2k_read_cap(opj_j2k_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ opj_event_mgr_t * p_manager
+ )
+{
+ /* preconditions */
+ assert(p_header_data != 00);
+ assert(p_j2k != 00);
+ assert(p_manager != 00);
+
+ (void)p_j2k;
+ (void)p_header_data;
+ (void)p_header_size;
+ (void)p_manager;
+
+ return OPJ_TRUE;
+}
+
+/**
+ * Reads a CPF marker (corresponding profile). Empty implementation. Found in HTJ2K files
+ * @param p_header_data the data contained in the CPF box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the CPF marker.
+ * @param p_manager the user event manager.
+*/
+static OPJ_BOOL opj_j2k_read_cpf(opj_j2k_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ opj_event_mgr_t * p_manager
+ )
+{
+ /* preconditions */
+ assert(p_header_data != 00);
+ assert(p_j2k != 00);
+ assert(p_manager != 00);
+
+ (void)p_j2k;
+ (void)p_header_data;
+ (void)p_header_size;
+ (void)p_manager;
+
+ return OPJ_TRUE;
+}
+
/* ----------------------------------------------------------------------- */
/* J2K / JPT decoder interface */
/* ----------------------------------------------------------------------- */
OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads)
{
- if (opj_has_thread_support()) {
+ /* Currently we pass the thread-pool to the tcd, so we cannot re-set it */
+ /* afterwards */
+ if (opj_has_thread_support() && j2k->m_tcd == NULL) {
opj_thread_pool_destroy(j2k->m_tp);
j2k->m_tp = NULL;
if (num_threads <= (OPJ_UINT32)INT_MAX) {
static int opj_j2k_get_default_thread_count()
{
- const char* num_threads = getenv("OPJ_NUM_THREADS");
- if (num_threads == NULL || !opj_has_thread_support()) {
+ const char* num_threads_str = getenv("OPJ_NUM_THREADS");
+ int num_cpus;
+ int num_threads;
+
+ if (num_threads_str == NULL || !opj_has_thread_support()) {
return 0;
}
- if (strcmp(num_threads, "ALL_CPUS") == 0) {
- return opj_get_num_cpus();
+ num_cpus = opj_get_num_cpus();
+ if (strcmp(num_threads_str, "ALL_CPUS") == 0) {
+ return num_cpus;
+ }
+ if (num_cpus == 0) {
+ num_cpus = 32;
+ }
+ num_threads = atoi(num_threads_str);
+ if (num_threads < 0) {
+ num_threads = 0;
+ } else if (num_threads > 2 * num_cpus) {
+ num_threads = 2 * num_cpus;
}
- return atoi(num_threads);
+ return num_threads;
}
/* ----------------------------------------------------------------------- */
}
/* Precincts */
- parameters->csty |= 0x01;
+ parameters->csty |= J2K_CP_CSTY_PRT;
if (parameters->numresolution == 1) {
parameters->res_spec = 1;
parameters->prcw_init[0] = 128;
/* Bitdepth */
for (i = 0; i < image->numcomps; i++) {
- if ((image->comps[i].bpp != 12) | (image->comps[i].sgnd)) {
+ if ((image->comps[i].prec != 12) | (image->comps[i].sgnd)) {
char signed_str[] = "signed";
char unsigned_str[] = "unsigned";
char *tmp_str = image->comps[i].sgnd ? signed_str : unsigned_str;
"Precision of each component shall be 12 bits unsigned"
"-> At least component %d of input image (%d bits, %s) is not compliant\n"
"-> Non-profile-3 codestream will be generated\n",
- i, image->comps[i].bpp, tmp_str);
+ i, image->comps[i].prec, tmp_str);
return OPJ_FALSE;
}
}
return OPJ_TRUE;
}
-OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
- opj_cparameters_t *parameters,
- opj_image_t *image,
- opj_event_mgr_t * p_manager)
+static int opj_j2k_get_imf_max_NL(opj_cparameters_t *parameters,
+ opj_image_t *image)
{
- OPJ_UINT32 i, j, tileno, numpocs_tile;
- opj_cp_t *cp = 00;
- OPJ_UINT32 cblkw, cblkh;
-
- if (!p_j2k || !parameters || ! image) {
- return OPJ_FALSE;
- }
-
- if ((parameters->numresolution <= 0) ||
- (parameters->numresolution > OPJ_J2K_MAXRLVLS)) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid number of resolutions : %d not in range [1,%d]\n",
- parameters->numresolution, OPJ_J2K_MAXRLVLS);
- return OPJ_FALSE;
+ /* Decomposition levels */
+ const OPJ_UINT16 rsiz = parameters->rsiz;
+ const OPJ_UINT16 profile = OPJ_GET_IMF_PROFILE(rsiz);
+ const OPJ_UINT32 XTsiz = parameters->tile_size_on ? (OPJ_UINT32)
+ parameters->cp_tdx : image->x1;
+ switch (profile) {
+ case OPJ_PROFILE_IMF_2K:
+ return 5;
+ case OPJ_PROFILE_IMF_4K:
+ return 6;
+ case OPJ_PROFILE_IMF_8K:
+ return 7;
+ case OPJ_PROFILE_IMF_2K_R: {
+ if (XTsiz >= 2048) {
+ return 5;
+ } else if (XTsiz >= 1024) {
+ return 4;
+ }
+ break;
}
-
- if (parameters->cblockw_init < 4 || parameters->cblockw_init > 1024) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
- parameters->cblockw_init);
- return OPJ_FALSE;
+ case OPJ_PROFILE_IMF_4K_R: {
+ if (XTsiz >= 4096) {
+ return 6;
+ } else if (XTsiz >= 2048) {
+ return 5;
+ } else if (XTsiz >= 1024) {
+ return 4;
+ }
+ break;
}
- if (parameters->cblockh_init < 4 || parameters->cblockh_init > 1024) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid value for cblockh_init: %d not a power of 2 not in range [4,1024]\n",
- parameters->cblockh_init);
- return OPJ_FALSE;
+ case OPJ_PROFILE_IMF_8K_R: {
+ if (XTsiz >= 8192) {
+ return 7;
+ } else if (XTsiz >= 4096) {
+ return 6;
+ } else if (XTsiz >= 2048) {
+ return 5;
+ } else if (XTsiz >= 1024) {
+ return 4;
+ }
+ break;
}
- if (parameters->cblockw_init * parameters->cblockh_init > 4096) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid value for cblockw_init * cblockh_init: should be <= 4096\n");
- return OPJ_FALSE;
+ default:
+ break;
}
- cblkw = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockw_init);
- cblkh = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockh_init);
- if (parameters->cblockw_init != (1 << cblkw)) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
- parameters->cblockw_init);
- return OPJ_FALSE;
+ return -1;
+}
+
+static void opj_j2k_set_imf_parameters(opj_cparameters_t *parameters,
+ opj_image_t *image, opj_event_mgr_t *p_manager)
+{
+ const OPJ_UINT16 rsiz = parameters->rsiz;
+ const OPJ_UINT16 profile = OPJ_GET_IMF_PROFILE(rsiz);
+
+ OPJ_UNUSED(p_manager);
+
+ /* Override defaults set by opj_set_default_encoder_parameters */
+ if (parameters->cblockw_init == OPJ_COMP_PARAM_DEFAULT_CBLOCKW &&
+ parameters->cblockh_init == OPJ_COMP_PARAM_DEFAULT_CBLOCKH) {
+ parameters->cblockw_init = 32;
+ parameters->cblockh_init = 32;
}
- if (parameters->cblockh_init != (1 << cblkh)) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
- parameters->cblockh_init);
- return OPJ_FALSE;
+
+ /* One tile part for each component */
+ parameters->tp_flag = 'C';
+ parameters->tp_on = 1;
+
+ if (parameters->prog_order == OPJ_COMP_PARAM_DEFAULT_PROG_ORDER) {
+ parameters->prog_order = OPJ_CPRL;
}
- /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */
- cp = &(p_j2k->m_cp);
+ if (profile == OPJ_PROFILE_IMF_2K ||
+ profile == OPJ_PROFILE_IMF_4K ||
+ profile == OPJ_PROFILE_IMF_8K) {
+ /* 9-7 transform */
+ parameters->irreversible = 1;
+ }
- /* set default values for cp */
- cp->tw = 1;
- cp->th = 1;
+ /* Adjust the number of resolutions if set to its defaults */
+ if (parameters->numresolution == OPJ_COMP_PARAM_DEFAULT_NUMRESOLUTION &&
+ image->x0 == 0 &&
+ image->y0 == 0) {
+ const int max_NL = opj_j2k_get_imf_max_NL(parameters, image);
+ if (max_NL >= 0 && parameters->numresolution > max_NL) {
+ parameters->numresolution = max_NL + 1;
+ }
- /* FIXME ADE: to be removed once deprecated cp_cinema and cp_rsiz have been removed */
+ /* Note: below is generic logic */
+ if (!parameters->tile_size_on) {
+ while (parameters->numresolution > 0) {
+ if (image->x1 < (1U << ((OPJ_UINT32)parameters->numresolution - 1U))) {
+ parameters->numresolution --;
+ continue;
+ }
+ if (image->y1 < (1U << ((OPJ_UINT32)parameters->numresolution - 1U))) {
+ parameters->numresolution --;
+ continue;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Set defaults precincts */
+ if (parameters->csty == 0) {
+ parameters->csty |= J2K_CP_CSTY_PRT;
+ if (parameters->numresolution == 1) {
+ parameters->res_spec = 1;
+ parameters->prcw_init[0] = 128;
+ parameters->prch_init[0] = 128;
+ } else {
+ int i;
+ parameters->res_spec = parameters->numresolution - 1;
+ for (i = 0; i < parameters->res_spec; i++) {
+ parameters->prcw_init[i] = 256;
+ parameters->prch_init[i] = 256;
+ }
+ }
+ }
+}
+
+/* Table A.53 from JPEG2000 standard */
+static const OPJ_UINT16 tabMaxSubLevelFromMainLevel[] = {
+ 15, /* unspecified */
+ 1,
+ 1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+};
+
+static OPJ_BOOL opj_j2k_is_imf_compliant(opj_cparameters_t *parameters,
+ opj_image_t *image,
+ opj_event_mgr_t *p_manager)
+{
+ OPJ_UINT32 i;
+ const OPJ_UINT16 rsiz = parameters->rsiz;
+ const OPJ_UINT16 profile = OPJ_GET_IMF_PROFILE(rsiz);
+ const OPJ_UINT16 mainlevel = OPJ_GET_IMF_MAINLEVEL(rsiz);
+ const OPJ_UINT16 sublevel = OPJ_GET_IMF_SUBLEVEL(rsiz);
+ const int NL = parameters->numresolution - 1;
+ const OPJ_UINT32 XTsiz = parameters->tile_size_on ? (OPJ_UINT32)
+ parameters->cp_tdx : image->x1;
+ OPJ_BOOL ret = OPJ_TRUE;
+
+ /* Validate mainlevel */
+ if (mainlevel > OPJ_IMF_MAINLEVEL_MAX) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile require mainlevel <= 11.\n"
+ "-> %d is thus not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ mainlevel);
+ ret = OPJ_FALSE;
+ } else {
+ /* Validate sublevel */
+ assert(sizeof(tabMaxSubLevelFromMainLevel) ==
+ (OPJ_IMF_MAINLEVEL_MAX + 1) * sizeof(tabMaxSubLevelFromMainLevel[0]));
+ if (sublevel > tabMaxSubLevelFromMainLevel[mainlevel]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile require sublevel <= %d for mainlevel = %d.\n"
+ "-> %d is thus not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ tabMaxSubLevelFromMainLevel[mainlevel],
+ mainlevel,
+ sublevel);
+ ret = OPJ_FALSE;
+ }
+ }
+
+ /* Number of components */
+ if (image->numcomps > 3) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require at most 3 components.\n"
+ "-> Number of components of input image (%d) is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->numcomps);
+ ret = OPJ_FALSE;
+ }
+
+ if (image->x0 != 0 || image->y0 != 0) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require image origin to be at 0,0.\n"
+ "-> %d,%d is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->x0, image->y0 != 0);
+ ret = OPJ_FALSE;
+ }
+
+ if (parameters->cp_tx0 != 0 || parameters->cp_ty0 != 0) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require tile origin to be at 0,0.\n"
+ "-> %d,%d is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->cp_tx0, parameters->cp_ty0);
+ ret = OPJ_FALSE;
+ }
+
+ if (parameters->tile_size_on) {
+ if (profile == OPJ_PROFILE_IMF_2K ||
+ profile == OPJ_PROFILE_IMF_4K ||
+ profile == OPJ_PROFILE_IMF_8K) {
+ if ((OPJ_UINT32)parameters->cp_tdx < image->x1 ||
+ (OPJ_UINT32)parameters->cp_tdy < image->y1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K/4K/8K single tile profiles require tile to be greater or equal to image size.\n"
+ "-> %d,%d is lesser than %d,%d\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->cp_tdx,
+ parameters->cp_tdy,
+ image->x1,
+ image->y1);
+ ret = OPJ_FALSE;
+ }
+ } else {
+ if ((OPJ_UINT32)parameters->cp_tdx >= image->x1 &&
+ (OPJ_UINT32)parameters->cp_tdy >= image->y1) {
+ /* ok */
+ } else if (parameters->cp_tdx == 1024 &&
+ parameters->cp_tdy == 1024) {
+ /* ok */
+ } else if (parameters->cp_tdx == 2048 &&
+ parameters->cp_tdy == 2048 &&
+ (profile == OPJ_PROFILE_IMF_4K ||
+ profile == OPJ_PROFILE_IMF_8K)) {
+ /* ok */
+ } else if (parameters->cp_tdx == 4096 &&
+ parameters->cp_tdy == 4096 &&
+ profile == OPJ_PROFILE_IMF_8K) {
+ /* ok */
+ } else {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K_R/4K_R/8K_R single/multiple tile profiles "
+ "require tile to be greater or equal to image size,\n"
+ "or to be (1024,1024), or (2048,2048) for 4K_R/8K_R "
+ "or (4096,4096) for 8K_R.\n"
+ "-> %d,%d is non conformant\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->cp_tdx,
+ parameters->cp_tdy);
+ ret = OPJ_FALSE;
+ }
+ }
+ }
+
+ /* Bitdepth */
+ for (i = 0; i < image->numcomps; i++) {
+ if (!(image->comps[i].prec >= 8 && image->comps[i].prec <= 16) ||
+ (image->comps[i].sgnd)) {
+ char signed_str[] = "signed";
+ char unsigned_str[] = "unsigned";
+ char *tmp_str = image->comps[i].sgnd ? signed_str : unsigned_str;
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require precision of each component to b in [8-16] bits unsigned"
+ "-> At least component %d of input image (%d bits, %s) is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ i, image->comps[i].prec, tmp_str);
+ ret = OPJ_FALSE;
+ }
+ }
+
+ /* Sub-sampling */
+ for (i = 0; i < image->numcomps; i++) {
+ if (i == 0 && image->comps[i].dx != 1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require XRSiz1 == 1. Here it is set to %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[i].dx);
+ ret = OPJ_FALSE;
+ }
+ if (i == 1 && image->comps[i].dx != 1 && image->comps[i].dx != 2) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require XRSiz2 == 1 or 2. Here it is set to %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[i].dx);
+ ret = OPJ_FALSE;
+ }
+ if (i > 1 && image->comps[i].dx != image->comps[i - 1].dx) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require XRSiz%d to be the same as XRSiz2. "
+ "Here it is set to %d instead of %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ i + 1, image->comps[i].dx, image->comps[i - 1].dx);
+ ret = OPJ_FALSE;
+ }
+ if (image->comps[i].dy != 1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require YRsiz == 1. "
+ "Here it is set to %d for component %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[i].dy, i);
+ ret = OPJ_FALSE;
+ }
+ }
+
+ /* Image size */
+ switch (profile) {
+ case OPJ_PROFILE_IMF_2K:
+ case OPJ_PROFILE_IMF_2K_R:
+ if (((image->comps[0].w > 2048) | (image->comps[0].h > 1556))) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K/2K_R profile require:\n"
+ "width <= 2048 and height <= 1556\n"
+ "-> Input image size %d x %d is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[0].w, image->comps[0].h);
+ ret = OPJ_FALSE;
+ }
+ break;
+ case OPJ_PROFILE_IMF_4K:
+ case OPJ_PROFILE_IMF_4K_R:
+ if (((image->comps[0].w > 4096) | (image->comps[0].h > 3112))) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K/4K_R profile require:\n"
+ "width <= 4096 and height <= 3112\n"
+ "-> Input image size %d x %d is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[0].w, image->comps[0].h);
+ ret = OPJ_FALSE;
+ }
+ break;
+ case OPJ_PROFILE_IMF_8K:
+ case OPJ_PROFILE_IMF_8K_R:
+ if (((image->comps[0].w > 8192) | (image->comps[0].h > 6224))) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 8K/8K_R profile require:\n"
+ "width <= 8192 and height <= 6224\n"
+ "-> Input image size %d x %d is not compliant\n"
+ "-> Non-IMF codestream will be generated\n",
+ image->comps[0].w, image->comps[0].h);
+ ret = OPJ_FALSE;
+ }
+ break;
+ default :
+ assert(0);
+ return OPJ_FALSE;
+ }
+
+ if (parameters->roi_compno != -1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile forbid RGN / region of interest marker.\n"
+ "-> Compression parameters specify a ROI\n"
+ "-> Non-IMF codestream will be generated\n");
+ ret = OPJ_FALSE;
+ }
+
+ if (parameters->cblockw_init != 32 || parameters->cblockh_init != 32) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile require code block size to be 32x32.\n"
+ "-> Compression parameters set it to %dx%d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->cblockw_init,
+ parameters->cblockh_init);
+ ret = OPJ_FALSE;
+ }
+
+ if (parameters->prog_order != OPJ_CPRL) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile require progression order to be CPRL.\n"
+ "-> Compression parameters set it to %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->prog_order);
+ ret = OPJ_FALSE;
+ }
+
+ if (parameters->numpocs != 0) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile forbid POC markers.\n"
+ "-> Compression parameters set %d POC.\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->numpocs);
+ ret = OPJ_FALSE;
+ }
+
+ /* Codeblock style: no mode switch enabled */
+ if (parameters->mode != 0) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profile forbid mode switch in code block style.\n"
+ "-> Compression parameters set code block style to %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->mode);
+ ret = OPJ_FALSE;
+ }
+
+ if (profile == OPJ_PROFILE_IMF_2K ||
+ profile == OPJ_PROFILE_IMF_4K ||
+ profile == OPJ_PROFILE_IMF_8K) {
+ /* Expect 9-7 transform */
+ if (parameters->irreversible != 1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K/4K/8K profiles require 9-7 Irreversible Transform.\n"
+ "-> Compression parameters set it to reversible.\n"
+ "-> Non-IMF codestream will be generated\n");
+ ret = OPJ_FALSE;
+ }
+ } else {
+ /* Expect 5-3 transform */
+ if (parameters->irreversible != 0) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K/4K/8K profiles require 5-3 reversible Transform.\n"
+ "-> Compression parameters set it to irreversible.\n"
+ "-> Non-IMF codestream will be generated\n");
+ ret = OPJ_FALSE;
+ }
+ }
+
+ /* Number of layers */
+ if (parameters->tcp_numlayers != 1) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K/4K/8K profiles require 1 single quality layer.\n"
+ "-> Number of layers is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ parameters->tcp_numlayers);
+ ret = OPJ_FALSE;
+ }
+
+ /* Decomposition levels */
+ switch (profile) {
+ case OPJ_PROFILE_IMF_2K:
+ if (!(NL >= 1 && NL <= 5)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K profile requires 1 <= NL <= 5:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ break;
+ case OPJ_PROFILE_IMF_4K:
+ if (!(NL >= 1 && NL <= 6)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K profile requires 1 <= NL <= 6:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ break;
+ case OPJ_PROFILE_IMF_8K:
+ if (!(NL >= 1 && NL <= 7)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 8K profile requires 1 <= NL <= 7:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ break;
+ case OPJ_PROFILE_IMF_2K_R: {
+ if (XTsiz >= 2048) {
+ if (!(NL >= 1 && NL <= 5)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K_R profile requires 1 <= NL <= 5 for XTsiz >= 2048:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 1024) {
+ if (!(NL >= 1 && NL <= 4)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 2K_R profile requires 1 <= NL <= 4 for XTsiz in [1024,2048[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ }
+ break;
+ }
+ case OPJ_PROFILE_IMF_4K_R: {
+ if (XTsiz >= 4096) {
+ if (!(NL >= 1 && NL <= 6)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 6 for XTsiz >= 4096:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 2048) {
+ if (!(NL >= 1 && NL <= 5)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 5 for XTsiz in [2048,4096[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 1024) {
+ if (!(NL >= 1 && NL <= 4)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 4 for XTsiz in [1024,2048[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ }
+ break;
+ }
+ case OPJ_PROFILE_IMF_8K_R: {
+ if (XTsiz >= 8192) {
+ if (!(NL >= 1 && NL <= 7)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 7 for XTsiz >= 8192:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 4096) {
+ if (!(NL >= 1 && NL <= 6)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 6 for XTsiz in [4096,8192[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 2048) {
+ if (!(NL >= 1 && NL <= 5)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 5 for XTsiz in [2048,4096[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ } else if (XTsiz >= 1024) {
+ if (!(NL >= 1 && NL <= 4)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF 4K_R profile requires 1 <= NL <= 4 for XTsiz in [1024,2048[:\n"
+ "-> Number of decomposition levels is %d.\n"
+ "-> Non-IMF codestream will be generated\n",
+ NL);
+ ret = OPJ_FALSE;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (parameters->numresolution == 1) {
+ if (parameters->res_spec != 1 ||
+ parameters->prcw_init[0] != 128 ||
+ parameters->prch_init[0] != 128) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require PPx = PPy = 7 for NLLL band, else 8.\n"
+ "-> Supplied values are different from that.\n"
+ "-> Non-IMF codestream will be generated\n");
+ ret = OPJ_FALSE;
+ }
+ } else {
+ int i;
+ for (i = 0; i < parameters->res_spec; i++) {
+ if (parameters->prcw_init[i] != 256 ||
+ parameters->prch_init[i] != 256) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "IMF profiles require PPx = PPy = 7 for NLLL band, else 8.\n"
+ "-> Supplied values are different from that.\n"
+ "-> Non-IMF codestream will be generated\n");
+ ret = OPJ_FALSE;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k,
+ opj_cparameters_t *parameters,
+ opj_image_t *image,
+ opj_event_mgr_t * p_manager)
+{
+ OPJ_UINT32 i, j, tileno, numpocs_tile;
+ opj_cp_t *cp = 00;
+ OPJ_UINT32 cblkw, cblkh;
+
+ if (!p_j2k || !parameters || ! image) {
+ return OPJ_FALSE;
+ }
+
+ if ((parameters->numresolution <= 0) ||
+ (parameters->numresolution > OPJ_J2K_MAXRLVLS)) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid number of resolutions : %d not in range [1,%d]\n",
+ parameters->numresolution, OPJ_J2K_MAXRLVLS);
+ return OPJ_FALSE;
+ }
+
+ if (parameters->cblockw_init < 4 || parameters->cblockw_init > 1024) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
+ parameters->cblockw_init);
+ return OPJ_FALSE;
+ }
+ if (parameters->cblockh_init < 4 || parameters->cblockh_init > 1024) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for cblockh_init: %d not a power of 2 not in range [4,1024]\n",
+ parameters->cblockh_init);
+ return OPJ_FALSE;
+ }
+ if (parameters->cblockw_init * parameters->cblockh_init > 4096) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for cblockw_init * cblockh_init: should be <= 4096\n");
+ return OPJ_FALSE;
+ }
+ cblkw = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockw_init);
+ cblkh = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockh_init);
+ if (parameters->cblockw_init != (1 << cblkw)) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
+ parameters->cblockw_init);
+ return OPJ_FALSE;
+ }
+ if (parameters->cblockh_init != (1 << cblkh)) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n",
+ parameters->cblockh_init);
+ return OPJ_FALSE;
+ }
+
+ /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */
+ cp = &(p_j2k->m_cp);
+
+ /* set default values for cp */
+ cp->tw = 1;
+ cp->th = 1;
+
+ /* FIXME ADE: to be removed once deprecated cp_cinema and cp_rsiz have been removed */
if (parameters->rsiz ==
OPJ_PROFILE_NONE) { /* consider deprecated fields only if RSIZ has not been set */
OPJ_BOOL deprecated_used = OPJ_FALSE;
parameters->tcp_rates[0] = 0;
}
+ if (parameters->cp_disto_alloc) {
+ /* Emit warnings if tcp_rates are not decreasing */
+ for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
+ OPJ_FLOAT32 rate_i_corr = parameters->tcp_rates[i];
+ OPJ_FLOAT32 rate_i_m_1_corr = parameters->tcp_rates[i - 1];
+ if (rate_i_corr <= 1.0) {
+ rate_i_corr = 1.0;
+ }
+ if (rate_i_m_1_corr <= 1.0) {
+ rate_i_m_1_corr = 1.0;
+ }
+ if (rate_i_corr >= rate_i_m_1_corr) {
+ if (rate_i_corr != parameters->tcp_rates[i] &&
+ rate_i_m_1_corr != parameters->tcp_rates[i - 1]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser "
+ "than tcp_rates[%d]=%f (corrected as %f)\n",
+ i, parameters->tcp_rates[i], rate_i_corr,
+ i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr);
+ } else if (rate_i_corr != parameters->tcp_rates[i]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser "
+ "than tcp_rates[%d]=%f\n",
+ i, parameters->tcp_rates[i], rate_i_corr,
+ i - 1, parameters->tcp_rates[i - 1]);
+ } else if (rate_i_m_1_corr != parameters->tcp_rates[i - 1]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f should be strictly lesser "
+ "than tcp_rates[%d]=%f (corrected as %f)\n",
+ i, parameters->tcp_rates[i],
+ i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr);
+ } else {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f should be strictly lesser "
+ "than tcp_rates[%d]=%f\n",
+ i, parameters->tcp_rates[i],
+ i - 1, parameters->tcp_rates[i - 1]);
+ }
+ }
+ }
+ } else if (parameters->cp_fixed_quality) {
+ /* Emit warnings if tcp_distoratio are not increasing */
+ for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
+ if (parameters->tcp_distoratio[i] < parameters->tcp_distoratio[i - 1] &&
+ !(i == (OPJ_UINT32)parameters->tcp_numlayers - 1 &&
+ parameters->tcp_distoratio[i] == 0)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_distoratio[%d]=%f should be strictly greater "
+ "than tcp_distoratio[%d]=%f\n",
+ i, parameters->tcp_distoratio[i], i - 1,
+ parameters->tcp_distoratio[i - 1]);
+ }
+ }
+ }
+
/* see if max_codestream_size does limit input rate */
if (parameters->max_cs_size <= 0) {
if (parameters->tcp_rates[parameters->tcp_numlayers - 1] > 0) {
OPJ_FLOAT32 temp_size;
- temp_size = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w *
- image->comps[0].h * image->comps[0].prec) /
- (parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 *
- (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy);
- parameters->max_cs_size = (int) floor(temp_size);
+ temp_size = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w *
+ image->comps[0].h * image->comps[0].prec) /
+ ((double)parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 *
+ image->comps[0].dx * image->comps[0].dy));
+ if (temp_size > INT_MAX) {
+ parameters->max_cs_size = INT_MAX;
+ } else {
+ parameters->max_cs_size = (int) floor(temp_size);
+ }
} else {
parameters->max_cs_size = 0;
}
} else {
OPJ_FLOAT32 temp_rate;
OPJ_BOOL cap = OPJ_FALSE;
- temp_rate = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w *
- image->comps[0].h * image->comps[0].prec) /
- (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx *
- image->comps[0].dy);
+
+ if (OPJ_IS_IMF(parameters->rsiz) && parameters->max_cs_size > 0 &&
+ parameters->tcp_numlayers == 1 && parameters->tcp_rates[0] == 0) {
+ parameters->tcp_rates[0] = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w *
+ image->comps[0].h * image->comps[0].prec) /
+ (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx *
+ image->comps[0].dy);
+ }
+
+ temp_rate = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w *
+ image->comps[0].h * image->comps[0].prec) /
+ (((double)parameters->max_cs_size) * 8 * image->comps[0].dx *
+ image->comps[0].dy));
for (i = 0; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
if (parameters->tcp_rates[i] < temp_rate) {
parameters->tcp_rates[i] = temp_rate;
}
}
+ if (OPJ_IS_CINEMA(parameters->rsiz) || OPJ_IS_IMF(parameters->rsiz)) {
+ p_j2k->m_specific_param.m_encoder.m_TLM = OPJ_TRUE;
+ }
+
/* Manage profiles and applications and set RSIZ */
/* set cinema parameters if required */
if (OPJ_IS_CINEMA(parameters->rsiz)) {
"JPEG 2000 Broadcast profiles not yet supported\n");
parameters->rsiz = OPJ_PROFILE_NONE;
} else if (OPJ_IS_IMF(parameters->rsiz)) {
- opj_event_msg(p_manager, EVT_WARNING,
- "JPEG 2000 IMF profiles not yet supported\n");
- parameters->rsiz = OPJ_PROFILE_NONE;
+ opj_j2k_set_imf_parameters(parameters, image, p_manager);
+ if (!opj_j2k_is_imf_compliant(parameters, image, p_manager)) {
+ parameters->rsiz = OPJ_PROFILE_NONE;
+ }
} else if (OPJ_IS_PART2(parameters->rsiz)) {
if (parameters->rsiz == ((OPJ_PROFILE_PART2) | (OPJ_EXTENSION_NONE))) {
opj_event_msg(p_manager, EVT_WARNING,
*/
if (parameters->tile_size_on) {
+ if (cp->tdx == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid tile width\n");
+ return OPJ_FALSE;
+ }
+ if (cp->tdy == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid tile height\n");
+ return OPJ_FALSE;
+ }
cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->x1 - cp->tx0),
(OPJ_INT32)cp->tdx);
cp->th = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(image->y1 - cp->ty0),
}
#endif /* USE_JPWL */
- /* initialize the mutiple tiles */
+ /* initialize the multiple tiles */
/* ---------------------------- */
cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t));
if (!cp->tcps) {
"Not enough memory to allocate tile coding parameters\n");
return OPJ_FALSE;
}
- if (parameters->numpocs) {
- /* initialisation of POC */
- opj_j2k_check_poc_val(parameters->POC, parameters->numpocs,
- (OPJ_UINT32)parameters->numresolution, image->numcomps,
- (OPJ_UINT32)parameters->tcp_numlayers, p_manager);
- /* TODO MSD use the return value*/
- }
for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
opj_tcp_t *tcp = &cp->tcps[tileno];
tcp->numlayers = (OPJ_UINT32)parameters->tcp_numlayers;
for (j = 0; j < tcp->numlayers; j++) {
- if (OPJ_IS_CINEMA(cp->rsiz)) {
+ if (OPJ_IS_CINEMA(cp->rsiz) || OPJ_IS_IMF(cp->rsiz)) {
if (cp->m_specific_param.m_enc.m_fixed_quality) {
tcp->distoratio[j] = parameters->tcp_distoratio[j];
}
tcp->rates[j] = parameters->tcp_rates[j];
}
}
+ if (!cp->m_specific_param.m_enc.m_fixed_quality &&
+ tcp->rates[j] <= 1.0) {
+ tcp->rates[j] = 0.0; /* force lossless */
+ }
}
tcp->csty = (OPJ_UINT32)parameters->csty;
if (parameters->numpocs) {
/* initialisation of POC */
- tcp->POC = 1;
for (i = 0; i < parameters->numpocs; i++) {
if (tileno + 1 == parameters->POC[i].tile) {
opj_poc_t *tcp_poc = &tcp->pocs[numpocs_tile];
+ if (parameters->POC[numpocs_tile].compno0 >= image->numcomps) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid compno0 for POC %d\n", i);
+ return OPJ_FALSE;
+ }
+
tcp_poc->resno0 = parameters->POC[numpocs_tile].resno0;
tcp_poc->compno0 = parameters->POC[numpocs_tile].compno0;
tcp_poc->layno1 = parameters->POC[numpocs_tile].layno1;
tcp_poc->resno1 = parameters->POC[numpocs_tile].resno1;
- tcp_poc->compno1 = parameters->POC[numpocs_tile].compno1;
+ tcp_poc->compno1 = opj_uint_min(parameters->POC[numpocs_tile].compno1,
+ image->numcomps);
tcp_poc->prg1 = parameters->POC[numpocs_tile].prg1;
tcp_poc->tile = parameters->POC[numpocs_tile].tile;
}
}
- tcp->numpocs = numpocs_tile - 1 ;
+ if (numpocs_tile) {
+
+ /* TODO MSD use the return value*/
+ opj_j2k_check_poc_val(parameters->POC, tileno, parameters->numpocs,
+ (OPJ_UINT32)parameters->numresolution, image->numcomps,
+ (OPJ_UINT32)parameters->tcp_numlayers, p_manager);
+
+ tcp->POC = 1;
+ tcp->numpocs = numpocs_tile - 1 ;
+ }
} else {
tcp->numpocs = 0;
}
/*Allocate and initialize some elements of codestrem index*/
if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) {
+ opj_image_destroy(*p_image);
+ *p_image = NULL;
return OPJ_FALSE;
}
if (l_marker_handler->id == J2K_MS_UNK) {
if (! opj_j2k_read_unk(p_j2k, p_stream, &l_current_marker, p_manager)) {
opj_event_msg(p_manager, EVT_ERROR,
- "Unknow marker have been detected and generated error.\n");
+ "Unknown marker have been detected and generated error.\n");
return OPJ_FALSE;
}
p_j2k->m_specific_param.m_decoder.m_header_data = 00;
p_j2k->m_specific_param.m_decoder.m_header_data_size = 0;
}
+
+ opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode);
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = 00;
+ p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0;
+
} else {
if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) {
break;
}
- if ((l_tot_len == 0U) || (l_tot_len < 14U)) {
+ if (l_tot_len < 14U) {
/* last SOT until EOC or invalid Psot value */
/* assume all is OK */
if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) {
OPJ_UINT32 l_marker_size;
const opj_dec_memory_marker_handler_t * l_marker_handler = 00;
opj_tcp_t * l_tcp = NULL;
+ const OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th;
/* preconditions */
assert(p_stream != 00);
return OPJ_FALSE;
}
if (l_correction_needed) {
- OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.tw * p_j2k->m_cp.th;
OPJ_UINT32 l_tile_no;
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
"Non conformant codestream TPsot==TNsot.\n");
}
}
- if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
- /* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
- if (opj_stream_read_data(p_stream,
- p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
- opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
- return OPJ_FALSE;
- }
-
- /* Read 2 bytes from buffer as the new marker ID */
- opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,
- &l_current_marker, 2);
- }
} else {
/* Indicate we will try to read a new tile-part header*/
p_j2k->m_specific_param.m_decoder.m_skip_data = 0;
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
+ }
+ if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
/* Try to read 2 bytes (the next marker ID) from stream and copy them into the buffer */
if (opj_stream_read_data(p_stream,
p_j2k->m_specific_param.m_decoder.m_header_data, 2, p_manager) != 2) {
+
+ /* Deal with likely non conformant SPOT6 files, where the last */
+ /* row of tiles have TPsot == 0 and TNsot == 0, and missing EOC, */
+ /* but no other tile-parts were found. */
+ if (p_j2k->m_current_tile_number + 1 == l_nb_tiles) {
+ OPJ_UINT32 l_tile_no;
+ for (l_tile_no = 0U; l_tile_no < l_nb_tiles; ++l_tile_no) {
+ if (p_j2k->m_cp.tcps[l_tile_no].m_current_tile_part_number == 0 &&
+ p_j2k->m_cp.tcps[l_tile_no].m_nb_tile_parts == 0) {
+ break;
+ }
+ }
+ if (l_tile_no < l_nb_tiles) {
+ opj_event_msg(p_manager, EVT_INFO,
+ "Tile %u has TPsot == 0 and TNsot == 0, "
+ "but no other tile-parts were found. "
+ "EOC is also missing.\n",
+ l_tile_no);
+ p_j2k->m_current_tile_number = l_tile_no;
+ l_current_marker = J2K_MS_EOC;
+ p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+ break;
+ }
+ }
+
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
return OPJ_FALSE;
}
/* Current marker is the EOC marker ?*/
if (l_current_marker == J2K_MS_EOC) {
- p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+ if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_EOC) {
+ p_j2k->m_current_tile_number = 0;
+ p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
+ }
}
- /* FIXME DOC ???*/
+ /* Deal with tiles that have a single tile-part with TPsot == 0 and TNsot == 0 */
if (! p_j2k->m_specific_param.m_decoder.m_can_decode) {
- OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number;
while ((p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00)) {
/* When using the opj_read_tile_header / opj_decode_tile_data API */
/* such as in test_tile_decoder, m_output_image is NULL, so fall back */
/* to the full image dimension. This is a bit surprising that */
- /* opj_set_decode_area() is only used to determinte intersecting tiles, */
+ /* opj_set_decode_area() is only used to determine intersecting tiles, */
/* but full tile decoding is done */
l_image_for_bounds = p_j2k->m_output_image ? p_j2k->m_output_image :
p_j2k->m_private_image;
l_image_for_bounds->y0,
l_image_for_bounds->x1,
l_image_for_bounds->y1,
+ p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode,
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode,
l_tcp->m_data,
l_tcp->m_data_size,
p_tile_index,
l_img_comp_dest = p_output_image->comps;
- for (i = 0; i < l_image_src->numcomps; i++) {
+ for (i = 0; i < l_image_src->numcomps;
+ i++, ++l_img_comp_dest, ++l_img_comp_src, ++l_tilec) {
OPJ_INT32 res_x0, res_x1, res_y0, res_y1;
OPJ_UINT32 src_data_stride;
const OPJ_INT32* p_src_data;
- /* Allocate output component buffer if necessary */
- if (!l_img_comp_dest->data) {
- OPJ_SIZE_T l_width = l_img_comp_dest->w;
- OPJ_SIZE_T l_height = l_img_comp_dest->h;
-
- if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) ||
- l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) {
- /* would overflow */
- return OPJ_FALSE;
- }
- l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height *
- sizeof(OPJ_INT32));
- if (! l_img_comp_dest->data) {
- return OPJ_FALSE;
- }
- /* Do we really need this memset ? */
- memset(l_img_comp_dest->data, 0, l_width * l_height * sizeof(OPJ_INT32));
- }
-
/* Copy info from decoded comp image to output image */
l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded;
p_src_data = l_tilec->data_win;
}
+ if (p_src_data == NULL) {
+ /* Happens for partial component decoding */
+ continue;
+ }
+
l_width_src = (OPJ_UINT32)(res_x1 - res_x0);
l_height_src = (OPJ_UINT32)(res_y1 - res_y0);
l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest
* (OPJ_SIZE_T)l_img_comp_dest->w;
+ /* Allocate output component buffer if necessary */
+ if (l_img_comp_dest->data == NULL &&
+ l_start_offset_src == 0 && l_start_offset_dest == 0 &&
+ src_data_stride == l_img_comp_dest->w &&
+ l_width_dest == l_img_comp_dest->w &&
+ l_height_dest == l_img_comp_dest->h) {
+ /* If the final image matches the tile buffer, then borrow it */
+ /* directly to save a copy */
+ if (p_tcd->whole_tile_decoding) {
+ l_img_comp_dest->data = l_tilec->data;
+ l_tilec->data = NULL;
+ } else {
+ l_img_comp_dest->data = l_tilec->data_win;
+ l_tilec->data_win = NULL;
+ }
+ continue;
+ } else if (l_img_comp_dest->data == NULL) {
+ OPJ_SIZE_T l_width = l_img_comp_dest->w;
+ OPJ_SIZE_T l_height = l_img_comp_dest->h;
+
+ if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) ||
+ l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) {
+ /* would overflow */
+ return OPJ_FALSE;
+ }
+ l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height *
+ sizeof(OPJ_INT32));
+ if (! l_img_comp_dest->data) {
+ return OPJ_FALSE;
+ }
+
+ if (l_img_comp_dest->w != l_width_dest ||
+ l_img_comp_dest->h != l_height_dest) {
+ memset(l_img_comp_dest->data, 0,
+ (OPJ_SIZE_T)l_img_comp_dest->w * l_img_comp_dest->h * sizeof(OPJ_INT32));
+ }
+ }
+
/* Move the output buffer to the first place where we will write*/
l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest;
}
}
- ++l_img_comp_dest;
- ++l_img_comp_src;
- ++l_tilec;
+
}
return OPJ_TRUE;
l_img_comp = p_image->comps;
for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) {
OPJ_INT32 l_h, l_w;
+ if (p_image->x0 > (OPJ_UINT32)INT_MAX ||
+ p_image->y0 > (OPJ_UINT32)INT_MAX ||
+ p_image->x1 > (OPJ_UINT32)INT_MAX ||
+ p_image->y1 > (OPJ_UINT32)INT_MAX) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Image coordinates above INT_MAX are not supported\n");
+ return OPJ_FALSE;
+ }
l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0,
(OPJ_INT32)l_img_comp->dx);
return OPJ_TRUE;
}
+OPJ_BOOL opj_j2k_set_decoded_components(opj_j2k_t *p_j2k,
+ OPJ_UINT32 numcomps,
+ const OPJ_UINT32* comps_indices,
+ opj_event_mgr_t * p_manager)
+{
+ OPJ_UINT32 i;
+ OPJ_BOOL* already_mapped;
+
+ if (p_j2k->m_private_image == NULL) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "opj_read_header() should be called before "
+ "opj_set_decoded_components().\n");
+ return OPJ_FALSE;
+ }
+
+ already_mapped = (OPJ_BOOL*) opj_calloc(sizeof(OPJ_BOOL),
+ p_j2k->m_private_image->numcomps);
+ if (already_mapped == NULL) {
+ return OPJ_FALSE;
+ }
+
+ for (i = 0; i < numcomps; i++) {
+ if (comps_indices[i] >= p_j2k->m_private_image->numcomps) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid component index: %u\n",
+ comps_indices[i]);
+ opj_free(already_mapped);
+ return OPJ_FALSE;
+ }
+ if (already_mapped[comps_indices[i]]) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Component index %u used several times\n",
+ comps_indices[i]);
+ opj_free(already_mapped);
+ return OPJ_FALSE;
+ }
+ already_mapped[comps_indices[i]] = OPJ_TRUE;
+ }
+ opj_free(already_mapped);
+
+ opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode);
+ if (numcomps) {
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode =
+ (OPJ_UINT32*) opj_malloc(numcomps * sizeof(OPJ_UINT32));
+ if (p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode == NULL) {
+ p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0;
+ return OPJ_FALSE;
+ }
+ memcpy(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode,
+ comps_indices,
+ numcomps * sizeof(OPJ_UINT32));
+ } else {
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = NULL;
+ }
+ p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = numcomps;
+
+ return OPJ_TRUE;
+}
+
OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
opj_image_t* p_image,
OPJ_UINT32 it_comp;
if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
- &p_j2k->m_cp.tcps[0].m_data != NULL) {
+ p_j2k->m_cp.tcps[0].m_data != NULL) {
/* In the case of a single-tiled image whose codestream we have already */
/* ingested, go on */
}
}
/* Up */
- if (p_start_x < 0) {
+ if (p_start_y < 0) {
opj_event_msg(p_manager, EVT_ERROR,
"Up position of the decoded area (region_y0=%d) should be >= 0.\n",
p_start_y);
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->numresolutions,
- 1); /* SPcox (D) */
- ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */
+ /* SPcod (D) / SPcoc (A) */
+ opj_read_bytes(l_current_ptr, &l_tccp->numresolutions, 1);
+ ++l_tccp->numresolutions; /* tccp->numresolutions = read() + 1 */
if (l_tccp->numresolutions > OPJ_J2K_MAXRLVLS) {
opj_event_msg(p_manager, EVT_ERROR,
"Invalid value for numresolutions : %d, max value is set in openjpeg.h at %d\n",
/* If user wants to remove more resolutions than the codestream contains, return error */
if (l_cp->m_specific_param.m_dec.m_reduce >= l_tccp->numresolutions) {
opj_event_msg(p_manager, EVT_ERROR,
- "Error decoding component %d.\nThe number of resolutions to remove is higher than the number "
- "of resolutions of this component\nModify the cp_reduce parameter.\n\n",
- compno);
+ "Error decoding component %d.\nThe number of resolutions "
+ "to remove (%d) is greater or equal than the number "
+ "of resolutions of this component (%d)\nModify the cp_reduce parameter.\n\n",
+ compno, l_cp->m_specific_param.m_dec.m_reduce, l_tccp->numresolutions);
p_j2k->m_specific_param.m_decoder.m_state |=
0x8000;/* FIXME J2K_DEC_STATE_ERR;*/
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1); /* SPcoc (E) */
+ /* SPcod (E) / SPcoc (B) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblkw, 1);
++l_current_ptr;
l_tccp->cblkw += 2;
- opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1); /* SPcoc (F) */
+ /* SPcod (F) / SPcoc (C) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblkh, 1);
++l_current_ptr;
l_tccp->cblkh += 2;
return OPJ_FALSE;
}
-
- opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1); /* SPcoc (G) */
+ /* SPcod (G) / SPcoc (D) */
+ opj_read_bytes(l_current_ptr, &l_tccp->cblksty, 1);
++l_current_ptr;
- if (l_tccp->cblksty & 0xC0U) { /* 2 msb are reserved, assume we can't read */
+ if ((l_tccp->cblksty & J2K_CCP_CBLKSTY_HTMIXED) != 0) {
+ /* We do not support HT mixed mode yet. For conformance, it should be supported.*/
opj_event_msg(p_manager, EVT_ERROR,
- "Error reading SPCod SPCoc element, Invalid code-block style found\n");
+ "Error reading SPCod SPCoc element. Unsupported Mixed HT code-block style found\n");
return OPJ_FALSE;
}
- opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1); /* SPcoc (H) */
+ /* SPcod (H) / SPcoc (E) */
+ opj_read_bytes(l_current_ptr, &l_tccp->qmfbid, 1);
++l_current_ptr;
+ if (l_tccp->qmfbid > 1) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Error reading SPCod SPCoc element, Invalid transformation found\n");
+ return OPJ_FALSE;
+ }
+
*p_header_size = *p_header_size - 5;
/* use custom precinct size ? */
return OPJ_FALSE;
}
+ /* SPcod (I_i) / SPcoc (F_i) */
for (i = 0; i < l_tccp->numresolutions; ++i) {
- opj_read_bytes(l_current_ptr, &l_tmp, 1); /* SPcoc (I_i) */
+ opj_read_bytes(l_current_ptr, &l_tmp, 1);
++l_current_ptr;
/* Precinct exponent 0 is only allowed for lowest resolution level (Table A.21) */
if ((i != 0) && (((l_tmp & 0xf) == 0) || ((l_tmp >> 4) == 0))) {
return OPJ_TRUE;
}
+static OPJ_BOOL opj_j2k_are_all_used_components_decoded(opj_j2k_t *p_j2k,
+ opj_event_mgr_t * p_manager)
+{
+ OPJ_UINT32 compno;
+ OPJ_BOOL decoded_all_used_components = OPJ_TRUE;
+
+ if (p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode) {
+ for (compno = 0;
+ compno < p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode; compno++) {
+ OPJ_UINT32 dec_compno =
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode[compno];
+ if (p_j2k->m_output_image->comps[dec_compno].data == NULL) {
+ opj_event_msg(p_manager, EVT_WARNING, "Failed to decode component %d\n",
+ dec_compno);
+ decoded_all_used_components = OPJ_FALSE;
+ }
+ }
+ } else {
+ for (compno = 0; compno < p_j2k->m_output_image->numcomps; compno++) {
+ if (p_j2k->m_output_image->comps[compno].data == NULL) {
+ opj_event_msg(p_manager, EVT_WARNING, "Failed to decode component %d\n",
+ compno);
+ decoded_all_used_components = OPJ_FALSE;
+ }
+ }
+ }
+
+ if (decoded_all_used_components == OPJ_FALSE) {
+ opj_event_msg(p_manager, EVT_ERROR, "Failed to decode all used components\n");
+ return OPJ_FALSE;
+ }
+
+ return OPJ_TRUE;
+}
+
+
static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k,
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager)
}
}
+ if (! opj_j2k_are_all_used_components_decoded(p_j2k, p_manager)) {
+ return OPJ_FALSE;
+ }
+
return OPJ_TRUE;
}
/**
- * Sets up the procedures to do on decoding data. Developpers wanting to extend the library can add their own reading procedures.
+ * Sets up the procedures to do on decoding data. Developers wanting to extend the library can add their own reading procedures.
*/
static OPJ_BOOL opj_j2k_setup_decoding(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager)
}
+ if (! opj_j2k_are_all_used_components_decoded(p_j2k, p_manager)) {
+ return OPJ_FALSE;
+ }
+
return OPJ_TRUE;
}
/**
- * Sets up the procedures to do on decoding one tile. Developpers wanting to extend the library can add their own reading procedures.
+ * Sets up the procedures to do on decoding one tile. Developers wanting to extend the library can add their own reading procedures.
*/
static OPJ_BOOL opj_j2k_setup_decoding_tile(opj_j2k_t *p_j2k,
opj_event_mgr_t * p_manager)
return OPJ_TRUE;
}
+static OPJ_BOOL opj_j2k_move_data_from_codec_to_output_image(opj_j2k_t * p_j2k,
+ opj_image_t * p_image)
+{
+ OPJ_UINT32 compno;
+
+ /* Move data and copy one information from codec to output image*/
+ if (p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode > 0) {
+ opj_image_comp_t* newcomps =
+ (opj_image_comp_t*) opj_malloc(
+ p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode *
+ sizeof(opj_image_comp_t));
+ if (newcomps == NULL) {
+ opj_image_destroy(p_j2k->m_private_image);
+ p_j2k->m_private_image = NULL;
+ return OPJ_FALSE;
+ }
+ for (compno = 0; compno < p_image->numcomps; compno++) {
+ opj_image_data_free(p_image->comps[compno].data);
+ p_image->comps[compno].data = NULL;
+ }
+ for (compno = 0;
+ compno < p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode; compno++) {
+ OPJ_UINT32 src_compno =
+ p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode[compno];
+ memcpy(&(newcomps[compno]),
+ &(p_j2k->m_output_image->comps[src_compno]),
+ sizeof(opj_image_comp_t));
+ newcomps[compno].resno_decoded =
+ p_j2k->m_output_image->comps[src_compno].resno_decoded;
+ newcomps[compno].data = p_j2k->m_output_image->comps[src_compno].data;
+ p_j2k->m_output_image->comps[src_compno].data = NULL;
+ }
+ for (compno = 0; compno < p_image->numcomps; compno++) {
+ assert(p_j2k->m_output_image->comps[compno].data == NULL);
+ opj_image_data_free(p_j2k->m_output_image->comps[compno].data);
+ p_j2k->m_output_image->comps[compno].data = NULL;
+ }
+ p_image->numcomps = p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode;
+ opj_free(p_image->comps);
+ p_image->comps = newcomps;
+ } else {
+ for (compno = 0; compno < p_image->numcomps; compno++) {
+ p_image->comps[compno].resno_decoded =
+ p_j2k->m_output_image->comps[compno].resno_decoded;
+ opj_image_data_free(p_image->comps[compno].data);
+ p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
+#if 0
+ char fn[256];
+ sprintf(fn, "/tmp/%d.raw", compno);
+ FILE *debug = fopen(fn, "wb");
+ fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32),
+ p_image->comps[compno].w * p_image->comps[compno].h, debug);
+ fclose(debug);
+#endif
+ p_j2k->m_output_image->comps[compno].data = NULL;
+ }
+ }
+ return OPJ_TRUE;
+}
+
OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
opj_stream_private_t * p_stream,
opj_image_t * p_image,
opj_event_mgr_t * p_manager)
{
- OPJ_UINT32 compno;
-
if (!p_image) {
return OPJ_FALSE;
}
}
/* Move data and copy one information from codec to output image*/
- for (compno = 0; compno < p_image->numcomps; compno++) {
- p_image->comps[compno].resno_decoded =
- p_j2k->m_output_image->comps[compno].resno_decoded;
- opj_image_data_free(p_image->comps[compno].data);
- p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
-#if 0
- char fn[256];
- sprintf(fn, "/tmp/%d.raw", compno);
- FILE *debug = fopen(fn, "wb");
- fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32),
- p_image->comps[compno].w * p_image->comps[compno].h, debug);
- fclose(debug);
-#endif
- p_j2k->m_output_image->comps[compno].data = NULL;
- }
-
- return OPJ_TRUE;
+ return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image);
}
OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k,
return OPJ_FALSE;
}
+ if (p_image->numcomps < p_j2k->m_private_image->numcomps) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Image has less components than codestream.\n");
+ return OPJ_FALSE;
+ }
+
if (/*(tile_index < 0) &&*/ (tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th)) {
opj_event_msg(p_manager, EVT_ERROR,
"Tile index provided by the user is incorrect %d (max = %d) \n", tile_index,
}
l_img_comp = p_image->comps;
- for (compno = 0; compno < p_image->numcomps; ++compno) {
+ for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) {
OPJ_INT32 l_comp_x1, l_comp_y1;
l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor;
l_img_comp++;
}
+ if (p_image->numcomps > p_j2k->m_private_image->numcomps) {
+ /* Can happen when calling repeatdly opj_get_decoded_tile() on an
+ * image with a color palette, where color palette expansion is done
+ * later in jp2.c */
+ for (compno = p_j2k->m_private_image->numcomps; compno < p_image->numcomps;
+ ++compno) {
+ opj_image_data_free(p_image->comps[compno].data);
+ p_image->comps[compno].data = NULL;
+ }
+ p_image->numcomps = p_j2k->m_private_image->numcomps;
+ }
+
/* Destroy the previous output image*/
if (p_j2k->m_output_image) {
opj_image_destroy(p_j2k->m_output_image);
}
- /* Create the ouput image from the information previously computed*/
+ /* Create the output image from the information previously computed*/
p_j2k->m_output_image = opj_image_create0();
if (!(p_j2k->m_output_image)) {
return OPJ_FALSE;
}
/* Move data and copy one information from codec to output image*/
- for (compno = 0; compno < p_image->numcomps; compno++) {
- p_image->comps[compno].resno_decoded =
- p_j2k->m_output_image->comps[compno].resno_decoded;
-
- if (p_image->comps[compno].data) {
- opj_image_data_free(p_image->comps[compno].data);
- }
-
- p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
-
- p_j2k->m_output_image->comps[compno].data = NULL;
- }
-
- return OPJ_TRUE;
+ return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image);
}
OPJ_BOOL opj_j2k_set_decoded_resolution_factor(opj_j2k_t *p_j2k,
return OPJ_FALSE;
}
+/* ----------------------------------------------------------------------- */
+
+OPJ_BOOL opj_j2k_encoder_set_extra_options(
+ opj_j2k_t *p_j2k,
+ const char* const* p_options,
+ opj_event_mgr_t * p_manager)
+{
+ const char* const* p_option_iter;
+
+ if (p_options == NULL) {
+ return OPJ_TRUE;
+ }
+
+ for (p_option_iter = p_options; *p_option_iter != NULL; ++p_option_iter) {
+ if (strncmp(*p_option_iter, "PLT=", 4) == 0) {
+ if (strcmp(*p_option_iter, "PLT=YES") == 0) {
+ p_j2k->m_specific_param.m_encoder.m_PLT = OPJ_TRUE;
+ } else if (strcmp(*p_option_iter, "PLT=NO") == 0) {
+ p_j2k->m_specific_param.m_encoder.m_PLT = OPJ_FALSE;
+ } else {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for option: %s.\n", *p_option_iter);
+ return OPJ_FALSE;
+ }
+ } else if (strncmp(*p_option_iter, "TLM=", 4) == 0) {
+ if (strcmp(*p_option_iter, "TLM=YES") == 0) {
+ p_j2k->m_specific_param.m_encoder.m_TLM = OPJ_TRUE;
+ } else if (strcmp(*p_option_iter, "TLM=NO") == 0) {
+ p_j2k->m_specific_param.m_encoder.m_TLM = OPJ_FALSE;
+ } else {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid value for option: %s.\n", *p_option_iter);
+ return OPJ_FALSE;
+ }
+ } else {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Invalid option: %s.\n", *p_option_iter);
+ return OPJ_FALSE;
+ }
+ }
+
+ return OPJ_TRUE;
+}
+
+/* ----------------------------------------------------------------------- */
+
OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k,
opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager)
}
}
}
- l_current_tile_size = opj_tcd_get_encoded_tile_size(p_j2k->m_tcd);
+ l_current_tile_size = opj_tcd_get_encoder_input_buffer_size(p_j2k->m_tcd);
if (!l_reuse_data) {
if (l_current_tile_size > l_max_tile_size) {
OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data,
l_current_data = l_new_current_data;
l_max_tile_size = l_current_tile_size;
}
+ if (l_current_data == NULL) {
+ /* Should not happen in practice, but will avoid Coverity to */
+ /* complain about a null pointer dereference */
+ assert(0);
+ return OPJ_FALSE;
+ }
/* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */
/* 32 bit components @ 8 bit precision get converted to 8 bit */
return OPJ_FALSE;
}
- if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,
(opj_procedure)opj_j2k_write_updated_tlm, p_manager)) {
return OPJ_FALSE;
return OPJ_FALSE;
}
- if (OPJ_IS_CINEMA(p_j2k->m_cp.rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,
(opj_procedure)opj_j2k_write_tlm, p_manager)) {
return OPJ_FALSE;
}
/* DEVELOPER CORNER, insert your custom procedures */
- if (p_j2k->m_cp.rsiz & OPJ_EXTENSION_MCT) {
+ if ((p_j2k->m_cp.rsiz & (OPJ_PROFILE_PART2 | OPJ_EXTENSION_MCT)) ==
+ (OPJ_PROFILE_PART2 | OPJ_EXTENSION_MCT)) {
if (! opj_procedure_list_add_procedure(p_j2k->m_procedure_list,
(opj_procedure)opj_j2k_write_mct_data_group, p_manager)) {
return OPJ_FALSE;
static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
opj_stream_private_t *p_stream,
struct opj_event_mgr * p_manager)
{
l_current_nb_bytes_written = 0;
l_begin_data = p_data;
- if (! opj_j2k_write_sot(p_j2k, p_data, p_total_data_size,
+ if (! opj_j2k_write_sot(p_j2k, p_data, total_data_size,
&l_current_nb_bytes_written, p_stream,
p_manager)) {
return OPJ_FALSE;
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
if (!OPJ_IS_CINEMA(l_cp->rsiz)) {
#if 0
p_manager);
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
l_current_nb_bytes_written = 0;
opj_j2k_write_qcc_in_memory(p_j2k, compno, p_data, &l_current_nb_bytes_written,
p_manager);
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
}
#endif
- if (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) {
+ if (l_cp->tcps[p_j2k->m_current_tile_number].POC) {
l_current_nb_bytes_written = 0;
opj_j2k_write_poc_in_memory(p_j2k, p_data, &l_current_nb_bytes_written,
p_manager);
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
}
}
l_current_nb_bytes_written = 0;
if (! opj_j2k_write_sod(p_j2k, l_tcd, p_data, &l_current_nb_bytes_written,
- p_total_data_size, p_stream, p_manager)) {
+ total_data_size, p_stream, p_manager)) {
return OPJ_FALSE;
}
opj_write_bytes(l_begin_data + 6, l_nb_bytes_written,
4); /* PSOT */
- if (OPJ_IS_CINEMA(l_cp->rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
opj_j2k_update_tlm(p_j2k, l_nb_bytes_written);
}
static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
OPJ_UINT32 * p_data_written,
- OPJ_UINT32 p_total_data_size,
+ OPJ_UINT32 total_data_size,
opj_stream_private_t *p_stream,
struct opj_event_mgr * p_manager
)
l_begin_data = p_data;
if (! opj_j2k_write_sot(p_j2k, p_data,
- p_total_data_size,
+ total_data_size,
&l_current_nb_bytes_written,
p_stream,
p_manager)) {
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
l_part_tile_size += l_current_nb_bytes_written;
l_current_nb_bytes_written = 0;
if (! opj_j2k_write_sod(p_j2k, l_tcd, p_data, &l_current_nb_bytes_written,
- p_total_data_size, p_stream, p_manager)) {
+ total_data_size, p_stream, p_manager)) {
return OPJ_FALSE;
}
p_data += l_current_nb_bytes_written;
l_nb_bytes_written += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
l_part_tile_size += l_current_nb_bytes_written;
/* Writing Psot in SOT marker */
opj_write_bytes(l_begin_data + 6, l_part_tile_size,
4); /* PSOT */
- if (OPJ_IS_CINEMA(l_cp->rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
opj_j2k_update_tlm(p_j2k, l_part_tile_size);
}
l_begin_data = p_data;
if (! opj_j2k_write_sot(p_j2k, p_data,
- p_total_data_size,
+ total_data_size,
&l_current_nb_bytes_written, p_stream,
p_manager)) {
return OPJ_FALSE;
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
l_part_tile_size += l_current_nb_bytes_written;
l_current_nb_bytes_written = 0;
if (! opj_j2k_write_sod(p_j2k, l_tcd, p_data, &l_current_nb_bytes_written,
- p_total_data_size, p_stream, p_manager)) {
+ total_data_size, p_stream, p_manager)) {
return OPJ_FALSE;
}
l_nb_bytes_written += l_current_nb_bytes_written;
p_data += l_current_nb_bytes_written;
- p_total_data_size -= l_current_nb_bytes_written;
+ total_data_size -= l_current_nb_bytes_written;
l_part_tile_size += l_current_nb_bytes_written;
/* Writing Psot in SOT marker */
opj_write_bytes(l_begin_data + 6, l_part_tile_size,
4); /* PSOT */
- if (OPJ_IS_CINEMA(l_cp->rsiz)) {
+ if (p_j2k->m_specific_param.m_encoder.m_TLM) {
opj_j2k_update_tlm(p_j2k, l_part_tile_size);
}
{
OPJ_UINT32 l_tlm_size;
OPJ_OFF_T l_tlm_position, l_current_position;
+ OPJ_UINT32 size_per_tile_part;
/* preconditions */
assert(p_j2k != 00);
assert(p_manager != 00);
assert(p_stream != 00);
- l_tlm_size = 5 * p_j2k->m_specific_param.m_encoder.m_total_tile_parts;
+ size_per_tile_part = p_j2k->m_specific_param.m_encoder.m_Ttlmi_is_byte ? 5 : 6;
+ l_tlm_size = size_per_tile_part *
+ p_j2k->m_specific_param.m_encoder.m_total_tile_parts;
l_tlm_position = 6 + p_j2k->m_specific_param.m_encoder.m_tlm_start;
l_current_position = opj_stream_tell(p_stream);