X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fopenjp2%2Fj2k.c;h=220f4b1e8dbea77ec22ad8bf11b0e63f8214ee2e;hb=241e9e8efeb6750ef4202a61b3a436628e4f6d23;hp=174cf769697321655bbc39756369c8af4a3496d5;hpb=0a25dceca7761ee3f16cbb2ced87b915a948b25e;p=openjpeg.git diff --git a/src/lib/openjp2/j2k.c b/src/lib/openjp2/j2k.c index 174cf769..220f4b1e 100644 --- a/src/lib/openjp2/j2k.c +++ b/src/lib/openjp2/j2k.c @@ -49,10 +49,8 @@ /** @name Local static functions */ /*@{*/ -#define OPJ_UNUSED(x) (void)x - /** - * 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); @@ -91,22 +89,22 @@ static OPJ_BOOL opj_j2k_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_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); @@ -149,7 +147,7 @@ static OPJ_BOOL opj_j2k_create_tcd(opj_j2k_t *p_j2k, 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. @@ -371,7 +369,7 @@ static OPJ_BOOL opj_j2k_pre_write_tile(opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager); -static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, +static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, opj_image_t* p_output_image); static void opj_get_tile_dimensions(opj_image_t * l_image, @@ -402,14 +400,14 @@ static OPJ_BOOL opj_j2k_setup_header_writing(opj_j2k_t *p_j2k, 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); @@ -510,7 +508,7 @@ static OPJ_BOOL opj_j2k_write_cod(opj_j2k_t *p_j2k, 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. @@ -834,14 +832,14 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, * * @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); @@ -881,11 +879,13 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, /** * 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. */ @@ -893,7 +893,7 @@ 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); @@ -910,9 +910,15 @@ static OPJ_BOOL opj_j2k_read_sod(opj_j2k_t *p_j2k, 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 */ @@ -1171,6 +1177,32 @@ static OPJ_BOOL opj_j2k_read_cbd(opj_j2k_t *p_j2k, 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. @@ -1221,6 +1253,7 @@ static OPJ_BOOL opj_j2k_write_epc(opj_j2k_t *p_j2k, * 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 @@ -1230,6 +1263,7 @@ static OPJ_BOOL opj_j2k_write_epc(opj_j2k_t *p_j2k, * @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, @@ -1284,6 +1318,13 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, 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. * @@ -1384,10 +1425,12 @@ static const opj_dec_memory_marker_handler_t j2k_memory_marker_handler_tab [] = {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}, @@ -1617,6 +1660,7 @@ const char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order) } 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, @@ -1630,9 +1674,10 @@ static OPJ_BOOL opj_j2k_check_poc_val(const opj_poc_t *p_pocs, 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; - packet_array = (OPJ_UINT32*) opj_calloc(step_l * p_num_layers, + assert(p_nb_pocs > 0); + + packet_array = (OPJ_UINT32*) opj_calloc((size_t)step_l * p_num_layers, sizeof(OPJ_UINT32)); if (packet_array == 00) { opj_event_msg(p_manager, EVT_ERROR, @@ -1640,63 +1685,37 @@ static OPJ_BOOL opj_j2k_check_poc_val(const opj_poc_t *p_pocs, 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; @@ -1704,7 +1723,13 @@ static OPJ_BOOL opj_j2k_check_poc_val(const opj_poc_t *p_pocs, 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; } } @@ -1765,7 +1790,7 @@ static OPJ_UINT32 opj_j2k_get_num_tp(opj_cp_t *cp, OPJ_UINT32 pino, 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; @@ -1927,7 +1952,8 @@ static OPJ_BOOL opj_j2k_read_soc(opj_j2k_t *p_j2k, /* 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*/ @@ -2144,13 +2170,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_FALSE; } - /* testcase 1610.pdf.SIGSEGV.59c.681 */ - if ((0xFFFFFFFFU / l_image->x1) < l_image->y1) { - opj_event_msg(p_manager, EVT_ERROR, - "Prevent buffer overflow (x1: %d, y1: %d)\n", l_image->x1, l_image->y1); - return OPJ_FALSE; - } - /* testcase issue427-illegal-tile-offset.jp2 */ l_tx1 = opj_uint_adds(l_cp->tx0, l_cp->tdx); /* manage overflow */ l_ty1 = opj_uint_adds(l_cp->ty0, l_cp->tdy); /* manage overflow */ @@ -2634,7 +2653,7 @@ static OPJ_BOOL opj_j2k_write_cod(opj_j2k_t *p_j2k, } /** - * 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. @@ -2666,12 +2685,17 @@ static OPJ_BOOL opj_j2k_read_cod(opj_j2k_t *p_j2k, &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 */ @@ -2717,6 +2741,12 @@ static OPJ_BOOL opj_j2k_read_cod(opj_j2k_t *p_j2k, 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; @@ -3455,6 +3485,28 @@ static OPJ_UINT32 opj_j2k_get_specific_header_sizes(opj_j2k_t *p_j2k) 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; @@ -3511,11 +3563,10 @@ static OPJ_BOOL opj_j2k_read_poc(opj_j2k_t *p_j2k, 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; @@ -4099,7 +4150,12 @@ static OPJ_BOOL opj_j2k_merge_ppt(opj_tcp_t *p_tcp, opj_event_mgr_t * p_manager) /* 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; @@ -4148,13 +4204,33 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, { 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( @@ -4169,6 +4245,7 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, 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; @@ -4188,11 +4265,14 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, 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) { @@ -4204,7 +4284,7 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, 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 @@ -4217,7 +4297,7 @@ static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k, 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; @@ -4313,6 +4393,10 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, 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); @@ -4327,23 +4411,31 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, 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) { @@ -4598,17 +4690,105 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, 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); @@ -4617,7 +4797,7 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, 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; @@ -4625,10 +4805,9 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, 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 = @@ -4666,22 +4845,78 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, 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; } @@ -5031,7 +5266,7 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, 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; @@ -5075,25 +5310,12 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, 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; } @@ -5153,12 +5375,11 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, 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; } @@ -5169,7 +5390,7 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, /* 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 */ @@ -5177,16 +5398,23 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, 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; @@ -6394,6 +6622,60 @@ static OPJ_BOOL opj_j2k_read_cbd(opj_j2k_t *p_j2k, 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 */ /* ----------------------------------------------------------------------- */ @@ -6415,7 +6697,9 @@ void opj_j2k_setup_decoder(opj_j2k_t *j2k, opj_dparameters_t *parameters) 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) { @@ -6432,14 +6716,27 @@ OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads) 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; } - return atoi(num_threads); + 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 num_threads; } /* ----------------------------------------------------------------------- */ @@ -6597,7 +6894,7 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, } /* Precincts */ - parameters->csty |= 0x01; + parameters->csty |= J2K_CP_CSTY_PRT; if (parameters->numresolution == 1) { parameters->res_spec = 1; parameters->prcw_init[0] = 128; @@ -6678,7 +6975,7 @@ static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, /* 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; @@ -6687,7 +6984,7 @@ static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, "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; } } @@ -6723,61 +7020,642 @@ static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_UINT16 rsiz, 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; + /* 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->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; + 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->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_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->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; + default: + 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; + 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; } - 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; + + /* 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; } - 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; + + if (profile == OPJ_PROFILE_IMF_2K || + profile == OPJ_PROFILE_IMF_4K || + profile == OPJ_PROFILE_IMF_8K) { + /* 9-7 transform */ + parameters->irreversible = 1; } - /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ - cp = &(p_j2k->m_cp); + /* 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; + } + + /* 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; @@ -6841,25 +7719,93 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, 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; @@ -6873,6 +7819,10 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, } } + 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)) { @@ -6896,9 +7846,10 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, "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, @@ -6990,10 +7941,25 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, */ 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), (OPJ_INT32)cp->tdy); + /* Check that the number of tiles is valid */ + if (cp->tw > 65535 / cp->th) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid number of tiles : %u x %u (maximum fixed by jpeg2000 norm is 65535 tiles)\n", + cp->tw, cp->th); + return OPJ_FALSE; + } } else { cp->tdx = image->x1 - cp->tx0; cp->tdy = image->y1 - cp->ty0; @@ -7060,7 +8026,7 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, } #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) { @@ -7068,20 +8034,13 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, "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]; } @@ -7093,6 +8052,10 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, 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; @@ -7104,16 +8067,22 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, 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; @@ -7121,7 +8090,16 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, } } - 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; } @@ -7449,6 +8427,8 @@ OPJ_BOOL opj_j2k_read_header(opj_stream_private_t *p_stream, /*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; } @@ -7856,7 +8836,7 @@ static OPJ_BOOL opj_j2k_read_header_procedure(opj_j2k_t *p_j2k, 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 has been detected and generated error.\n"); return OPJ_FALSE; } @@ -8200,6 +9180,11 @@ void opj_j2k_destroy(opj_j2k_t *p_j2k) 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) { @@ -8485,7 +9470,7 @@ static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t 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)) { @@ -8530,6 +9515,7 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, 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); @@ -8705,7 +9691,6 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, 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; @@ -8720,27 +9705,42 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, "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; } @@ -8753,12 +9753,14 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, /* 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)) { @@ -8789,9 +9791,13 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, *p_tile_index = p_j2k->m_current_tile_number; *p_go_on = OPJ_TRUE; - *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd); - if (*p_data_size == UINT_MAX) { - return OPJ_FALSE; + if (p_data_size) { + /* For internal use in j2k.c, we don't need this */ + /* This is just needed for folks using the opj_read_tile_header() / opj_decode_tile_data() combo */ + *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd, OPJ_FALSE); + if (*p_data_size == UINT_MAX) { + return OPJ_FALSE; + } } *p_tile_x0 = p_j2k->m_tcd->tcd_image->tiles->x0; *p_tile_y0 = p_j2k->m_tcd->tcd_image->tiles->y0; @@ -8835,7 +9841,7 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, /* 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; @@ -8844,6 +9850,8 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, 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, @@ -8902,26 +9910,24 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, return OPJ_TRUE; } -static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, +static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, opj_image_t* p_output_image) { - OPJ_UINT32 i, j, k = 0; + OPJ_UINT32 i, j; OPJ_UINT32 l_width_src, l_height_src; OPJ_UINT32 l_width_dest, l_height_dest; OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src; - OPJ_SIZE_T l_start_offset_src, l_line_offset_src, l_end_offset_src ; + OPJ_SIZE_T l_start_offset_src; OPJ_UINT32 l_start_x_dest, l_start_y_dest; OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest; - OPJ_SIZE_T l_start_offset_dest, l_line_offset_dest; + OPJ_SIZE_T l_start_offset_dest; opj_image_comp_t * l_img_comp_src = 00; opj_image_comp_t * l_img_comp_dest = 00; opj_tcd_tilecomp_t * l_tilec = 00; opj_image_t * l_image_src = 00; - OPJ_UINT32 l_size_comp, l_remaining; OPJ_INT32 * l_dest_ptr; - opj_tcd_resolution_t* l_res = 00; l_tilec = p_tcd->tcd_image->tiles->comps; l_image_src = p_tcd->image; @@ -8929,53 +9935,52 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, l_img_comp_dest = p_output_image->comps; - for (i = 0; i < l_image_src->numcomps; i++) { - - /* 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)); - } + 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; /* Copy info from decoded comp image to output image */ l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded; - /*-----*/ - /* Compute the precision of the output buffer */ - l_size_comp = l_img_comp_src->prec >> 3; /*(/ 8)*/ - l_remaining = l_img_comp_src->prec & 7; /* (%8) */ - l_res = l_tilec->resolutions + l_img_comp_src->resno_decoded; - - if (l_remaining) { - ++l_size_comp; + if (p_tcd->whole_tile_decoding) { + opj_tcd_resolution_t* l_res = l_tilec->resolutions + + l_img_comp_src->resno_decoded; + res_x0 = l_res->x0; + res_y0 = l_res->y0; + res_x1 = l_res->x1; + res_y1 = l_res->y1; + src_data_stride = (OPJ_UINT32)( + l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x1 - + l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0); + p_src_data = l_tilec->data; + } else { + opj_tcd_resolution_t* l_res = l_tilec->resolutions + + l_img_comp_src->resno_decoded; + res_x0 = (OPJ_INT32)l_res->win_x0; + res_y0 = (OPJ_INT32)l_res->win_y0; + res_x1 = (OPJ_INT32)l_res->win_x1; + res_y1 = (OPJ_INT32)l_res->win_y1; + src_data_stride = l_res->win_x1 - l_res->win_x0; + p_src_data = l_tilec->data_win; } - if (l_size_comp == 3) { - l_size_comp = 4; + 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); + /* Current tile component size*/ /*if (i == 0) { fprintf(stdout, "SRC: l_res_x0=%d, l_res_x1=%d, l_res_y0=%d, l_res_y1=%d\n", - l_res->x0, l_res->x1, l_res->y0, l_res->y1); + res_x0, res_x1, res_y0, res_y1); }*/ - l_width_src = (OPJ_UINT32)(l_res->x1 - l_res->x0); - l_height_src = (OPJ_UINT32)(l_res->y1 - l_res->y0); /* Border of the current output component*/ l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); @@ -8996,53 +10001,53 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, * l_start_y_dest, l_width_dest, l_height_dest) which will be modified * by this input area. * */ - assert(l_res->x0 >= 0); - assert(l_res->x1 >= 0); - if (l_x0_dest < (OPJ_UINT32)l_res->x0) { - l_start_x_dest = (OPJ_UINT32)l_res->x0 - l_x0_dest; + assert(res_x0 >= 0); + assert(res_x1 >= 0); + if (l_x0_dest < (OPJ_UINT32)res_x0) { + l_start_x_dest = (OPJ_UINT32)res_x0 - l_x0_dest; l_offset_x0_src = 0; - if (l_x1_dest >= (OPJ_UINT32)l_res->x1) { + if (l_x1_dest >= (OPJ_UINT32)res_x1) { l_width_dest = l_width_src; l_offset_x1_src = 0; } else { - l_width_dest = l_x1_dest - (OPJ_UINT32)l_res->x0 ; + l_width_dest = l_x1_dest - (OPJ_UINT32)res_x0 ; l_offset_x1_src = (OPJ_INT32)(l_width_src - l_width_dest); } } else { l_start_x_dest = 0U; - l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0; + l_offset_x0_src = (OPJ_INT32)l_x0_dest - res_x0; - if (l_x1_dest >= (OPJ_UINT32)l_res->x1) { + if (l_x1_dest >= (OPJ_UINT32)res_x1) { l_width_dest = l_width_src - (OPJ_UINT32)l_offset_x0_src; l_offset_x1_src = 0; } else { l_width_dest = l_img_comp_dest->w ; - l_offset_x1_src = l_res->x1 - (OPJ_INT32)l_x1_dest; + l_offset_x1_src = res_x1 - (OPJ_INT32)l_x1_dest; } } - if (l_y0_dest < (OPJ_UINT32)l_res->y0) { - l_start_y_dest = (OPJ_UINT32)l_res->y0 - l_y0_dest; + if (l_y0_dest < (OPJ_UINT32)res_y0) { + l_start_y_dest = (OPJ_UINT32)res_y0 - l_y0_dest; l_offset_y0_src = 0; - if (l_y1_dest >= (OPJ_UINT32)l_res->y1) { + if (l_y1_dest >= (OPJ_UINT32)res_y1) { l_height_dest = l_height_src; l_offset_y1_src = 0; } else { - l_height_dest = l_y1_dest - (OPJ_UINT32)l_res->y0 ; + l_height_dest = l_y1_dest - (OPJ_UINT32)res_y0 ; l_offset_y1_src = (OPJ_INT32)(l_height_src - l_height_dest); } } else { l_start_y_dest = 0U; - l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0; + l_offset_y0_src = (OPJ_INT32)l_y0_dest - res_y0; - if (l_y1_dest >= (OPJ_UINT32)l_res->y1) { + if (l_y1_dest >= (OPJ_UINT32)res_y1) { l_height_dest = l_height_src - (OPJ_UINT32)l_offset_y0_src; l_offset_y1_src = 0; } else { l_height_dest = l_img_comp_dest->h ; - l_offset_y1_src = l_res->y1 - (OPJ_INT32)l_y1_dest; + l_offset_y1_src = res_y1 - (OPJ_INT32)l_y1_dest; } } @@ -9058,119 +10063,65 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, /* Compute the input buffer offset */ l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src - * (OPJ_SIZE_T)l_width_src; - l_line_offset_src = (OPJ_SIZE_T)l_offset_x1_src + (OPJ_SIZE_T)l_offset_x0_src; - l_end_offset_src = (OPJ_SIZE_T)l_offset_y1_src * (OPJ_SIZE_T)l_width_src - - (OPJ_SIZE_T)l_offset_x0_src; + * (OPJ_SIZE_T)src_data_stride; /* Compute the output buffer offset */ 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; - l_line_offset_dest = (OPJ_SIZE_T)l_img_comp_dest->w - (OPJ_SIZE_T)l_width_dest; - - /* Move the output buffer to the first place where we will write*/ - l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; - - /*if (i == 0) { - fprintf(stdout, "COMPO[%d]:\n",i); - fprintf(stdout, "SRC: l_start_x_src=%d, l_start_y_src=%d, l_width_src=%d, l_height_src=%d\n" - "\t tile offset:%d, %d, %d, %d\n" - "\t buffer offset: %d; %d, %d\n", - l_res->x0, l_res->y0, l_width_src, l_height_src, - l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src, - l_start_offset_src, l_line_offset_src, l_end_offset_src); - - fprintf(stdout, "DEST: l_start_x_dest=%d, l_start_y_dest=%d, l_width_dest=%d, l_height_dest=%d\n" - "\t start offset: %d, line offset= %d\n", - l_start_x_dest, l_start_y_dest, l_width_dest, l_height_dest, l_start_offset_dest, l_line_offset_dest); - }*/ - - switch (l_size_comp) { - case 1: { - OPJ_CHAR * l_src_ptr = (OPJ_CHAR*) p_data; - l_src_ptr += l_start_offset_src; /* Move to the first place where we will read*/ - - if (l_img_comp_src->sgnd) { - for (j = 0 ; j < l_height_dest ; ++j) { - for (k = 0 ; k < l_width_dest ; ++k) { - *(l_dest_ptr++) = (OPJ_INT32)(* - (l_src_ptr++)); /* Copy only the data needed for the output image */ - } - l_dest_ptr += - l_line_offset_dest; /* Move to the next place where we will write */ - l_src_ptr += l_line_offset_src ; /* Move to the next place where we will read */ - } + /* 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 { - for (j = 0 ; j < l_height_dest ; ++j) { - for (k = 0 ; k < l_width_dest ; ++k) { - *(l_dest_ptr++) = (OPJ_INT32)((*(l_src_ptr++)) & 0xff); - } + 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; - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src; - } + 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; } - l_src_ptr += - l_end_offset_src; /* Move to the end of this component-part of the input buffer */ - p_data = (OPJ_BYTE*) - l_src_ptr; /* Keep the current position for the next component-part */ + 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)); + } } - break; - case 2: { - OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data; - l_src_ptr += l_start_offset_src; - - if (l_img_comp_src->sgnd) { - for (j = 0; j < l_height_dest; ++j) { - for (k = 0; k < l_width_dest; ++k) { - OPJ_INT16 val; - memcpy(&val, l_src_ptr, sizeof(val)); - l_src_ptr ++; - *(l_dest_ptr++) = val; - } - - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src ; - } - } else { - for (j = 0; j < l_height_dest; ++j) { - for (k = 0; k < l_width_dest; ++k) { - OPJ_INT16 val; - memcpy(&val, l_src_ptr, sizeof(val)); - l_src_ptr ++; - *(l_dest_ptr++) = val & 0xffff; - } - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src ; - } - } + /* 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_src_ptr += l_end_offset_src; - p_data = (OPJ_BYTE*) l_src_ptr; - } - break; - case 4: { - OPJ_INT32 * l_src_ptr = (OPJ_INT32 *) p_data; + { + const OPJ_INT32 * l_src_ptr = p_src_data; l_src_ptr += l_start_offset_src; for (j = 0; j < l_height_dest; ++j) { memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32)); - l_dest_ptr += l_width_dest + l_line_offset_dest; - l_src_ptr += l_width_dest + l_line_offset_src ; + l_dest_ptr += l_img_comp_dest->w; + l_src_ptr += src_data_stride; } - - l_src_ptr += l_end_offset_src; - p_data = (OPJ_BYTE*) l_src_ptr; - } - break; } - ++l_img_comp_dest; - ++l_img_comp_src; - ++l_tilec; + } return OPJ_TRUE; @@ -9186,6 +10137,14 @@ static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image, 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); @@ -9220,6 +10179,65 @@ static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image, 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, @@ -9232,10 +10250,15 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, OPJ_BOOL ret; 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) { + /* In the case of a single-tiled image whose codestream we have already */ + /* ingested, go on */ + } /* Check if we are read the main header */ - if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { + else if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { opj_event_msg(p_manager, EVT_ERROR, - "Need to decode the main header before begin to decode the remaining codestream"); + "Need to decode the main header before begin to decode the remaining codestream.\n"); return OPJ_FALSE; } @@ -9289,7 +10312,7 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, } /* 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); @@ -9640,9 +10663,9 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k, 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", @@ -9654,19 +10677,22 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k, /* 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; @@ -9677,18 +10703,26 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k, 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 ? */ @@ -9698,8 +10732,9 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k, 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))) { @@ -10542,16 +11577,50 @@ static OPJ_BOOL opj_j2k_allocate_tile_element_cstr_index(opj_j2k_t *p_j2k) 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) { OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; - OPJ_UINT32 l_data_size, l_max_data_size; OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; OPJ_UINT32 nr_tiles = 0; /* Particular case for whole single tile decoding */ @@ -10561,12 +11630,11 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, p_j2k->m_output_image->x0 == 0 && p_j2k->m_output_image->y0 == 0 && p_j2k->m_output_image->x1 == p_j2k->m_cp.tdx && - p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy && - p_j2k->m_output_image->comps[0].factor == 0) { + p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy) { OPJ_UINT32 i; if (! opj_j2k_read_tile_header(p_j2k, &l_current_tile_no, - &l_data_size, + NULL, &l_tile_x0, &l_tile_y0, &l_tile_x1, &l_tile_y1, &l_nb_comps, @@ -10595,59 +11663,55 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, return OPJ_TRUE; } - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; - for (;;) { - if (! opj_j2k_read_tile_header(p_j2k, - &l_current_tile_no, - &l_data_size, - &l_tile_x0, &l_tile_y0, - &l_tile_x1, &l_tile_y1, - &l_nb_comps, - &l_go_on, - p_stream, - p_manager)) { - opj_free(l_current_data); - return OPJ_FALSE; - } - - if (! l_go_on) { - break; - } - - if (l_data_size > l_max_data_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, - l_data_size); - if (! l_new_current_data) { - opj_free(l_current_data); - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n", - l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); + if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 && + p_j2k->m_cp.tcps[0].m_data != NULL) { + l_current_tile_no = 0; + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_DATA; + } else { + if (! opj_j2k_read_tile_header(p_j2k, + &l_current_tile_no, + NULL, + &l_tile_x0, &l_tile_y0, + &l_tile_x1, &l_tile_y1, + &l_nb_comps, + &l_go_on, + p_stream, + p_manager)) { return OPJ_FALSE; } - l_current_data = l_new_current_data; - l_max_data_size = l_data_size; + + if (! l_go_on) { + break; + } } - if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size, + if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0, p_stream, p_manager)) { - opj_free(l_current_data); opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); return OPJ_FALSE; } + opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, + if (! opj_j2k_update_image_data(p_j2k->m_tcd, p_j2k->m_output_image)) { - opj_free(l_current_data); return OPJ_FALSE; } + + if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 && + !(p_j2k->m_output_image->x0 == p_j2k->m_private_image->x0 && + p_j2k->m_output_image->y0 == p_j2k->m_private_image->y0 && + p_j2k->m_output_image->x1 == p_j2k->m_private_image->x1 && + p_j2k->m_output_image->y1 == p_j2k->m_private_image->y1)) { + /* Keep current tcp data */ + } else { + opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]); + } + opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); @@ -10660,13 +11724,15 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, } } - opj_free(l_current_data); + 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) @@ -10694,24 +11760,14 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; OPJ_UINT32 l_tile_no_to_dec; - OPJ_UINT32 l_data_size, l_max_data_size; OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; OPJ_UINT32 l_nb_tiles; OPJ_UINT32 i; - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode one tile\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; - /*Allocate and initialize some elements of codestrem index if not already done*/ if (!p_j2k->cstr_index->tile_index) { if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) { - opj_free(l_current_data); return OPJ_FALSE; } } @@ -10726,7 +11782,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, if (!(opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } } else { @@ -10734,7 +11789,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } } @@ -10756,14 +11810,13 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, for (;;) { if (! opj_j2k_read_tile_header(p_j2k, &l_current_tile_no, - &l_data_size, + NULL, &l_tile_x0, &l_tile_y0, &l_tile_x1, &l_tile_y1, &l_nb_comps, &l_go_on, p_stream, p_manager)) { - opj_free(l_current_data); return OPJ_FALSE; } @@ -10771,33 +11824,19 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, break; } - if (l_data_size > l_max_data_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, - l_data_size); - if (! l_new_current_data) { - opj_free(l_current_data); - l_current_data = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n", - l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - return OPJ_FALSE; - } - l_current_data = l_new_current_data; - l_max_data_size = l_data_size; - } - - if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size, + if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0, p_stream, p_manager)) { - opj_free(l_current_data); return OPJ_FALSE; } opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, + if (! opj_j2k_update_image_data(p_j2k->m_tcd, p_j2k->m_output_image)) { - opj_free(l_current_data); return OPJ_FALSE; } + opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]); + opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); @@ -10806,7 +11845,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } break; @@ -10818,13 +11856,15 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, } - opj_free(l_current_data); + 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) @@ -10842,13 +11882,71 @@ static OPJ_BOOL opj_j2k_setup_decoding_tile(opj_j2k_t *p_j2k, 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; } @@ -10878,9 +11976,11 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, } } - p_j2k->m_output_image = opj_image_create0(); - if (!(p_j2k->m_output_image)) { - return OPJ_FALSE; + if (p_j2k->m_output_image == NULL) { + p_j2k->m_output_image = opj_image_create0(); + if (!(p_j2k->m_output_image)) { + return OPJ_FALSE; + } } opj_copy_image_header(p_image, p_j2k->m_output_image); @@ -10897,22 +11997,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, } /* 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; - 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, @@ -10930,6 +12015,12 @@ 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, @@ -10960,7 +12051,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, } 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; @@ -10982,12 +12073,24 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, 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; @@ -11009,20 +12112,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, } /* 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, @@ -11056,13 +12146,59 @@ 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) { OPJ_UINT32 i, j; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_max_tile_size = 0, l_current_tile_size; + OPJ_SIZE_T l_max_tile_size = 0, l_current_tile_size; OPJ_BYTE * l_current_data = 00; OPJ_BOOL l_reuse_data = OPJ_FALSE; opj_tcd_t* p_tcd = 00; @@ -11113,7 +12249,7 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, } } } - 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, @@ -11128,6 +12264,12 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, 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 */ @@ -11435,7 +12577,7 @@ static OPJ_BOOL opj_j2k_setup_end_compress(opj_j2k_t *p_j2k, 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; @@ -11518,7 +12660,7 @@ static OPJ_BOOL opj_j2k_setup_header_writing(opj_j2k_t *p_j2k, 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; @@ -11545,7 +12687,8 @@ static OPJ_BOOL opj_j2k_setup_header_writing(opj_j2k_t *p_j2k, } /* 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; @@ -11575,7 +12718,7 @@ static OPJ_BOOL opj_j2k_setup_header_writing(opj_j2k_t *p_j2k, 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) { @@ -11599,7 +12742,7 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, 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; @@ -11607,7 +12750,7 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, 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 @@ -11617,29 +12760,29 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, 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; } @@ -11650,7 +12793,7 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, 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); } @@ -11660,7 +12803,7 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, 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 ) @@ -11693,7 +12836,7 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, 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)) { @@ -11702,25 +12845,25 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, 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); } @@ -11739,7 +12882,7 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, 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; @@ -11747,26 +12890,26 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, 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); } @@ -11785,13 +12928,16 @@ static OPJ_BOOL opj_j2k_write_updated_tlm(opj_j2k_t *p_j2k, { 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);